Merge branch 'upstream' into topic/asoc
Takashi Iwai [Mon, 1 Dec 2008 17:02:17 +0000 (18:02 +0100)]
126 files changed:
Documentation/sound/alsa/soc/machine.txt
MAINTAINERS
arch/arm/mach-pxa/include/mach/palmasoc.h [new file with mode: 0644]
include/sound/l3.h [new file with mode: 0644]
include/sound/s3c24xx_uda134x.h [new file with mode: 0644]
include/sound/soc-dai.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/uda134x.h [new file with mode: 0644]
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/at32/Kconfig [deleted file]
sound/soc/at32/Makefile [deleted file]
sound/soc/at32/at32-pcm.h [deleted file]
sound/soc/at32/at32-ssc.c [deleted file]
sound/soc/at32/at32-ssc.h [deleted file]
sound/soc/at91/Kconfig [deleted file]
sound/soc/at91/Makefile [deleted file]
sound/soc/at91/at91-pcm.c [deleted file]
sound/soc/at91/at91-pcm.h [deleted file]
sound/soc/at91/at91-ssc.c [deleted file]
sound/soc/at91/at91-ssc.h [deleted file]
sound/soc/atmel/Kconfig [new file with mode: 0644]
sound/soc/atmel/Makefile [new file with mode: 0644]
sound/soc/atmel/atmel-pcm.c [moved from sound/soc/at32/at32-pcm.c with 50% similarity]
sound/soc/atmel/atmel-pcm.h [new file with mode: 0644]
sound/soc/atmel/atmel_ssc_dai.c [new file with mode: 0644]
sound/soc/atmel/atmel_ssc_dai.h [new file with mode: 0644]
sound/soc/atmel/playpaq_wm8510.c [moved from sound/soc/at32/playpaq_wm8510.c with 98% similarity]
sound/soc/atmel/sam9g20_wm8731.c [new file with mode: 0644]
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/au1x/sample-ac97.c
sound/soc/blackfin/Kconfig
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ac97.h
sound/soc/blackfin/bf5xx-ad1980.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-sport.h
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/l3.c [new file with mode: 0644]
sound/soc/codecs/pcm3008.c [new file with mode: 0644]
sound/soc/codecs/pcm3008.h [new file with mode: 0644]
sound/soc/codecs/ssm2602.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/twl4030.c [new file with mode: 0644]
sound/soc/codecs/twl4030.h [new file with mode: 0644]
sound/soc/codecs/uda134x.c [new file with mode: 0644]
sound/soc/codecs/uda134x.h [new file with mode: 0644]
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8580.h
sound/soc/codecs/wm8728.c [new file with mode: 0644]
sound/soc/codecs/wm8728.h [new file with mode: 0644]
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8900.h
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8990.h
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/davinci/Kconfig
sound/soc/davinci/Makefile
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-sffsdr.c [new file with mode: 0644]
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/soc-of-simple.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap2evm.c [new file with mode: 0644]
sound/soc/omap/omap3beagle.c [new file with mode: 0644]
sound/soc/omap/osk5912.c
sound/soc/omap/overo.c [new file with mode: 0644]
sound/soc/omap/sdp3430.c [new file with mode: 0644]
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/corgi.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/em-x270.c
sound/soc/pxa/palm27x.c [new file with mode: 0644]
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa-ssp.c [new file with mode: 0644]
sound/soc/pxa/pxa-ssp.h [new file with mode: 0644]
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/pxa/zylonite.c [new file with mode: 0644]
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/ln2440sbc_alc650.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/s3c2412-i2s.c
sound/soc/s3c24xx/s3c2443-ac97.c
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx_uda134x.c [new file with mode: 0644]
sound/soc/s3c24xx/smdk2443_wm9710.c
sound/soc/sh/hac.c
sound/soc/sh/sh7760-ac97.c
sound/soc/sh/ssi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c

index f370e7d..bab7711 100644 (file)
@@ -9,7 +9,7 @@ the audio subsystem with the kernel as a platform device and is represented by
 the following struct:-
 
 /* SoC machine */
-struct snd_soc_machine {
+struct snd_soc_card {
        char *name;
 
        int (*probe)(struct platform_device *pdev);
@@ -67,10 +67,10 @@ static struct snd_soc_dai_link corgi_dai = {
        .ops = &corgi_ops,
 };
 
-struct snd_soc_machine then sets up the machine with it's DAIs. e.g.
+struct snd_soc_card then sets up the machine with it's DAIs. e.g.
 
 /* corgi audio machine driver */
-static struct snd_soc_machine snd_soc_machine_corgi = {
+static struct snd_soc_card snd_soc_corgi = {
        .name = "Corgi",
        .dai_link = &corgi_dai,
        .num_links = 1,
@@ -90,7 +90,7 @@ static struct wm8731_setup_data corgi_wm8731_setup = {
 
 /* corgi audio subsystem */
 static struct snd_soc_device corgi_snd_devdata = {
-       .machine = &snd_soc_machine_corgi,
+       .machine = &snd_soc_corgi,
        .platform = &pxa2xx_soc_platform,
        .codec_dev = &soc_codec_dev_wm8731,
        .codec_data = &corgi_wm8731_setup,
index 618c1ef..6df20ea 100644 (file)
@@ -3967,7 +3967,7 @@ M:        tiwai@suse.de
 L:     alsa-devel@alsa-project.org (subscribers-only)
 S:     Maintained
 
-SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
+SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 P:     Liam Girdwood
 M:     lrg@slimlogic.co.uk
 P:     Mark Brown
diff --git a/arch/arm/mach-pxa/include/mach/palmasoc.h b/arch/arm/mach-pxa/include/mach/palmasoc.h
new file mode 100644 (file)
index 0000000..6c4b1f7
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _INCLUDE_PALMASOC_H_
+#define _INCLUDE_PALMASOC_H_
+struct palm27x_asoc_info {
+       int     jack_gpio;
+};
+
+#ifdef CONFIG_SND_PXA2XX_SOC_PALM27X
+void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data);
+#else
+static inline void palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) {}
+#endif
+
+#endif
diff --git a/include/sound/l3.h b/include/sound/l3.h
new file mode 100644 (file)
index 0000000..423a08f
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _L3_H_
+#define _L3_H_ 1
+
+struct l3_pins {
+       void (*setdat)(int);
+       void (*setclk)(int);
+       void (*setmode)(int);
+       int data_hold;
+       int data_setup;
+       int clock_high;
+       int mode_hold;
+       int mode;
+       int mode_setup;
+};
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len);
+
+#endif
diff --git a/include/sound/s3c24xx_uda134x.h b/include/sound/s3c24xx_uda134x.h
new file mode 100644 (file)
index 0000000..33df4cb
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _S3C24XX_UDA134X_H_
+#define _S3C24XX_UDA134X_H_ 1
+
+#include <sound/uda134x.h>
+
+struct s3c24xx_uda134x_platform_data {
+       int l3_clk;
+       int l3_mode;
+       int l3_data;
+       void (*power) (int);
+       int model;
+};
+
+#endif
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
new file mode 100644 (file)
index 0000000..a01a24b
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * linux/sound/soc-dai.h -- ALSA SoC Layer
+ *
+ * Copyright:  2005-2008 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Digital Audio Interface (DAI) API.
+ */
+
+#ifndef __LINUX_SND_SOC_DAI_H
+#define __LINUX_SND_SOC_DAI_H
+
+
+#include <linux/list.h>
+
+struct snd_pcm_substream;
+
+/*
+ * DAI hardware audio formats.
+ *
+ * Describes the physical PCM data formating and clocking. Add new formats
+ * to the end.
+ */
+#define SND_SOC_DAIFMT_I2S             0 /* I2S mode */
+#define SND_SOC_DAIFMT_RIGHT_J         1 /* Right Justified mode */
+#define SND_SOC_DAIFMT_LEFT_J          2 /* Left Justified mode */
+#define SND_SOC_DAIFMT_DSP_A           3 /* L data msb after FRM LRC */
+#define SND_SOC_DAIFMT_DSP_B           4 /* L data msb during FRM LRC */
+#define SND_SOC_DAIFMT_AC97            5 /* AC97 */
+
+/* left and right justified also known as MSB and LSB respectively */
+#define SND_SOC_DAIFMT_MSB             SND_SOC_DAIFMT_LEFT_J
+#define SND_SOC_DAIFMT_LSB             SND_SOC_DAIFMT_RIGHT_J
+
+/*
+ * DAI Clock gating.
+ *
+ * DAI bit clocks can be be gated (disabled) when not the DAI is not
+ * sending or receiving PCM data in a frame. This can be used to save power.
+ */
+#define SND_SOC_DAIFMT_CONT            (0 << 4) /* continuous clock */
+#define SND_SOC_DAIFMT_GATED           (1 << 4) /* clock is gated */
+
+/*
+ * DAI Left/Right Clocks.
+ *
+ * Specifies whether the DAI can support different samples for similtanious
+ * playback and capture. This usually requires a seperate physical frame
+ * clock for playback and capture.
+ */
+#define SND_SOC_DAIFMT_SYNC            (0 << 5) /* Tx FRM = Rx FRM */
+#define SND_SOC_DAIFMT_ASYNC           (1 << 5) /* Tx FRM ~ Rx FRM */
+
+/*
+ * TDM
+ *
+ * Time Division Multiplexing. Allows PCM data to be multplexed with other
+ * data on the DAI.
+ */
+#define SND_SOC_DAIFMT_TDM             (1 << 6)
+
+/*
+ * DAI hardware signal inversions.
+ *
+ * Specifies whether the DAI can also support inverted clocks for the specified
+ * format.
+ */
+#define SND_SOC_DAIFMT_NB_NF           (0 << 8) /* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_IF           (1 << 8) /* normal bclk + inv frm */
+#define SND_SOC_DAIFMT_IB_NF           (2 << 8) /* invert bclk + nor frm */
+#define SND_SOC_DAIFMT_IB_IF           (3 << 8) /* invert bclk + frm */
+
+/*
+ * DAI hardware clock masters.
+ *
+ * This is wrt the codec, the inverse is true for the interface
+ * i.e. if the codec is clk and frm master then the interface is
+ * clk and frame slave.
+ */
+#define SND_SOC_DAIFMT_CBM_CFM         (0 << 12) /* codec clk & frm master */
+#define SND_SOC_DAIFMT_CBS_CFM         (1 << 12) /* codec clk slave & frm master */
+#define SND_SOC_DAIFMT_CBM_CFS         (2 << 12) /* codec clk master & frame slave */
+#define SND_SOC_DAIFMT_CBS_CFS         (3 << 12) /* codec clk & frm slave */
+
+#define SND_SOC_DAIFMT_FORMAT_MASK     0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK      0x00f0
+#define SND_SOC_DAIFMT_INV_MASK                0x0f00
+#define SND_SOC_DAIFMT_MASTER_MASK     0xf000
+
+/*
+ * Master Clock Directions
+ */
+#define SND_SOC_CLOCK_IN               0
+#define SND_SOC_CLOCK_OUT              1
+
+struct snd_soc_dai_ops;
+struct snd_soc_dai;
+struct snd_ac97_bus_ops;
+
+/* Digital Audio Interface clocking API.*/
+int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+       unsigned int freq, int dir);
+
+int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
+       int div_id, int div);
+
+int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
+       int pll_id, unsigned int freq_in, unsigned int freq_out);
+
+/* Digital Audio interface formatting */
+int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
+
+int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
+       unsigned int mask, int slots);
+
+int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
+
+/* Digital Audio Interface mute */
+int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
+
+/*
+ * Digital Audio Interface.
+ *
+ * Describes the Digital Audio Interface in terms of it's ALSA, DAI and AC97
+ * operations an capabilities. Codec and platfom drivers will register a this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface a
+ */
+struct snd_soc_dai_ops {
+       /*
+        * DAI clocking configuration, all optional.
+        * Called by soc_card drivers, normally in their hw_params.
+        */
+       int (*set_sysclk)(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir);
+       int (*set_pll)(struct snd_soc_dai *dai,
+               int pll_id, unsigned int freq_in, unsigned int freq_out);
+       int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
+
+       /*
+        * DAI format configuration
+        * Called by soc_card drivers, normally in their hw_params.
+        */
+       int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
+       int (*set_tdm_slot)(struct snd_soc_dai *dai,
+               unsigned int mask, int slots);
+       int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
+
+       /*
+        * DAI digital mute - optional.
+        * Called by soc-core to minimise any pops.
+        */
+       int (*digital_mute)(struct snd_soc_dai *dai, int mute);
+
+       /*
+        * ALSA PCM audio operations - all optional.
+        * Called by soc-core during audio PCM operations.
+        */
+       int (*startup)(struct snd_pcm_substream *,
+               struct snd_soc_dai *);
+       void (*shutdown)(struct snd_pcm_substream *,
+               struct snd_soc_dai *);
+       int (*hw_params)(struct snd_pcm_substream *,
+               struct snd_pcm_hw_params *, struct snd_soc_dai *);
+       int (*hw_free)(struct snd_pcm_substream *,
+               struct snd_soc_dai *);
+       int (*prepare)(struct snd_pcm_substream *,
+               struct snd_soc_dai *);
+       int (*trigger)(struct snd_pcm_substream *, int,
+               struct snd_soc_dai *);
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+       /* DAI description */
+       char *name;
+       unsigned int id;
+       int ac97_control;
+
+       /* DAI callbacks */
+       int (*probe)(struct platform_device *pdev,
+                    struct snd_soc_dai *dai);
+       void (*remove)(struct platform_device *pdev,
+                      struct snd_soc_dai *dai);
+       int (*suspend)(struct platform_device *pdev,
+               struct snd_soc_dai *dai);
+       int (*resume)(struct platform_device *pdev,
+               struct snd_soc_dai *dai);
+
+       /* ops */
+       struct snd_soc_dai_ops ops;
+
+       /* DAI capabilities */
+       struct snd_soc_pcm_stream capture;
+       struct snd_soc_pcm_stream playback;
+
+       /* DAI runtime info */
+       struct snd_pcm_runtime *runtime;
+       struct snd_soc_codec *codec;
+       unsigned int active;
+       unsigned char pop_wait:1;
+       void *dma_data;
+
+       /* DAI private data */
+       void *private_data;
+
+       /* parent codec/platform */
+       union {
+               struct snd_soc_codec *codec;
+               struct snd_soc_platform *platform;
+       };
+
+       struct list_head list;
+};
+
+#endif
index ca699a3..7ee2f70 100644 (file)
@@ -221,8 +221,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
        int num);
 
 /* dapm path setup */
-int  __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
-       const char *sink_name, const char *control_name, const char *src_name);
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
 void snd_soc_dapm_free(struct snd_soc_device *socdev);
 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
index 5e01898..444f9c2 100644 (file)
@@ -21,8 +21,6 @@
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 
-#define SND_SOC_VERSION "0.13.2"
-
 /*
  * Convenience kcontrol builders
  */
@@ -145,84 +143,6 @@ enum snd_soc_bias_level {
        SND_SOC_BIAS_OFF,
 };
 
-/*
- * Digital Audio Interface (DAI) types
- */
-#define SND_SOC_DAI_AC97       0x1
-#define SND_SOC_DAI_I2S                0x2
-#define SND_SOC_DAI_PCM                0x4
-#define SND_SOC_DAI_AC97_BUS   0x8     /* for custom i.e. non ac97_codec.c */
-
-/*
- * DAI hardware audio formats
- */
-#define SND_SOC_DAIFMT_I2S             0       /* I2S mode */
-#define SND_SOC_DAIFMT_RIGHT_J 1       /* Right justified mode */
-#define SND_SOC_DAIFMT_LEFT_J  2       /* Left Justified mode */
-#define SND_SOC_DAIFMT_DSP_A   3       /* L data msb after FRM or LRC */
-#define SND_SOC_DAIFMT_DSP_B   4       /* L data msb during FRM or LRC */
-#define SND_SOC_DAIFMT_AC97            5       /* AC97 */
-
-#define SND_SOC_DAIFMT_MSB     SND_SOC_DAIFMT_LEFT_J
-#define SND_SOC_DAIFMT_LSB     SND_SOC_DAIFMT_RIGHT_J
-
-/*
- * DAI Gating
- */
-#define SND_SOC_DAIFMT_CONT                    (0 << 4)        /* continuous clock */
-#define SND_SOC_DAIFMT_GATED           (1 << 4)        /* clock is gated when not Tx/Rx */
-
-/*
- * DAI Sync
- * Synchronous LR (Left Right) clocks and Frame signals.
- */
-#define SND_SOC_DAIFMT_SYNC            (0 << 5)        /* Tx FRM = Rx FRM */
-#define SND_SOC_DAIFMT_ASYNC           (1 << 5)        /* Tx FRM ~ Rx FRM */
-
-/*
- * TDM
- */
-#define SND_SOC_DAIFMT_TDM             (1 << 6)
-
-/*
- * DAI hardware signal inversions
- */
-#define SND_SOC_DAIFMT_NB_NF           (0 << 8)        /* normal bclk + frm */
-#define SND_SOC_DAIFMT_NB_IF           (1 << 8)        /* normal bclk + inv frm */
-#define SND_SOC_DAIFMT_IB_NF           (2 << 8)        /* invert bclk + nor frm */
-#define SND_SOC_DAIFMT_IB_IF           (3 << 8)        /* invert bclk + frm */
-
-/*
- * DAI hardware clock masters
- * This is wrt the codec, the inverse is true for the interface
- * i.e. if the codec is clk and frm master then the interface is
- * clk and frame slave.
- */
-#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */
-#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */
-#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */
-#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */
-
-#define SND_SOC_DAIFMT_FORMAT_MASK             0x000f
-#define SND_SOC_DAIFMT_CLOCK_MASK              0x00f0
-#define SND_SOC_DAIFMT_INV_MASK                        0x0f00
-#define SND_SOC_DAIFMT_MASTER_MASK             0xf000
-
-
-/*
- * Master Clock Directions
- */
-#define SND_SOC_CLOCK_IN       0
-#define SND_SOC_CLOCK_OUT      1
-
-/*
- * AC97 codec ID's bitmask
- */
-#define SND_SOC_DAI_AC97_ID0   (1 << 0)
-#define SND_SOC_DAI_AC97_ID1   (1 << 1)
-#define SND_SOC_DAI_AC97_ID2   (1 << 2)
-#define SND_SOC_DAI_AC97_ID3   (1 << 3)
-
 struct snd_soc_device;
 struct snd_soc_pcm_stream;
 struct snd_soc_ops;
@@ -230,7 +150,6 @@ struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
 struct snd_soc_codec;
-struct snd_soc_machine_config;
 struct soc_enum;
 struct snd_soc_ac97_ops;
 struct snd_soc_clock_info;
@@ -263,27 +182,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
        struct snd_ac97_bus_ops *ops, int num);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
-/* Digital Audio Interface clocking API.*/
-int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-       unsigned int freq, int dir);
-
-int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
-       int div_id, int div);
-
-int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
-       int pll_id, unsigned int freq_in, unsigned int freq_out);
-
-/* Digital Audio interface formatting */
-int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
-
-int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
-       unsigned int mask, int slots);
-
-int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
-
-/* Digital Audio Interface mute */
-int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
-
 /*
  *Controls
  */
@@ -341,61 +239,6 @@ struct snd_soc_ops {
        int (*trigger)(struct snd_pcm_substream *, int);
 };
 
-/* ASoC DAI ops */
-struct snd_soc_dai_ops {
-       /* DAI clocking configuration */
-       int (*set_sysclk)(struct snd_soc_dai *dai,
-               int clk_id, unsigned int freq, int dir);
-       int (*set_pll)(struct snd_soc_dai *dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out);
-       int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
-
-       /* DAI format configuration */
-       int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
-       int (*set_tdm_slot)(struct snd_soc_dai *dai,
-               unsigned int mask, int slots);
-       int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
-
-       /* digital mute */
-       int (*digital_mute)(struct snd_soc_dai *dai, int mute);
-};
-
-/* SoC  DAI (Digital Audio Interface) */
-struct snd_soc_dai {
-       /* DAI description */
-       char *name;
-       unsigned int id;
-       unsigned char type;
-
-       /* DAI callbacks */
-       int (*probe)(struct platform_device *pdev,
-                    struct snd_soc_dai *dai);
-       void (*remove)(struct platform_device *pdev,
-                      struct snd_soc_dai *dai);
-       int (*suspend)(struct platform_device *pdev,
-               struct snd_soc_dai *dai);
-       int (*resume)(struct platform_device *pdev,
-               struct snd_soc_dai *dai);
-
-       /* ops */
-       struct snd_soc_ops ops;
-       struct snd_soc_dai_ops dai_ops;
-
-       /* DAI capabilities */
-       struct snd_soc_pcm_stream capture;
-       struct snd_soc_pcm_stream playback;
-
-       /* DAI runtime info */
-       struct snd_pcm_runtime *runtime;
-       struct snd_soc_codec *codec;
-       unsigned int active;
-       unsigned char pop_wait:1;
-       void *dma_data;
-
-       /* DAI private data */
-       void *private_data;
-};
-
 /* SoC Audio Codec */
 struct snd_soc_codec {
        char *name;
@@ -426,6 +269,7 @@ struct snd_soc_codec {
        short reg_cache_step;
 
        /* dapm */
+       u32 pop_time;
        struct list_head dapm_widgets;
        struct list_head dapm_paths;
        enum snd_soc_bias_level bias_level;
@@ -484,8 +328,8 @@ struct snd_soc_dai_link  {
        struct snd_pcm *pcm;
 };
 
-/* SoC machine */
-struct snd_soc_machine {
+/* SoC card */
+struct snd_soc_card {
        char *name;
 
        int (*probe)(struct platform_device *pdev);
@@ -499,7 +343,7 @@ struct snd_soc_machine {
        int (*resume_post)(struct platform_device *pdev);
 
        /* callbacks */
-       int (*set_bias_level)(struct snd_soc_machine *,
+       int (*set_bias_level)(struct snd_soc_card *,
                              enum snd_soc_bias_level level);
 
        /* CPU <--> Codec DAI links  */
@@ -510,13 +354,16 @@ struct snd_soc_machine {
 /* SoC Device - the audio subsystem */
 struct snd_soc_device {
        struct device *dev;
-       struct snd_soc_machine *machine;
+       struct snd_soc_card *card;
        struct snd_soc_platform *platform;
        struct snd_soc_codec *codec;
        struct snd_soc_codec_device *codec_dev;
        struct delayed_work delayed_work;
        struct work_struct deferred_resume_work;
        void *codec_data;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry   *debugfs_root;
+#endif
 };
 
 /* runtime channel data */
@@ -542,4 +389,6 @@ struct soc_enum {
        void *dapm;
 };
 
+#include <sound/soc-dai.h>
+
 #endif
diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h
new file mode 100644 (file)
index 0000000..475ef8b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * uda134x.h  --  UDA134x ALSA SoC Codec driver
+ *
+ * Copyright 2007 Dension Audio Systems Ltd.
+ * Author: Zoltan Devai
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _UDA134X_H
+#define _UDA134X_H
+
+#include <sound/l3.h>
+
+struct uda134x_platform_data {
+       struct l3_pins l3;
+       void (*power) (int);
+       int model;
+#define UDA134X_UDA1340 1
+#define UDA134X_UDA1341 2
+#define UDA134X_UDA1344 3
+};
+
+#endif /* _UDA134X_H */
index 4dfda66..615ebf0 100644 (file)
@@ -23,8 +23,7 @@ config SND_SOC_AC97_BUS
        bool
 
 # All the supported Soc's
-source "sound/soc/at32/Kconfig"
-source "sound/soc/at91/Kconfig"
+source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
index d849349..4d475c3 100644 (file)
@@ -1,5 +1,5 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
-obj-$(CONFIG_SND_SOC)  += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
+obj-$(CONFIG_SND_SOC)  += codecs/ atmel/ pxa/ s3c24xx/ sh/ fsl/ davinci/
 obj-$(CONFIG_SND_SOC)  += omap/ au1x/ blackfin/
diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig
deleted file mode 100644 (file)
index b0765e8..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-config SND_AT32_SOC
-        tristate "SoC Audio for the Atmel AT32 System-on-a-Chip"
-        depends on AVR32 && SND_SOC
-        help
-          Say Y or M if you want to add support for codecs attached to 
-          the AT32 SSC interface.  You will also need to
-          to select the audio interfaces to support below.
-
-
-config SND_AT32_SOC_SSC
-        tristate
-
-
-
-config SND_AT32_SOC_PLAYPAQ
-        tristate "SoC Audio support for PlayPaq with WM8510"
-        depends on SND_AT32_SOC && BOARD_PLAYPAQ
-        select SND_AT32_SOC_SSC
-        select SND_SOC_WM8510
-        help
-          Say Y or M here if you want to add support for SoC audio
-          on the LRS PlayPaq.
-
-
-
-config SND_AT32_SOC_PLAYPAQ_SLAVE
-        bool "Run CODEC on PlayPaq in slave mode"
-        depends on SND_AT32_SOC_PLAYPAQ
-        default n
-        help
-          Say Y if you want to run with the AT32 SSC generating the BCLK
-          and FRAME signals on the PlayPaq.  Unless you want to play
-          with the AT32 as the SSC master, you probably want to say N here,
-          as this will give you better sound quality.
diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile
deleted file mode 100644 (file)
index c03e55e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# AT32 Platform Support
-snd-soc-at32-objs := at32-pcm.o
-snd-soc-at32-ssc-objs := at32-ssc.o
-
-obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o
-obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o
-
-# AT32 Machine Support
-snd-soc-playpaq-objs := playpaq_wm8510.o
-
-obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h
deleted file mode 100644 (file)
index 2a52430..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* sound/soc/at32/at32-pcm.h
- * ASoC PCM interface for Atmel AT32 SoC
- *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __SOUND_SOC_AT32_AT32_PCM_H
-#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__
-
-#include <linux/atmel-ssc.h>
-
-
-/*
- * Registers and status bits that are required by the PCM driver
- * TODO: Is ptcr really used?
- */
-struct at32_pdc_regs {
-       u32 xpr;                /* PDC RX/TX pointer */
-       u32 xcr;                /* PDC RX/TX counter */
-       u32 xnpr;               /* PDC next RX/TX pointer */
-       u32 xncr;               /* PDC next RX/TX counter */
-       u32 ptcr;               /* PDC transfer control */
-};
-
-
-
-/*
- * SSC mask info
- */
-struct at32_ssc_mask {
-       u32 ssc_enable;         /* SSC RX/TX enable */
-       u32 ssc_disable;        /* SSC RX/TX disable */
-       u32 ssc_endx;           /* SSC ENDTX or ENDRX */
-       u32 ssc_endbuf;         /* SSC TXBUFF or RXBUFF */
-       u32 pdc_enable;         /* PDC RX/TX enable */
-       u32 pdc_disable;        /* PDC RX/TX disable */
-};
-
-
-
-/*
- * This structure, shared between the PCM driver and the interface,
- * contains all information required by the PCM driver to perform the
- * PDC DMA operation.  All fields except dma_intr_handler() are initialized
- * by the interface.  The dms_intr_handler() pointer is set by the PCM
- * driver and called by the interface SSC interrupt handler if it is
- * non-NULL.
- */
-struct at32_pcm_dma_params {
-       char *name;             /* stream identifier */
-       int pdc_xfer_size;      /* PDC counter increment in bytes */
-       struct ssc_device *ssc; /* SSC device for stream */
-       struct at32_pdc_regs *pdc;      /* PDC register info */
-       struct at32_ssc_mask *mask;     /* SSC mask info */
-       struct snd_pcm_substream *substream;
-       void (*dma_intr_handler) (u32, struct snd_pcm_substream *);
-};
-
-
-
-/*
- * The AT32 ASoC platform driver
- */
-extern struct snd_soc_platform at32_soc_platform;
-
-
-
-/*
- * SSC register access (since ssc_writel() / ssc_readl() require literal name)
- */
-#define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
-#define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
-
-#endif /* __SOUND_SOC_AT32_AT32_PCM_H */
diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c
deleted file mode 100644 (file)
index 4ef6492..0000000
+++ /dev/null
@@ -1,849 +0,0 @@
-/* sound/soc/at32/at32-ssc.c
- * ASoC platform driver for AT32 using SSC as DAI
- *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.org>
- *
- * 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.
- *
- * Note that this is basically a port of the sound/soc/at91-ssc.c to
- * the AVR32 kernel.  Thanks to Frank Mandarino for that code.
- */
-
-/* #define DEBUG */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/atmel_pdc.h>
-#include <linux/atmel-ssc.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include "at32-pcm.h"
-#include "at32-ssc.h"
-
-
-
-/*-------------------------------------------------------------------------*\
- * Constants
-\*-------------------------------------------------------------------------*/
-#define NUM_SSC_DEVICES                3
-
-/*
- * SSC direction masks
- */
-#define SSC_DIR_MASK_UNUSED    0
-#define SSC_DIR_MASK_PLAYBACK  1
-#define SSC_DIR_MASK_CAPTURE   2
-
-/*
- * SSC register values that Atmel left out of <linux/atmel-ssc.h>.  These
- * are expected to be used with SSC_BF
- */
-/* START bit field values */
-#define SSC_START_CONTINUOUS   0
-#define SSC_START_TX_RX                1
-#define SSC_START_LOW_RF       2
-#define SSC_START_HIGH_RF      3
-#define SSC_START_FALLING_RF   4
-#define SSC_START_RISING_RF    5
-#define SSC_START_LEVEL_RF     6
-#define SSC_START_EDGE_RF      7
-#define SSS_START_COMPARE_0    8
-
-/* CKI bit field values */
-#define SSC_CKI_FALLING                0
-#define SSC_CKI_RISING         1
-
-/* CKO bit field values */
-#define SSC_CKO_NONE           0
-#define SSC_CKO_CONTINUOUS     1
-#define SSC_CKO_TRANSFER       2
-
-/* CKS bit field values */
-#define SSC_CKS_DIV            0
-#define SSC_CKS_CLOCK          1
-#define SSC_CKS_PIN            2
-
-/* FSEDGE bit field values */
-#define SSC_FSEDGE_POSITIVE    0
-#define SSC_FSEDGE_NEGATIVE    1
-
-/* FSOS bit field values */
-#define SSC_FSOS_NONE          0
-#define SSC_FSOS_NEGATIVE      1
-#define SSC_FSOS_POSITIVE      2
-#define SSC_FSOS_LOW           3
-#define SSC_FSOS_HIGH          4
-#define SSC_FSOS_TOGGLE                5
-
-#define START_DELAY            1
-
-
-
-/*-------------------------------------------------------------------------*\
- * Module data
-\*-------------------------------------------------------------------------*/
-/*
- * SSC PDC registered required by the PCM DMA engine
- */
-static struct at32_pdc_regs pdc_tx_reg = {
-       .xpr = SSC_PDC_TPR,
-       .xcr = SSC_PDC_TCR,
-       .xnpr = SSC_PDC_TNPR,
-       .xncr = SSC_PDC_TNCR,
-};
-
-
-
-static struct at32_pdc_regs pdc_rx_reg = {
-       .xpr = SSC_PDC_RPR,
-       .xcr = SSC_PDC_RCR,
-       .xnpr = SSC_PDC_RNPR,
-       .xncr = SSC_PDC_RNCR,
-};
-
-
-
-/*
- * SSC and PDC status bits for transmit and receive
- */
-static struct at32_ssc_mask ssc_tx_mask = {
-       .ssc_enable = SSC_BIT(CR_TXEN),
-       .ssc_disable = SSC_BIT(CR_TXDIS),
-       .ssc_endx = SSC_BIT(SR_ENDTX),
-       .ssc_endbuf = SSC_BIT(SR_TXBUFE),
-       .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN),
-       .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS),
-};
-
-
-
-static struct at32_ssc_mask ssc_rx_mask = {
-       .ssc_enable = SSC_BIT(CR_RXEN),
-       .ssc_disable = SSC_BIT(CR_RXDIS),
-       .ssc_endx = SSC_BIT(SR_ENDRX),
-       .ssc_endbuf = SSC_BIT(SR_RXBUFF),
-       .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN),
-       .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS),
-};
-
-
-
-/*
- * DMA parameters for each SSC
- */
-static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
-       {
-        {
-         .name = "SSC0 PCM out",
-         .pdc = &pdc_tx_reg,
-         .mask = &ssc_tx_mask,
-         },
-        {
-         .name = "SSC0 PCM in",
-         .pdc = &pdc_rx_reg,
-         .mask = &ssc_rx_mask,
-         },
-        },
-       {
-        {
-         .name = "SSC1 PCM out",
-         .pdc = &pdc_tx_reg,
-         .mask = &ssc_tx_mask,
-         },
-        {
-         .name = "SSC1 PCM in",
-         .pdc = &pdc_rx_reg,
-         .mask = &ssc_rx_mask,
-         },
-        },
-       {
-        {
-         .name = "SSC2 PCM out",
-         .pdc = &pdc_tx_reg,
-         .mask = &ssc_tx_mask,
-         },
-        {
-         .name = "SSC2 PCM in",
-         .pdc = &pdc_rx_reg,
-         .mask = &ssc_rx_mask,
-         },
-        },
-};
-
-
-
-static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = {
-       {
-        .name = "ssc0",
-        .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
-        .dir_mask = SSC_DIR_MASK_UNUSED,
-        .initialized = 0,
-        },
-       {
-        .name = "ssc1",
-        .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
-        .dir_mask = SSC_DIR_MASK_UNUSED,
-        .initialized = 0,
-        },
-       {
-        .name = "ssc2",
-        .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
-        .dir_mask = SSC_DIR_MASK_UNUSED,
-        .initialized = 0,
-        },
-};
-
-
-
-
-/*-------------------------------------------------------------------------*\
- * ISR
-\*-------------------------------------------------------------------------*/
-/*
- * SSC interrupt handler.  Passes PDC interrupts to the DMA interrupt
- * handler in the PCM driver.
- */
-static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id)
-{
-       struct at32_ssc_info *ssc_p = dev_id;
-       struct at32_pcm_dma_params *dma_params;
-       u32 ssc_sr;
-       u32 ssc_substream_mask;
-       int i;
-
-       ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) &
-                 ssc_readl(ssc_p->ssc->regs, IMR));
-
-       /*
-        * Loop through substreams attached to this SSC.  If a DMA-related
-        * interrupt occured on that substream, call the DMA interrupt
-        * handler function, if one has been registered in the dma_param
-        * structure by the PCM driver.
-        */
-       for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
-               dma_params = ssc_p->dma_params[i];
-
-               if ((dma_params != NULL) &&
-                   (dma_params->dma_intr_handler != NULL)) {
-                       ssc_substream_mask = (dma_params->mask->ssc_endx |
-                                             dma_params->mask->ssc_endbuf);
-                       if (ssc_sr & ssc_substream_mask) {
-                               dma_params->dma_intr_handler(ssc_sr,
-                                                            dma_params->
-                                                            substream);
-                       }
-               }
-       }
-
-
-       return IRQ_HANDLED;
-}
-
-/*-------------------------------------------------------------------------*\
- * DAI functions
-\*-------------------------------------------------------------------------*/
-/*
- * Startup.  Only that one substream allowed in each direction.
- */
-static int at32_ssc_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-       int dir_mask;
-
-       dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                   SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE);
-
-       spin_lock_irq(&ssc_p->lock);
-       if (ssc_p->dir_mask & dir_mask) {
-               spin_unlock_irq(&ssc_p->lock);
-               return -EBUSY;
-       }
-       ssc_p->dir_mask |= dir_mask;
-       spin_unlock_irq(&ssc_p->lock);
-
-       return 0;
-}
-
-
-
-/*
- * Shutdown.  Clear DMA parameters and shutdown the SSC if there
- * are no other substreams open.
- */
-static void at32_ssc_shutdown(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-       struct at32_pcm_dma_params *dma_params;
-       int dir_mask;
-
-       dma_params = ssc_p->dma_params[substream->stream];
-
-       if (dma_params != NULL) {
-               ssc_writel(dma_params->ssc->regs, CR,
-                          dma_params->mask->ssc_disable);
-               pr_debug("%s disabled SSC_SR=0x%08x\n",
-                        (substream->stream ? "receiver" : "transmit"),
-                        ssc_readl(ssc_p->ssc->regs, SR));
-
-               dma_params->ssc = NULL;
-               dma_params->substream = NULL;
-               ssc_p->dma_params[substream->stream] = NULL;
-       }
-
-
-       dir_mask = 1 << substream->stream;
-       spin_lock_irq(&ssc_p->lock);
-       ssc_p->dir_mask &= ~dir_mask;
-       if (!ssc_p->dir_mask) {
-               /* Shutdown the SSC clock */
-               pr_debug("at32-ssc: Stopping user %d clock\n",
-                        ssc_p->ssc->user);
-               clk_disable(ssc_p->ssc->clk);
-
-               if (ssc_p->initialized) {
-                       free_irq(ssc_p->ssc->irq, ssc_p);
-                       ssc_p->initialized = 0;
-               }
-
-               /* Reset the SSC */
-               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
-
-               /* clear the SSC dividers */
-               ssc_p->cmr_div = 0;
-               ssc_p->tcmr_period = 0;
-               ssc_p->rcmr_period = 0;
-       }
-       spin_unlock_irq(&ssc_p->lock);
-}
-
-
-
-/*
- * Set the SSC system clock rate
- */
-static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-                                  int clk_id, unsigned int freq, int dir)
-{
-       /* TODO: What the heck do I do here? */
-       return 0;
-}
-
-
-
-/*
- * Record DAI format for use by hw_params()
- */
-static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-                               unsigned int fmt)
-{
-       struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-       ssc_p->daifmt = fmt;
-       return 0;
-}
-
-
-
-/*
- * Record SSC clock dividers for use in hw_params()
- */
-static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-                                  int div_id, int div)
-{
-       struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-       switch (div_id) {
-       case AT32_SSC_CMR_DIV:
-               /*
-                * The same master clock divider is used for both
-                * transmit and receive, so if a value has already
-                * been set, it must match this value
-                */
-               if (ssc_p->cmr_div == 0)
-                       ssc_p->cmr_div = div;
-               else if (div != ssc_p->cmr_div)
-                       return -EBUSY;
-               break;
-
-       case AT32_SSC_TCMR_PERIOD:
-               ssc_p->tcmr_period = div;
-               break;
-
-       case AT32_SSC_RCMR_PERIOD:
-               ssc_p->rcmr_period = div;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-
-
-/*
- * Configure the SSC
- */
-static int at32_ssc_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int id = rtd->dai->cpu_dai->id;
-       struct at32_ssc_info *ssc_p = &ssc_info[id];
-       struct at32_pcm_dma_params *dma_params;
-       int channels, bits;
-       u32 tfmr, rfmr, tcmr, rcmr;
-       int start_event;
-       int ret;
-
-
-       /*
-        * Currently, there is only one set of dma_params for each direction.
-        * If more are added, this code will have to be changed to select
-        * the proper set
-        */
-       dma_params = &ssc_dma_params[id][substream->stream];
-       dma_params->ssc = ssc_p->ssc;
-       dma_params->substream = substream;
-
-       ssc_p->dma_params[substream->stream] = dma_params;
-
-
-       /*
-        * The cpu_dai->dma_data field is only used to communicate the
-        * appropriate DMA parameters to the PCM driver's hw_params()
-        * function.  It should not be used for other purposes as it
-        * is common to all substreams.
-        */
-       rtd->dai->cpu_dai->dma_data = dma_params;
-
-       channels = params_channels(params);
-
-
-       /*
-        * Determine sample size in bits and the PDC increment
-        */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               bits = 8;
-               dma_params->pdc_xfer_size = 1;
-               break;
-
-       case SNDRV_PCM_FORMAT_S16:
-               bits = 16;
-               dma_params->pdc_xfer_size = 2;
-               break;
-
-       case SNDRV_PCM_FORMAT_S24:
-               bits = 24;
-               dma_params->pdc_xfer_size = 4;
-               break;
-
-       case SNDRV_PCM_FORMAT_S32:
-               bits = 32;
-               dma_params->pdc_xfer_size = 4;
-               break;
-
-       default:
-               pr_warning("at32-ssc: Unsupported PCM format %d",
-                          params_format(params));
-               return -EINVAL;
-       }
-       pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n",
-                bits, dma_params->pdc_xfer_size, channels);
-
-
-       /*
-        * The SSC only supports up to 16-bit samples in I2S format, due
-        * to the size of the Frame Mode Register FSLEN field.
-        */
-       if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
-               if (bits > 16) {
-                       pr_warning("at32-ssc: "
-                                  "sample size %d is too large for I2S\n",
-                                  bits);
-                       return -EINVAL;
-               }
-
-
-       /*
-        * Compute the SSC register settings
-        */
-       switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK |
-                                SND_SOC_DAIFMT_MASTER_MASK)) {
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
-               /*
-                * I2S format, SSC provides BCLK and LRS clocks.
-                *
-                * The SSC transmit and receive clocks are generated from the
-                * MCK divider, and the BCLK signal is output on the SSC TK line
-                */
-               pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n");
-               rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
-                       SSC_BF(RCMR_STTDLY, START_DELAY) |
-                       SSC_BF(RCMR_START, SSC_START_FALLING_RF) |
-                       SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
-                       SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
-                       SSC_BF(RCMR_CKS, SSC_CKS_DIV));
-
-               rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-                       SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) |
-                       SSC_BF(RFMR_FSLEN, bits - 1) |
-                       SSC_BF(RFMR_DATNB, channels - 1) |
-                       SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
-
-               tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) |
-                       SSC_BF(TCMR_STTDLY, START_DELAY) |
-                       SSC_BF(TCMR_START, SSC_START_FALLING_RF) |
-                       SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
-                       SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) |
-                       SSC_BF(TCMR_CKS, SSC_CKS_DIV));
-
-               tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-                       SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) |
-                       SSC_BF(TFMR_FSLEN, bits - 1) |
-                       SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) |
-                       SSC_BF(TFMR_DATLEN, bits - 1));
-               break;
-
-
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-               /*
-                * I2S format, CODEC supplies BCLK and LRC clock.
-                *
-                * The SSC transmit clock is obtained from the BCLK signal
-                * on the TK line, and the SSC receive clock is generated from
-                * the transmit clock.
-                *
-                * For single channel data, one sample is transferred on the
-                * falling edge of the LRC clock.  For two channel data, one
-                * sample is transferred on both edges of the LRC clock.
-                */
-               pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n");
-               start_event = ((channels == 1) ?
-                              SSC_START_FALLING_RF : SSC_START_EDGE_RF);
-
-               rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) |
-                       SSC_BF(RCMR_START, start_event) |
-                       SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
-                       SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
-                       SSC_BF(RCMR_CKS, SSC_CKS_CLOCK));
-
-               rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-                       SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) |
-                       SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
-
-               tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) |
-                       SSC_BF(TCMR_START, start_event) |
-                       SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
-                       SSC_BF(TCMR_CKO, SSC_CKO_NONE) |
-                       SSC_BF(TCMR_CKS, SSC_CKS_PIN));
-
-               tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-                       SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) |
-                       SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1));
-               break;
-
-
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
-               /*
-                * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
-                *
-                * The SSC transmit and receive clocks are generated from the
-                * MCK divider, and the BCLK signal is output on the SSC TK line
-                */
-               pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n");
-               rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
-                       SSC_BF(RCMR_STTDLY, 1) |
-                       SSC_BF(RCMR_START, SSC_START_RISING_RF) |
-                       SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
-                       SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
-                       SSC_BF(RCMR_CKS, SSC_CKS_DIV));
-
-               rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-                       SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) |
-                       SSC_BF(RFMR_DATNB, channels - 1) |
-                       SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
-
-               tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) |
-                       SSC_BF(TCMR_STTDLY, 1) |
-                       SSC_BF(TCMR_START, SSC_START_RISING_RF) |
-                       SSC_BF(TCMR_CKI, SSC_CKI_RISING) |
-                       SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) |
-                       SSC_BF(TCMR_CKS, SSC_CKS_DIV));
-
-               tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-                       SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) |
-                       SSC_BF(TFMR_DATNB, channels - 1) |
-                       SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1));
-               break;
-
-
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
-       default:
-               pr_warning("at32-ssc: unsupported DAI format 0x%x\n",
-                          ssc_p->daifmt);
-               return -EINVAL;
-               break;
-       }
-       pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
-                rcmr, rfmr, tcmr, tfmr);
-
-
-       if (!ssc_p->initialized) {
-               /* enable peripheral clock */
-               pr_debug("at32-ssc: Starting clock\n");
-               clk_enable(ssc_p->ssc->clk);
-
-               /* Reset the SSC and its PDC registers */
-               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
-
-               ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
-
-               ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
-
-               ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0,
-                                 ssc_p->name, ssc_p);
-               if (ret < 0) {
-                       pr_warning("at32-ssc: request irq failed (%d)\n", ret);
-                       pr_debug("at32-ssc: Stopping clock\n");
-                       clk_disable(ssc_p->ssc->clk);
-                       return ret;
-               }
-
-               ssc_p->initialized = 1;
-       }
-
-       /* Set SSC clock mode register */
-       ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
-
-       /* set receive clock mode and format */
-       ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
-       ssc_writel(ssc_p->ssc->regs, RFMR, rfmr);
-
-       /* set transmit clock mode and format */
-       ssc_writel(ssc_p->ssc->regs, TCMR, tcmr);
-       ssc_writel(ssc_p->ssc->regs, TFMR, tfmr);
-
-       pr_debug("at32-ssc: SSC initialized\n");
-       return 0;
-}
-
-
-
-static int at32_ssc_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-       struct at32_pcm_dma_params *dma_params;
-
-       dma_params = ssc_p->dma_params[substream->stream];
-
-       ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable);
-
-       return 0;
-}
-
-
-
-#ifdef CONFIG_PM
-static int at32_ssc_suspend(struct platform_device *pdev,
-                           struct snd_soc_dai *cpu_dai)
-{
-       struct at32_ssc_info *ssc_p;
-
-       if (!cpu_dai->active)
-               return 0;
-
-       ssc_p = &ssc_info[cpu_dai->id];
-
-       /* Save the status register before disabling transmit and receive */
-       ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
-       ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS));
-
-       /* Save the current interrupt mask, then disable unmasked interrupts */
-       ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR);
-       ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr);
-
-       ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR);
-       ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR);
-       ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR);
-       ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);
-       ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);
-
-       return 0;
-}
-
-
-
-static int at32_ssc_resume(struct platform_device *pdev,
-                          struct snd_soc_dai *cpu_dai)
-{
-       struct at32_ssc_info *ssc_p;
-       u32 cr;
-
-       if (!cpu_dai->active)
-               return 0;
-
-       ssc_p = &ssc_info[cpu_dai->id];
-
-       /* restore SSC register settings */
-       ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
-       ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);
-       ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr);
-       ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr);
-       ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr);
-
-       /* re-enable interrupts */
-       ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr);
-
-       /* Re-enable recieve and transmit as appropriate */
-       cr = 0;
-       cr |=
-           (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0;
-       cr |=
-           (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0;
-       ssc_writel(ssc_p->ssc->regs, CR, cr);
-
-       return 0;
-}
-#else /* CONFIG_PM */
-#  define at32_ssc_suspend     NULL
-#  define at32_ssc_resume      NULL
-#endif /* CONFIG_PM */
-
-
-#define AT32_SSC_RATES \
-    (SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-     SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-
-#define AT32_SSC_FORMATS \
-    (SNDRV_PCM_FMTBIT_S8  | SNDRV_PCM_FMTBIT_S16 | \
-     SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32)
-
-
-struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = {
-       {
-        .name = "at32-ssc0",
-        .id = 0,
-        .type = SND_SOC_DAI_PCM,
-        .suspend = at32_ssc_suspend,
-        .resume = at32_ssc_resume,
-        .playback = {
-                     .channels_min = 1,
-                     .channels_max = 2,
-                     .rates = AT32_SSC_RATES,
-                     .formats = AT32_SSC_FORMATS,
-                     },
-        .capture = {
-                    .channels_min = 1,
-                    .channels_max = 2,
-                    .rates = AT32_SSC_RATES,
-                    .formats = AT32_SSC_FORMATS,
-                    },
-        .ops = {
-                .startup = at32_ssc_startup,
-                .shutdown = at32_ssc_shutdown,
-                .prepare = at32_ssc_prepare,
-                .hw_params = at32_ssc_hw_params,
-                },
-        .dai_ops = {
-                    .set_sysclk = at32_ssc_set_dai_sysclk,
-                    .set_fmt = at32_ssc_set_dai_fmt,
-                    .set_clkdiv = at32_ssc_set_dai_clkdiv,
-                    },
-        .private_data = &ssc_info[0],
-        },
-       {
-        .name = "at32-ssc1",
-        .id = 1,
-        .type = SND_SOC_DAI_PCM,
-        .suspend = at32_ssc_suspend,
-        .resume = at32_ssc_resume,
-        .playback = {
-                     .channels_min = 1,
-                     .channels_max = 2,
-                     .rates = AT32_SSC_RATES,
-                     .formats = AT32_SSC_FORMATS,
-                     },
-        .capture = {
-                    .channels_min = 1,
-                    .channels_max = 2,
-                    .rates = AT32_SSC_RATES,
-                    .formats = AT32_SSC_FORMATS,
-                    },
-        .ops = {
-                .startup = at32_ssc_startup,
-                .shutdown = at32_ssc_shutdown,
-                .prepare = at32_ssc_prepare,
-                .hw_params = at32_ssc_hw_params,
-                },
-        .dai_ops = {
-                    .set_sysclk = at32_ssc_set_dai_sysclk,
-                    .set_fmt = at32_ssc_set_dai_fmt,
-                    .set_clkdiv = at32_ssc_set_dai_clkdiv,
-                    },
-        .private_data = &ssc_info[1],
-        },
-       {
-        .name = "at32-ssc2",
-        .id = 2,
-        .type = SND_SOC_DAI_PCM,
-        .suspend = at32_ssc_suspend,
-        .resume = at32_ssc_resume,
-        .playback = {
-                     .channels_min = 1,
-                     .channels_max = 2,
-                     .rates = AT32_SSC_RATES,
-                     .formats = AT32_SSC_FORMATS,
-                     },
-        .capture = {
-                    .channels_min = 1,
-                    .channels_max = 2,
-                    .rates = AT32_SSC_RATES,
-                    .formats = AT32_SSC_FORMATS,
-                    },
-        .ops = {
-                .startup = at32_ssc_startup,
-                .shutdown = at32_ssc_shutdown,
-                .prepare = at32_ssc_prepare,
-                .hw_params = at32_ssc_hw_params,
-                },
-        .dai_ops = {
-                    .set_sysclk = at32_ssc_set_dai_sysclk,
-                    .set_fmt = at32_ssc_set_dai_fmt,
-                    .set_clkdiv = at32_ssc_set_dai_clkdiv,
-                    },
-        .private_data = &ssc_info[2],
-        },
-};
-EXPORT_SYMBOL_GPL(at32_ssc_dai);
-
-
-MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
-MODULE_DESCRIPTION("AT32 SSC ASoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h
deleted file mode 100644 (file)
index 3c052db..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* sound/soc/at32/at32-ssc.h
- * ASoC SSC interface for Atmel AT32 SoC
- *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __SOUND_SOC_AT32_AT32_SSC_H
-#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__
-
-#include <linux/types.h>
-#include <linux/atmel-ssc.h>
-
-#include "at32-pcm.h"
-
-
-
-struct at32_ssc_state {
-       u32 ssc_cmr;
-       u32 ssc_rcmr;
-       u32 ssc_rfmr;
-       u32 ssc_tcmr;
-       u32 ssc_tfmr;
-       u32 ssc_sr;
-       u32 ssc_imr;
-};
-
-
-
-struct at32_ssc_info {
-       char *name;
-       struct ssc_device *ssc;
-       spinlock_t lock;        /* lock for dir_mask */
-       unsigned short dir_mask;        /* 0=unused, 1=playback, 2=capture */
-       unsigned short initialized;     /* true if SSC has been initialized */
-       unsigned short daifmt;
-       unsigned short cmr_div;
-       unsigned short tcmr_period;
-       unsigned short rcmr_period;
-       struct at32_pcm_dma_params *dma_params[2];
-       struct at32_ssc_state ssc_state;
-};
-
-
-/* SSC divider ids */
-#define AT32_SSC_CMR_DIV        0      /* MCK divider for BCLK */
-#define AT32_SSC_TCMR_PERIOD    1      /* BCLK divider for transmit FS */
-#define AT32_SSC_RCMR_PERIOD    2      /* BCLK divider for receive FS */
-
-
-extern struct snd_soc_dai at32_ssc_dai[];
-
-
-
-#endif /* __SOUND_SOC_AT32_AT32_SSC_H */
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
deleted file mode 100644 (file)
index 85a8832..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-config SND_AT91_SOC
-       tristate "SoC Audio for the Atmel AT91 System-on-Chip"
-       depends on ARCH_AT91
-       help
-         Say Y or M if you want to add support for codecs attached to
-         the AT91 SSC interface. You will also need
-         to select the audio interfaces to support below.
-
-config SND_AT91_SOC_SSC
-       tristate
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
deleted file mode 100644 (file)
index b817f11..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# AT91 Platform Support
-snd-soc-at91-objs := at91-pcm.o
-snd-soc-at91-ssc-objs := at91-ssc.o
-
-obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
-obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c
deleted file mode 100644 (file)
index 7ab48bd..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC
- *
- * Author:     Frank Mandarino <fmandarino@endrelia.com>
- *             Endrelia Technologies Inc.
- * Created:    Mar 3, 2006
- *
- * Based on pxa2xx-pcm.c by:
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 30, 2004
- * Copyright:  (C) 2004 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/atmel_pdc.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <mach/hardware.h>
-#include <mach/at91_ssc.h>
-
-#include "at91-pcm.h"
-
-#if 0
-#define        DBG(x...)       printk(KERN_INFO "at91-pcm: " x)
-#else
-#define        DBG(x...)
-#endif
-
-static const struct snd_pcm_hardware at91_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                 SNDRV_PCM_INFO_PAUSE,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 8192,
-       .periods_min            = 2,
-       .periods_max            = 1024,
-       .buffer_bytes_max       = 32 * 1024,
-};
-
-struct at91_runtime_data {
-       struct at91_pcm_dma_params *params;
-       dma_addr_t dma_buffer;                  /* physical address of dma buffer */
-       dma_addr_t dma_buffer_end;              /* first address beyond DMA buffer */
-       size_t period_size;
-       dma_addr_t period_ptr;                  /* physical address of next period */
-       u32 pdc_xpr_save;                       /* PDC register save */
-       u32 pdc_xcr_save;
-       u32 pdc_xnpr_save;
-       u32 pdc_xncr_save;
-};
-
-static void at91_pcm_dma_irq(u32 ssc_sr,
-       struct snd_pcm_substream *substream)
-{
-       struct at91_runtime_data *prtd = substream->runtime->private_data;
-       struct at91_pcm_dma_params *params = prtd->params;
-       static int count = 0;
-
-       count++;
-
-       if (ssc_sr & params->mask->ssc_endbuf) {
-
-               printk(KERN_WARNING
-                       "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
-                       substream->stream == SNDRV_PCM_STREAM_PLAYBACK
-                               ? "underrun" : "overrun",
-                       params->name, ssc_sr, count);
-
-               /* re-start the PDC */
-               at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-
-               prtd->period_ptr += prtd->period_size;
-               if (prtd->period_ptr >= prtd->dma_buffer_end) {
-                       prtd->period_ptr = prtd->dma_buffer;
-               }
-
-               at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
-               at91_ssc_write(params->ssc_base + params->pdc->xcr,
-                               prtd->period_size / params->pdc_xfer_size);
-
-               at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
-       }
-
-       if (ssc_sr & params->mask->ssc_endx) {
-
-               /* Load the PDC next pointer and counter registers */
-               prtd->period_ptr += prtd->period_size;
-               if (prtd->period_ptr >= prtd->dma_buffer_end) {
-                       prtd->period_ptr = prtd->dma_buffer;
-               }
-               at91_ssc_write(params->ssc_base + params->pdc->xnpr,
-                              prtd->period_ptr);
-               at91_ssc_write(params->ssc_base + params->pdc->xncr,
-                               prtd->period_size / params->pdc_xfer_size);
-       }
-
-       snd_pcm_period_elapsed(substream);
-}
-
-static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct at91_runtime_data *prtd = runtime->private_data;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       /* this may get called several times by oss emulation
-        * with different params */
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = params_buffer_bytes(params);
-
-       prtd->params = rtd->dai->cpu_dai->dma_data;
-       prtd->params->dma_intr_handler = at91_pcm_dma_irq;
-
-       prtd->dma_buffer = runtime->dma_addr;
-       prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
-       prtd->period_size = params_period_bytes(params);
-
-       DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
-               prtd->params->name, runtime->dma_bytes, prtd->period_size);
-       return 0;
-}
-
-static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct at91_runtime_data *prtd = substream->runtime->private_data;
-       struct at91_pcm_dma_params *params = prtd->params;
-
-       if (params != NULL) {
-               at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-               prtd->params->dma_intr_handler = NULL;
-       }
-
-       return 0;
-}
-
-static int at91_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct at91_runtime_data *prtd = substream->runtime->private_data;
-       struct at91_pcm_dma_params *params = prtd->params;
-
-       at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
-                       params->mask->ssc_endx | params->mask->ssc_endbuf);
-
-       at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-       return 0;
-}
-
-static int at91_pcm_trigger(struct snd_pcm_substream *substream,
-       int cmd)
-{
-       struct at91_runtime_data *prtd = substream->runtime->private_data;
-       struct at91_pcm_dma_params *params = prtd->params;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               prtd->period_ptr = prtd->dma_buffer;
-
-               at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
-               at91_ssc_write(params->ssc_base + params->pdc->xcr,
-                               prtd->period_size / params->pdc_xfer_size);
-
-               prtd->period_ptr += prtd->period_size;
-               at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
-               at91_ssc_write(params->ssc_base + params->pdc->xncr,
-                               prtd->period_size / params->pdc_xfer_size);
-
-               DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
-                       (unsigned long) prtd->period_ptr,
-                       at91_ssc_read(params->ssc_base + params->pdc->xpr),
-                       at91_ssc_read(params->ssc_base + params->pdc->xcr),
-                       at91_ssc_read(params->ssc_base + params->pdc->xnpr),
-                       at91_ssc_read(params->ssc_base + params->pdc->xncr));
-
-               at91_ssc_write(params->ssc_base + AT91_SSC_IER,
-                       params->mask->ssc_endx | params->mask->ssc_endbuf);
-
-               at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR,
-                       params->mask->pdc_enable);
-
-               DBG("sr=%lx imr=%lx\n",
-                   at91_ssc_read(params->ssc_base + AT91_SSC_SR),
-                   at91_ssc_read(params->ssc_base + AT91_SSC_IMR));
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-               break;
-
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static snd_pcm_uframes_t at91_pcm_pointer(
-       struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct at91_runtime_data *prtd = runtime->private_data;
-       struct at91_pcm_dma_params *params = prtd->params;
-       dma_addr_t ptr;
-       snd_pcm_uframes_t x;
-
-       ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
-       x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
-
-       if (x == runtime->buffer_size)
-               x = 0;
-       return x;
-}
-
-static int at91_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct at91_runtime_data *prtd;
-       int ret = 0;
-
-       snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
-
-       /* ensure that buffer size is a multiple of period size */
-       ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               goto out;
-
-       prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
-       if (prtd == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       runtime->private_data = prtd;
-
- out:
-       return ret;
-}
-
-static int at91_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct at91_runtime_data *prtd = substream->runtime->private_data;
-
-       kfree(prtd);
-       return 0;
-}
-
-static int at91_pcm_mmap(struct snd_pcm_substream *substream,
-       struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
-struct snd_pcm_ops at91_pcm_ops = {
-       .open           = at91_pcm_open,
-       .close          = at91_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = at91_pcm_hw_params,
-       .hw_free        = at91_pcm_hw_free,
-       .prepare        = at91_pcm_prepare,
-       .trigger        = at91_pcm_trigger,
-       .pointer        = at91_pcm_pointer,
-       .mmap           = at91_pcm_mmap,
-};
-
-static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
-       int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = at91_pcm_hardware.buffer_bytes_max;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-
-       DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
-               (void *) buf->area,
-               (void *) buf->addr,
-               size);
-
-       if (!buf->area)
-               return -ENOMEM;
-
-       buf->bytes = size;
-       return 0;
-}
-
-static u64 at91_pcm_dmamask = 0xffffffff;
-
-static int at91_pcm_new(struct snd_card *card,
-       struct snd_soc_dai *dai, struct snd_pcm *pcm)
-{
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &at91_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = 0xffffffff;
-
-       if (dai->playback.channels_min) {
-               ret = at91_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (dai->capture.channels_min) {
-               ret = at91_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
-}
-
-static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-
-#ifdef CONFIG_PM
-static int at91_pcm_suspend(struct platform_device *pdev,
-       struct snd_soc_dai *dai)
-{
-       struct snd_pcm_runtime *runtime = dai->runtime;
-       struct at91_runtime_data *prtd;
-       struct at91_pcm_dma_params *params;
-
-       if (!runtime)
-               return 0;
-
-       prtd = runtime->private_data;
-       params = prtd->params;
-
-       /* disable the PDC and save the PDC registers */
-
-       at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-
-       prtd->pdc_xpr_save  = at91_ssc_read(params->ssc_base + params->pdc->xpr);
-       prtd->pdc_xcr_save  = at91_ssc_read(params->ssc_base + params->pdc->xcr);
-       prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
-       prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
-
-       return 0;
-}
-
-static int at91_pcm_resume(struct platform_device *pdev,
-       struct snd_soc_dai *dai)
-{
-       struct snd_pcm_runtime *runtime = dai->runtime;
-       struct at91_runtime_data *prtd;
-       struct at91_pcm_dma_params *params;
-
-       if (!runtime)
-               return 0;
-
-       prtd = runtime->private_data;
-       params = prtd->params;
-
-       /* restore the PDC registers and enable the PDC */
-       at91_ssc_write(params->ssc_base + params->pdc->xpr,  prtd->pdc_xpr_save);
-       at91_ssc_write(params->ssc_base + params->pdc->xcr,  prtd->pdc_xcr_save);
-       at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
-       at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
-
-       at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
-       return 0;
-}
-#else
-#define at91_pcm_suspend       NULL
-#define at91_pcm_resume                NULL
-#endif
-
-struct snd_soc_platform at91_soc_platform = {
-       .name           = "at91-audio",
-       .pcm_ops        = &at91_pcm_ops,
-       .pcm_new        = at91_pcm_new,
-       .pcm_free       = at91_pcm_free_dma_buffers,
-       .suspend        = at91_pcm_suspend,
-       .resume         = at91_pcm_resume,
-};
-
-EXPORT_SYMBOL_GPL(at91_soc_platform);
-
-MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
-MODULE_DESCRIPTION("Atmel AT91 PCM module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h
deleted file mode 100644 (file)
index e5aada2..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC
- *
- * Author:     Frank Mandarino <fmandarino@endrelia.com>
- *             Endrelia Technologies Inc.
- * Created:    Mar 3, 2006
- *
- * Based on pxa2xx-pcm.h by:
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 30, 2004
- * Copyright:  MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _AT91_PCM_H
-#define _AT91_PCM_H
-
-#include <mach/hardware.h>
-
-struct at91_ssc_periph {
-       void __iomem    *base;
-       u32             pid;
-};
-
-/*
- * Registers and status bits that are required by the PCM driver.
- */
-struct at91_pdc_regs {
-       unsigned int    xpr;            /* PDC recv/trans pointer */
-       unsigned int    xcr;            /* PDC recv/trans counter */
-       unsigned int    xnpr;           /* PDC next recv/trans pointer */
-       unsigned int    xncr;           /* PDC next recv/trans counter */
-       unsigned int    ptcr;           /* PDC transfer control */
-};
-
-struct at91_ssc_mask {
-       u32     ssc_enable;             /* SSC recv/trans enable */
-       u32     ssc_disable;            /* SSC recv/trans disable */
-       u32     ssc_endx;               /* SSC ENDTX or ENDRX */
-       u32     ssc_endbuf;             /* SSC TXBUFE or RXBUFF */
-       u32     pdc_enable;             /* PDC recv/trans enable */
-       u32     pdc_disable;            /* PDC recv/trans disable */
-};
-
-/*
- * This structure, shared between the PCM driver and the interface,
- * contains all information required by the PCM driver to perform the
- * PDC DMA operation.  All fields except dma_intr_handler() are initialized
- * by the interface.  The dms_intr_handler() pointer is set by the PCM
- * driver and called by the interface SSC interrupt handler if it is
- * non-NULL.
- */
-struct at91_pcm_dma_params {
-       char *name;                     /* stream identifier */
-       int pdc_xfer_size;              /* PDC counter increment in bytes */
-       void __iomem *ssc_base;         /* SSC base address */
-       struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */
-       struct at91_ssc_mask *mask;/* SSC & PDC status bits */
-       struct snd_pcm_substream *substream;
-       void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
-};
-
-extern struct snd_soc_platform at91_soc_platform;
-
-#define at91_ssc_read(a)       ((unsigned long) __raw_readl(a))
-#define at91_ssc_write(a,v)    __raw_writel((v),(a))
-
-#endif /* _AT91_PCM_H */
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c
deleted file mode 100644 (file)
index 1b61cc4..0000000
+++ /dev/null
@@ -1,791 +0,0 @@
-/*
- * at91-ssc.c  --  ALSA SoC AT91 SSC Audio Layer Platform driver
- *
- * Author: Frank Mandarino <fmandarino@endrelia.com>
- *         Endrelia Technologies Inc.
- *
- * Based on pxa2xx Platform drivers by
- * Liam Girdwood <lrg@slimlogic.co.uk>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <mach/hardware.h>
-#include <mach/at91_pmc.h>
-#include <mach/at91_ssc.h>
-
-#include "at91-pcm.h"
-#include "at91-ssc.h"
-
-#if 0
-#define        DBG(x...)       printk(KERN_DEBUG "at91-ssc:" x)
-#else
-#define        DBG(x...)
-#endif
-
-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
-#define NUM_SSC_DEVICES                1
-#else
-#define NUM_SSC_DEVICES                3
-#endif
-
-
-/*
- * SSC PDC registers required by the PCM DMA engine.
- */
-static struct at91_pdc_regs pdc_tx_reg = {
-       .xpr            = ATMEL_PDC_TPR,
-       .xcr            = ATMEL_PDC_TCR,
-       .xnpr           = ATMEL_PDC_TNPR,
-       .xncr           = ATMEL_PDC_TNCR,
-};
-
-static struct at91_pdc_regs pdc_rx_reg = {
-       .xpr            = ATMEL_PDC_RPR,
-       .xcr            = ATMEL_PDC_RCR,
-       .xnpr           = ATMEL_PDC_RNPR,
-       .xncr           = ATMEL_PDC_RNCR,
-};
-
-/*
- * SSC & PDC status bits for transmit and receive.
- */
-static struct at91_ssc_mask ssc_tx_mask = {
-       .ssc_enable     = AT91_SSC_TXEN,
-       .ssc_disable    = AT91_SSC_TXDIS,
-       .ssc_endx       = AT91_SSC_ENDTX,
-       .ssc_endbuf     = AT91_SSC_TXBUFE,
-       .pdc_enable     = ATMEL_PDC_TXTEN,
-       .pdc_disable    = ATMEL_PDC_TXTDIS,
-};
-
-static struct at91_ssc_mask ssc_rx_mask = {
-       .ssc_enable     = AT91_SSC_RXEN,
-       .ssc_disable    = AT91_SSC_RXDIS,
-       .ssc_endx       = AT91_SSC_ENDRX,
-       .ssc_endbuf     = AT91_SSC_RXBUFF,
-       .pdc_enable     = ATMEL_PDC_RXTEN,
-       .pdc_disable    = ATMEL_PDC_RXTDIS,
-};
-
-
-/*
- * DMA parameters.
- */
-static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
-       {{
-       .name           = "SSC0 PCM out",
-       .pdc            = &pdc_tx_reg,
-       .mask           = &ssc_tx_mask,
-       },
-       {
-       .name           = "SSC0 PCM in",
-       .pdc            = &pdc_rx_reg,
-       .mask           = &ssc_rx_mask,
-       }},
-#if NUM_SSC_DEVICES == 3
-       {{
-       .name           = "SSC1 PCM out",
-       .pdc            = &pdc_tx_reg,
-       .mask           = &ssc_tx_mask,
-       },
-       {
-       .name           = "SSC1 PCM in",
-       .pdc            = &pdc_rx_reg,
-       .mask           = &ssc_rx_mask,
-       }},
-       {{
-       .name           = "SSC2 PCM out",
-       .pdc            = &pdc_tx_reg,
-       .mask           = &ssc_tx_mask,
-       },
-       {
-       .name           = "SSC2 PCM in",
-       .pdc            = &pdc_rx_reg,
-       .mask           = &ssc_rx_mask,
-       }},
-#endif
-};
-
-struct at91_ssc_state {
-       u32     ssc_cmr;
-       u32     ssc_rcmr;
-       u32     ssc_rfmr;
-       u32     ssc_tcmr;
-       u32     ssc_tfmr;
-       u32     ssc_sr;
-       u32     ssc_imr;
-};
-
-static struct at91_ssc_info {
-       char            *name;
-       struct at91_ssc_periph ssc;
-       spinlock_t      lock;           /* lock for dir_mask */
-       unsigned short  dir_mask;       /* 0=unused, 1=playback, 2=capture */
-       unsigned short  initialized;    /* 1=SSC has been initialized */
-       unsigned short  daifmt;
-       unsigned short  cmr_div;
-       unsigned short  tcmr_period;
-       unsigned short  rcmr_period;
-       struct at91_pcm_dma_params *dma_params[2];
-       struct at91_ssc_state ssc_state;
-
-} ssc_info[NUM_SSC_DEVICES] = {
-       {
-       .name           = "ssc0",
-       .lock           = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
-       .dir_mask       = 0,
-       .initialized    = 0,
-       },
-#if NUM_SSC_DEVICES == 3
-       {
-       .name           = "ssc1",
-       .lock           = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
-       .dir_mask       = 0,
-       .initialized    = 0,
-       },
-       {
-       .name           = "ssc2",
-       .lock           = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
-       .dir_mask       = 0,
-       .initialized    = 0,
-       },
-#endif
-};
-
-static unsigned int at91_ssc_sysclk;
-
-/*
- * SSC interrupt handler.  Passes PDC interrupts to the DMA
- * interrupt handler in the PCM driver.
- */
-static irqreturn_t at91_ssc_interrupt(int irq, void *dev_id)
-{
-       struct at91_ssc_info *ssc_p = dev_id;
-       struct at91_pcm_dma_params *dma_params;
-       u32 ssc_sr;
-       int i;
-
-       ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)
-                       & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
-
-       /*
-        * Loop through the substreams attached to this SSC.  If
-        * a DMA-related interrupt occurred on that substream, call
-        * the DMA interrupt handler function, if one has been
-        * registered in the dma_params structure by the PCM driver.
-        */
-       for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
-               dma_params = ssc_p->dma_params[i];
-
-               if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
-                       (ssc_sr &
-                       (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
-
-                       dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
-       }
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Startup.  Only that one substream allowed in each direction.
- */
-static int at91_ssc_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-       int dir_mask;
-
-       DBG("ssc_startup: SSC_SR=0x%08lx\n",
-                       at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
-       dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
-
-       spin_lock_irq(&ssc_p->lock);
-       if (ssc_p->dir_mask & dir_mask) {
-               spin_unlock_irq(&ssc_p->lock);
-               return -EBUSY;
-       }
-       ssc_p->dir_mask |= dir_mask;
-       spin_unlock_irq(&ssc_p->lock);
-
-       return 0;
-}
-
-/*
- * Shutdown.  Clear DMA parameters and shutdown the SSC if there
- * are no other substreams open.
- */
-static void at91_ssc_shutdown(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-       struct at91_pcm_dma_params *dma_params;
-       int dir, dir_mask;
-
-       dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
-       dma_params = ssc_p->dma_params[dir];
-
-       if (dma_params != NULL) {
-               at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
-                               dma_params->mask->ssc_disable);
-               DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
-                       at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
-
-               dma_params->ssc_base = NULL;
-               dma_params->substream = NULL;
-               ssc_p->dma_params[dir] = NULL;
-       }
-
-       dir_mask = 1 << dir;
-
-       spin_lock_irq(&ssc_p->lock);
-       ssc_p->dir_mask &= ~dir_mask;
-       if (!ssc_p->dir_mask) {
-               /* Shutdown the SSC clock. */
-               DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
-               at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
-
-               if (ssc_p->initialized) {
-                       free_irq(ssc_p->ssc.pid, ssc_p);
-                       ssc_p->initialized = 0;
-               }
-
-               /* Reset the SSC */
-               at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
-
-               /* Clear the SSC dividers */
-               ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
-       }
-       spin_unlock_irq(&ssc_p->lock);
-}
-
-/*
- * Record the SSC system clock rate.
- */
-static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-               int clk_id, unsigned int freq, int dir)
-{
-       /*
-        * The only clock supplied to the SSC is the AT91 master clock,
-        * which is only used if the SSC is generating BCLK and/or
-        * LRC clocks.
-        */
-       switch (clk_id) {
-       case AT91_SYSCLK_MCK:
-               at91_ssc_sysclk = freq;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/*
- * Record the DAI format for use in hw_params().
- */
-static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-               unsigned int fmt)
-{
-       struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-       ssc_p->daifmt = fmt;
-       return 0;
-}
-
-/*
- * Record SSC clock dividers for use in hw_params().
- */
-static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-       int div_id, int div)
-{
-       struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-       switch (div_id) {
-       case AT91SSC_CMR_DIV:
-               /*
-                * The same master clock divider is used for both
-                * transmit and receive, so if a value has already
-                * been set, it must match this value.
-                */
-               if (ssc_p->cmr_div == 0)
-                       ssc_p->cmr_div = div;
-               else
-                       if (div != ssc_p->cmr_div)
-                               return -EBUSY;
-               break;
-
-       case AT91SSC_TCMR_PERIOD:
-               ssc_p->tcmr_period = div;
-               break;
-
-       case AT91SSC_RCMR_PERIOD:
-               ssc_p->rcmr_period = div;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/*
- * Configure the SSC.
- */
-static int at91_ssc_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int id = rtd->dai->cpu_dai->id;
-       struct at91_ssc_info *ssc_p = &ssc_info[id];
-       struct at91_pcm_dma_params *dma_params;
-       int dir, channels, bits;
-       u32 tfmr, rfmr, tcmr, rcmr;
-       int start_event;
-       int ret;
-
-       /*
-        * Currently, there is only one set of dma params for
-        * each direction.  If more are added, this code will
-        * have to be changed to select the proper set.
-        */
-       dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
-
-       dma_params = &ssc_dma_params[id][dir];
-       dma_params->ssc_base = ssc_p->ssc.base;
-       dma_params->substream = substream;
-
-       ssc_p->dma_params[dir] = dma_params;
-
-       /*
-        * The cpu_dai->dma_data field is only used to communicate the
-        * appropriate DMA parameters to the pcm driver hw_params()
-        * function.  It should not be used for other purposes
-        * as it is common to all substreams.
-        */
-       rtd->dai->cpu_dai->dma_data = dma_params;
-
-       channels = params_channels(params);
-
-       /*
-        * Determine sample size in bits and the PDC increment.
-        */
-       switch(params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               bits = 8;
-               dma_params->pdc_xfer_size = 1;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               bits = 16;
-               dma_params->pdc_xfer_size = 2;
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               bits = 24;
-               dma_params->pdc_xfer_size = 4;
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               bits = 32;
-               dma_params->pdc_xfer_size = 4;
-               break;
-       default:
-               printk(KERN_WARNING "at91-ssc: unsupported PCM format\n");
-               return -EINVAL;
-       }
-
-       /*
-        * The SSC only supports up to 16-bit samples in I2S format, due
-        * to the size of the Frame Mode Register FSLEN field.
-        */
-       if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
-               && bits > 16) {
-               printk(KERN_WARNING
-                       "at91-ssc: sample size %d is too large for I2S\n", bits);
-               return -EINVAL;
-       }
-
-       /*
-        * Compute SSC register settings.
-        */
-       switch (ssc_p->daifmt
-               & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
-
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
-               /*
-                * I2S format, SSC provides BCLK and LRC clocks.
-                *
-                * The SSC transmit and receive clocks are generated from the
-                * MCK divider, and the BCLK signal is output on the SSC TK line.
-                */
-               rcmr =    (( ssc_p->rcmr_period         << 24) & AT91_SSC_PERIOD)
-                       | (( 1                          << 16) & AT91_SSC_STTDLY)
-                       | (( AT91_SSC_START_FALLING_RF       ) & AT91_SSC_START)
-                       | (( AT91_SSC_CK_RISING              ) & AT91_SSC_CKI)
-                       | (( AT91_SSC_CKO_NONE               ) & AT91_SSC_CKO)
-                       | (( AT91_SSC_CKS_DIV                ) & AT91_SSC_CKS);
-
-               rfmr =    (( AT91_SSC_FSEDGE_POSITIVE        ) & AT91_SSC_FSEDGE)
-                       | (( AT91_SSC_FSOS_NEGATIVE          ) & AT91_SSC_FSOS)
-                       | (((bits - 1)                  << 16) & AT91_SSC_FSLEN)
-                       | (((channels - 1)              <<  8) & AT91_SSC_DATNB)
-                       | (( 1                          <<  7) & AT91_SSC_MSBF)
-                       | (( 0                          <<  5) & AT91_SSC_LOOP)
-                       | (((bits - 1)                  <<  0) & AT91_SSC_DATALEN);
-
-               tcmr =    (( ssc_p->tcmr_period         << 24) & AT91_SSC_PERIOD)
-                       | (( 1                          << 16) & AT91_SSC_STTDLY)
-                       | (( AT91_SSC_START_FALLING_RF       ) & AT91_SSC_START)
-                       | (( AT91_SSC_CKI_FALLING            ) & AT91_SSC_CKI)
-                       | (( AT91_SSC_CKO_CONTINUOUS         ) & AT91_SSC_CKO)
-                       | (( AT91_SSC_CKS_DIV                ) & AT91_SSC_CKS);
-
-               tfmr =    (( AT91_SSC_FSEDGE_POSITIVE        ) & AT91_SSC_FSEDGE)
-                       | (( 0                          << 23) & AT91_SSC_FSDEN)
-                       | (( AT91_SSC_FSOS_NEGATIVE          ) & AT91_SSC_FSOS)
-                       | (((bits - 1)                  << 16) & AT91_SSC_FSLEN)
-                       | (((channels - 1)              <<  8) & AT91_SSC_DATNB)
-                       | (( 1                          <<  7) & AT91_SSC_MSBF)
-                       | (( 0                          <<  5) & AT91_SSC_DATDEF)
-                       | (((bits - 1)                  <<  0) & AT91_SSC_DATALEN);
-               break;
-
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-               /*
-                * I2S format, CODEC supplies BCLK and LRC clocks.
-                *
-                * The SSC transmit clock is obtained from the BCLK signal on
-                * on the TK line, and the SSC receive clock is generated from the
-                * transmit clock.
-                *
-                * For single channel data, one sample is transferred on the falling
-                * edge of the LRC clock.  For two channel data, one sample is
-                * transferred on both edges of the LRC clock.
-                */
-               start_event = channels == 1
-                               ? AT91_SSC_START_FALLING_RF
-                               : AT91_SSC_START_EDGE_RF;
-
-               rcmr =    (( 0                          << 24) & AT91_SSC_PERIOD)
-                       | (( 1                          << 16) & AT91_SSC_STTDLY)
-                       | (( start_event                     ) & AT91_SSC_START)
-                       | (( AT91_SSC_CK_RISING              ) & AT91_SSC_CKI)
-                       | (( AT91_SSC_CKO_NONE               ) & AT91_SSC_CKO)
-                       | (( AT91_SSC_CKS_CLOCK              ) & AT91_SSC_CKS);
-
-               rfmr =    (( AT91_SSC_FSEDGE_POSITIVE        ) & AT91_SSC_FSEDGE)
-                       | (( AT91_SSC_FSOS_NONE              ) & AT91_SSC_FSOS)
-                       | (( 0                          << 16) & AT91_SSC_FSLEN)
-                       | (( 0                          <<  8) & AT91_SSC_DATNB)
-                       | (( 1                          <<  7) & AT91_SSC_MSBF)
-                       | (( 0                          <<  5) & AT91_SSC_LOOP)
-                       | (((bits - 1)                  <<  0) & AT91_SSC_DATALEN);
-
-               tcmr =    (( 0                          << 24) & AT91_SSC_PERIOD)
-                       | (( 1                          << 16) & AT91_SSC_STTDLY)
-                       | (( start_event                     ) & AT91_SSC_START)
-                       | (( AT91_SSC_CKI_FALLING            ) & AT91_SSC_CKI)
-                       | (( AT91_SSC_CKO_NONE               ) & AT91_SSC_CKO)
-                       | (( AT91_SSC_CKS_PIN                ) & AT91_SSC_CKS);
-
-               tfmr =    (( AT91_SSC_FSEDGE_POSITIVE        ) & AT91_SSC_FSEDGE)
-                       | (( 0                          << 23) & AT91_SSC_FSDEN)
-                       | (( AT91_SSC_FSOS_NONE              ) & AT91_SSC_FSOS)
-                       | (( 0                          << 16) & AT91_SSC_FSLEN)
-                       | (( 0                          <<  8) & AT91_SSC_DATNB)
-                       | (( 1                          <<  7) & AT91_SSC_MSBF)
-                       | (( 0                          <<  5) & AT91_SSC_DATDEF)
-                       | (((bits - 1)                  <<  0) & AT91_SSC_DATALEN);
-               break;
-
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
-               /*
-                * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
-                *
-                * The SSC transmit and receive clocks are generated from the
-                * MCK divider, and the BCLK signal is output on the SSC TK line.
-                */
-               rcmr =    (( ssc_p->rcmr_period         << 24) & AT91_SSC_PERIOD)
-                       | (( 1                          << 16) & AT91_SSC_STTDLY)
-                       | (( AT91_SSC_START_RISING_RF        ) & AT91_SSC_START)
-                       | (( AT91_SSC_CK_RISING              ) & AT91_SSC_CKI)
-                       | (( AT91_SSC_CKO_NONE               ) & AT91_SSC_CKO)
-                       | (( AT91_SSC_CKS_DIV                ) & AT91_SSC_CKS);
-
-               rfmr =    (( AT91_SSC_FSEDGE_POSITIVE        ) & AT91_SSC_FSEDGE)
-                       | (( AT91_SSC_FSOS_POSITIVE          ) & AT91_SSC_FSOS)
-                       | (( 0                          << 16) & AT91_SSC_FSLEN)
-                       | (((channels - 1)              <<  8) & AT91_SSC_DATNB)
-                       | (( 1                          <<  7) & AT91_SSC_MSBF)
-                       | (( 0                          <<  5) & AT91_SSC_LOOP)
-                       | (((bits - 1)                  <<  0) & AT91_SSC_DATALEN);
-
-               tcmr =    (( ssc_p->tcmr_period         << 24) & AT91_SSC_PERIOD)
-                       | (( 1                          << 16) & AT91_SSC_STTDLY)
-                       | (( AT91_SSC_START_RISING_RF        ) & AT91_SSC_START)
-                       | (( AT91_SSC_CK_RISING              ) & AT91_SSC_CKI)
-                       | (( AT91_SSC_CKO_CONTINUOUS         ) & AT91_SSC_CKO)
-                       | (( AT91_SSC_CKS_DIV                ) & AT91_SSC_CKS);
-
-               tfmr =    (( AT91_SSC_FSEDGE_POSITIVE        ) & AT91_SSC_FSEDGE)
-                       | (( 0                          << 23) & AT91_SSC_FSDEN)
-                       | (( AT91_SSC_FSOS_POSITIVE          ) & AT91_SSC_FSOS)
-                       | (( 0                          << 16) & AT91_SSC_FSLEN)
-                       | (((channels - 1)              <<  8) & AT91_SSC_DATNB)
-                       | (( 1                          <<  7) & AT91_SSC_MSBF)
-                       | (( 0                          <<  5) & AT91_SSC_DATDEF)
-                       | (((bits - 1)                  <<  0) & AT91_SSC_DATALEN);
-
-
-
-                       break;
-
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
-       default:
-               printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n",
-                       ssc_p->daifmt);
-               return -EINVAL;
-               break;
-       }
-       DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr);
-
-       if (!ssc_p->initialized) {
-
-               /* Enable PMC peripheral clock for this SSC */
-               DBG("Starting pid %d clock\n", ssc_p->ssc.pid);
-               at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
-
-               /* Reset the SSC and its PDC registers */
-               at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
-
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0);
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0);
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0);
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0);
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0);
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0);
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0);
-               at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0);
-
-               if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt,
-                                       0, ssc_p->name, ssc_p)) < 0) {
-                       printk(KERN_WARNING "at91-ssc: request_irq failure\n");
-
-                       DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
-                       at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
-                       return ret;
-               }
-
-               ssc_p->initialized = 1;
-       }
-
-       /* set SSC clock mode register */
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div);
-
-       /* set receive clock mode and format */
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);
-
-       /* set transmit clock mode and format */
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);
-
-       DBG("hw_params: SSC initialized\n");
-       return 0;
-}
-
-
-static int at91_ssc_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-       struct at91_pcm_dma_params *dma_params;
-       int dir;
-
-       dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
-       dma_params = ssc_p->dma_params[dir];
-
-       at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
-                       dma_params->mask->ssc_enable);
-
-       DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit",
-               at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR));
-       return 0;
-}
-
-
-#ifdef CONFIG_PM
-static int at91_ssc_suspend(struct platform_device *pdev,
-       struct snd_soc_dai *cpu_dai)
-{
-       struct at91_ssc_info *ssc_p;
-
-       if(!cpu_dai->active)
-               return 0;
-
-       ssc_p = &ssc_info[cpu_dai->id];
-
-       /* Save the status register before disabling transmit and receive. */
-       ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
-                       AT91_SSC_TXDIS | AT91_SSC_RXDIS);
-
-       /* Save the current interrupt mask, then disable unmasked interrupts. */
-       ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr);
-
-       ssc_p->ssc_state.ssc_cmr  = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);
-       ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
-       ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR);
-       ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR);
-       ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR);
-
-       return 0;
-}
-
-static int at91_ssc_resume(struct platform_device *pdev,
-       struct snd_soc_dai *cpu_dai)
-{
-       struct at91_ssc_info *ssc_p;
-
-       if(!cpu_dai->active)
-               return 0;
-
-       ssc_p = &ssc_info[cpu_dai->id];
-
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr);
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR,  ssc_p->ssc_state.ssc_cmr);
-
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER,  ssc_p->ssc_state.ssc_imr);
-
-       at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
-               ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
-               ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
-
-       return 0;
-}
-
-#else
-#define at91_ssc_suspend       NULL
-#define at91_ssc_resume                NULL
-#endif
-
-#define AT91_SSC_RATES (SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 |\
-                       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
-                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
-                       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
-                       SNDRV_PCM_RATE_96000)
-
-#define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
-                         SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-
-struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = {
-       {       .name = "at91-ssc0",
-               .id = 0,
-               .type = SND_SOC_DAI_PCM,
-               .suspend = at91_ssc_suspend,
-               .resume = at91_ssc_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = AT91_SSC_RATES,
-                       .formats = AT91_SSC_FORMATS,},
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = AT91_SSC_RATES,
-                       .formats = AT91_SSC_FORMATS,},
-               .ops = {
-                       .startup = at91_ssc_startup,
-                       .shutdown = at91_ssc_shutdown,
-                       .prepare = at91_ssc_prepare,
-                       .hw_params = at91_ssc_hw_params,},
-               .dai_ops = {
-                       .set_sysclk = at91_ssc_set_dai_sysclk,
-                       .set_fmt = at91_ssc_set_dai_fmt,
-                       .set_clkdiv = at91_ssc_set_dai_clkdiv,},
-               .private_data = &ssc_info[0].ssc,
-       },
-#if NUM_SSC_DEVICES == 3
-       {       .name = "at91-ssc1",
-               .id = 1,
-               .type = SND_SOC_DAI_PCM,
-               .suspend = at91_ssc_suspend,
-               .resume = at91_ssc_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = AT91_SSC_RATES,
-                       .formats = AT91_SSC_FORMATS,},
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = AT91_SSC_RATES,
-                       .formats = AT91_SSC_FORMATS,},
-               .ops = {
-                       .startup = at91_ssc_startup,
-                       .shutdown = at91_ssc_shutdown,
-                       .prepare = at91_ssc_prepare,
-                       .hw_params = at91_ssc_hw_params,},
-               .dai_ops = {
-                       .set_sysclk = at91_ssc_set_dai_sysclk,
-                       .set_fmt = at91_ssc_set_dai_fmt,
-                       .set_clkdiv = at91_ssc_set_dai_clkdiv,},
-               .private_data = &ssc_info[1].ssc,
-       },
-       {       .name = "at91-ssc2",
-               .id = 2,
-               .type = SND_SOC_DAI_PCM,
-               .suspend = at91_ssc_suspend,
-               .resume = at91_ssc_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = AT91_SSC_RATES,
-                       .formats = AT91_SSC_FORMATS,},
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = AT91_SSC_RATES,
-                       .formats = AT91_SSC_FORMATS,},
-               .ops = {
-                       .startup = at91_ssc_startup,
-                       .shutdown = at91_ssc_shutdown,
-                       .prepare = at91_ssc_prepare,
-                       .hw_params = at91_ssc_hw_params,},
-               .dai_ops = {
-                       .set_sysclk = at91_ssc_set_dai_sysclk,
-                       .set_fmt = at91_ssc_set_dai_fmt,
-                       .set_clkdiv = at91_ssc_set_dai_clkdiv,},
-               .private_data = &ssc_info[2].ssc,
-       },
-#endif
-};
-
-EXPORT_SYMBOL_GPL(at91_ssc_dai);
-
-/* Module information */
-MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
-MODULE_DESCRIPTION("AT91 SSC ASoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h
deleted file mode 100644 (file)
index 6b7bf38..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * at91-ssc.h - ALSA SSC interface for the Atmel AT91 SoC
- *
- * Author:     Frank Mandarino <fmandarino@endrelia.com>
- *             Endrelia Technologies Inc.
- * Created:    Jan 9, 2007
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _AT91_SSC_H
-#define _AT91_SSC_H
-
-/* SSC system clock ids */
-#define AT91_SYSCLK_MCK                0 /* SSC uses AT91 MCK as system clock */
-
-/* SSC divider ids */
-#define AT91SSC_CMR_DIV                0 /* MCK divider for BCLK */
-#define AT91SSC_TCMR_PERIOD    1 /* BCLK divider for transmit FS */
-#define AT91SSC_RCMR_PERIOD    2 /* BCLK divider for receive FS */
-
-extern struct snd_soc_dai at91_ssc_dai[];
-
-#endif /* _AT91_SSC_H */
-
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
new file mode 100644 (file)
index 0000000..a608d70
--- /dev/null
@@ -0,0 +1,43 @@
+config SND_ATMEL_SOC
+       tristate "SoC Audio for the Atmel System-on-Chip"
+       depends on ARCH_AT91 || AVR32
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the ATMEL SSC interface. You will also need
+         to select the audio interfaces to support below.
+
+config SND_ATMEL_SOC_SSC
+       tristate
+       depends on SND_ATMEL_SOC
+       help
+         Say Y or M if you want to add support for codecs the
+         ATMEL SSC interface. You will also needs to select the individual
+         machine drivers to support below.
+
+config SND_AT91_SOC_SAM9G20_WM8731
+       tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
+       depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC
+       select SND_ATMEL_SOC_SSC
+       select SND_SOC_WM8731
+       help
+         Say Y if you want to add support for SoC audio on WM8731-based
+         AT91sam9g20 evaluation board.
+
+config SND_AT32_SOC_PLAYPAQ
+        tristate "SoC Audio support for PlayPaq with WM8510"
+        depends on SND_ATMEL_SOC && BOARD_PLAYPAQ
+        select SND_ATMEL_SOC_SSC
+        select SND_SOC_WM8510
+        help
+          Say Y or M here if you want to add support for SoC audio
+          on the LRS PlayPaq.
+
+config SND_AT32_SOC_PLAYPAQ_SLAVE
+        bool "Run CODEC on PlayPaq in slave mode"
+        depends on SND_AT32_SOC_PLAYPAQ
+        default n
+        help
+          Say Y if you want to run with the AT32 SSC generating the BCLK
+          and FRAME signals on the PlayPaq.  Unless you want to play
+          with the AT32 as the SSC master, you probably want to say N here,
+          as this will give you better sound quality.
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
new file mode 100644 (file)
index 0000000..f54a7cc
--- /dev/null
@@ -0,0 +1,15 @@
+# AT91 Platform Support
+snd-soc-atmel-pcm-objs := atmel-pcm.o
+snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
+
+obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o
+obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
+
+# AT91 Machine Support
+snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
+
+# AT32 Machine Support
+snd-soc-playpaq-objs := playpaq_wm8510.o
+
+obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
+obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
similarity index 50%
rename from sound/soc/at32/at32-pcm.c
rename to sound/soc/atmel/atmel-pcm.c
index c83584f..394412f 100644 (file)
@@ -1,15 +1,34 @@
-/* sound/soc/at32/at32-pcm.c
- * ASoC PCM interface for Atmel AT32 SoC
+/*
+ * atmel-pcm.c  --  ALSA PCM interface for the Atmel atmel SoC.
  *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.org>
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *
+ * Based on at91-pcm. by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ *
+ * Based on pxa2xx-pcm.c by:
+ *
+ * Author:     Nicolas Pitre
+ * Created:    Nov 30, 2004
+ * Copyright:  (C) 2004 MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Note that this is basically a port of the sound/soc/at91-pcm.c to
- * the AVR32 kernel.  Thanks to Frank Mandarino for that code.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/atmel_pdc.h>
+#include <linux/atmel-ssc.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include "at32-pcm.h"
+#include <mach/hardware.h>
 
+#include "atmel-pcm.h"
 
 
 /*--------------------------------------------------------------------------*\
 /* TODO: These values were taken from the AT91 platform driver, check
  *      them against real values for AT32
  */
-static const struct snd_pcm_hardware at32_pcm_hardware = {
-       .info = (SNDRV_PCM_INFO_MMAP |
-                SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_INTERLEAVED |
-                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                SNDRV_PCM_INFO_PAUSE),
-
-       .formats = SNDRV_PCM_FMTBIT_S16,
-       .period_bytes_min = 32,
-       .period_bytes_max = 8192,       /* 512 frames * 16 bytes / frame */
-       .periods_min = 2,
-       .periods_max = 1024,
-       .buffer_bytes_max = 32 * 1024,
+static const struct snd_pcm_hardware atmel_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .periods_min            = 2,
+       .periods_max            = 1024,
+       .buffer_bytes_max       = 32 * 1024,
 };
 
 
-
 /*--------------------------------------------------------------------------*\
  * Data types
 \*--------------------------------------------------------------------------*/
-struct at32_runtime_data {
-       struct at32_pcm_dma_params *params;
-       dma_addr_t dma_buffer;  /* physical address of DMA buffer */
-       dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
+struct atmel_runtime_data {
+       struct atmel_pcm_dma_params *params;
+       dma_addr_t dma_buffer;          /* physical address of dma buffer */
+       dma_addr_t dma_buffer_end;      /* first address beyond DMA buffer */
        size_t period_size;
 
-       dma_addr_t period_ptr;  /* physical address of next period */
-       int periods;            /* period index of period_ptr */
+       dma_addr_t period_ptr;          /* physical address of next period */
+       int periods;                    /* period index of period_ptr */
 
-       /* Save PDC registers (for power management) */
+       /* PDC register save */
        u32 pdc_xpr_save;
        u32 pdc_xcr_save;
        u32 pdc_xnpr_save;
@@ -71,49 +89,51 @@ struct at32_runtime_data {
 };
 
 
-
 /*--------------------------------------------------------------------------*\
  * Helper functions
 \*--------------------------------------------------------------------------*/
-static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+       int stream)
 {
        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *dmabuf = &substream->dma_buffer;
-       size_t size = at32_pcm_hardware.buffer_bytes_max;
-
-       dmabuf->dev.type = SNDRV_DMA_TYPE_DEV;
-       dmabuf->dev.dev = pcm->card->dev;
-       dmabuf->private_data = NULL;
-       dmabuf->area = dma_alloc_coherent(pcm->card->dev, size,
-                                         &dmabuf->addr, GFP_KERNEL);
-       pr_debug("at32_pcm: preallocate_dma_buffer: "
-                "area=%p, addr=%p, size=%ld\n",
-                (void *)dmabuf->area, (void *)dmabuf->addr, size);
-
-       if (!dmabuf->area)
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       size_t size = atmel_pcm_hardware.buffer_bytes_max;
+
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_coherent(pcm->card->dev, size,
+                                         &buf->addr, GFP_KERNEL);
+       pr_debug("atmel-pcm:"
+               "preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+               (void *) buf->area,
+               (void *) buf->addr,
+               size);
+
+       if (!buf->area)
                return -ENOMEM;
 
-       dmabuf->bytes = size;
+       buf->bytes = size;
        return 0;
 }
-
-
-
 /*--------------------------------------------------------------------------*\
  * ISR
 \*--------------------------------------------------------------------------*/
-static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream)
+static void atmel_pcm_dma_irq(u32 ssc_sr,
+       struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *rtd = substream->runtime;
-       struct at32_runtime_data *prtd = rtd->private_data;
-       struct at32_pcm_dma_params *params = prtd->params;
+       struct atmel_runtime_data *prtd = substream->runtime->private_data;
+       struct atmel_pcm_dma_params *params = prtd->params;
        static int count;
 
        count++;
+
        if (ssc_sr & params->mask->ssc_endbuf) {
-               pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
-                          substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-                          "underrun" : "overrun", params->name, ssc_sr, count);
+               pr_warning("atmel-pcm: buffer %s on %s"
+                               " (SSC_SR=%#x, count=%d)\n",
+                               substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+                               ? "underrun" : "overrun",
+                               params->name, ssc_sr, count);
 
                /* re-start the PDC */
                ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
@@ -122,7 +142,6 @@ static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream)
                if (prtd->period_ptr >= prtd->dma_buffer_end)
                        prtd->period_ptr = prtd->dma_buffer;
 
-
                ssc_writex(params->ssc->regs, params->pdc->xpr,
                           prtd->period_ptr);
                ssc_writex(params->ssc->regs, params->pdc->xcr,
@@ -131,60 +150,58 @@ static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream)
                           params->mask->pdc_enable);
        }
 
-
        if (ssc_sr & params->mask->ssc_endx) {
                /* Load the PDC next pointer and counter registers */
                prtd->period_ptr += prtd->period_size;
                if (prtd->period_ptr >= prtd->dma_buffer_end)
                        prtd->period_ptr = prtd->dma_buffer;
+
                ssc_writex(params->ssc->regs, params->pdc->xnpr,
                           prtd->period_ptr);
                ssc_writex(params->ssc->regs, params->pdc->xncr,
                           prtd->period_size / params->pdc_xfer_size);
        }
 
-
        snd_pcm_period_elapsed(substream);
 }
 
 
-
 /*--------------------------------------------------------------------------*\
  * PCM operations
 \*--------------------------------------------------------------------------*/
-static int at32_pcm_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
+static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct at32_runtime_data *prtd = runtime->private_data;
+       struct atmel_runtime_data *prtd = runtime->private_data;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
        /* this may get called several times by oss emulation
-        * with different params
-        */
+        * with different params */
+
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        runtime->dma_bytes = params_buffer_bytes(params);
 
        prtd->params = rtd->dai->cpu_dai->dma_data;
-       prtd->params->dma_intr_handler = at32_pcm_dma_irq;
+       prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
 
        prtd->dma_buffer = runtime->dma_addr;
        prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
        prtd->period_size = params_period_bytes(params);
 
-       pr_debug("hw_params: DMA for %s initialized "
-                "(dma_bytes=%ld, period_size=%ld)\n",
-                prtd->params->name, runtime->dma_bytes, prtd->period_size);
-
+       pr_debug("atmel-pcm: "
+               "hw_params: DMA for %s initialized "
+               "(dma_bytes=%u, period_size=%u)\n",
+               prtd->params->name,
+               runtime->dma_bytes,
+               prtd->period_size);
        return 0;
 }
 
-
-
-static int at32_pcm_hw_free(struct snd_pcm_substream *substream)
+static int atmel_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       struct at32_runtime_data *prtd = substream->runtime->private_data;
-       struct at32_pcm_dma_params *params = prtd->params;
+       struct atmel_runtime_data *prtd = substream->runtime->private_data;
+       struct atmel_pcm_dma_params *params = prtd->params;
 
        if (params != NULL) {
                ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
@@ -195,32 +212,29 @@ static int at32_pcm_hw_free(struct snd_pcm_substream *substream)
        return 0;
 }
 
-
-
-static int at32_pcm_prepare(struct snd_pcm_substream *substream)
+static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
 {
-       struct at32_runtime_data *prtd = substream->runtime->private_data;
-       struct at32_pcm_dma_params *params = prtd->params;
+       struct atmel_runtime_data *prtd = substream->runtime->private_data;
+       struct atmel_pcm_dma_params *params = prtd->params;
 
        ssc_writex(params->ssc->regs, SSC_IDR,
                   params->mask->ssc_endx | params->mask->ssc_endbuf);
        ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
                   params->mask->pdc_disable);
-
        return 0;
 }
 
-
-static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
+       int cmd)
 {
        struct snd_pcm_runtime *rtd = substream->runtime;
-       struct at32_runtime_data *prtd = rtd->private_data;
-       struct at32_pcm_dma_params *params = prtd->params;
+       struct atmel_runtime_data *prtd = rtd->private_data;
+       struct atmel_pcm_dma_params *params = prtd->params;
        int ret = 0;
 
-       pr_debug("at32_pcm_trigger: buffer_size = %ld, "
-                "dma_area = %p, dma_bytes = %ld\n",
-                rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
+       pr_debug("atmel-pcm:buffer_size = %ld,"
+               "dma_area = %p, dma_bytes = %u\n",
+               rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -237,26 +251,25 @@ static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                ssc_writex(params->ssc->regs, params->pdc->xncr,
                           prtd->period_size / params->pdc_xfer_size);
 
-               pr_debug("trigger: period_ptr=%lx, xpr=%x, "
-                        "xcr=%d, xnpr=%x, xncr=%d\n",
-                        (unsigned long)prtd->period_ptr,
-                        ssc_readx(params->ssc->regs, params->pdc->xpr),
-                        ssc_readx(params->ssc->regs, params->pdc->xcr),
-                        ssc_readx(params->ssc->regs, params->pdc->xnpr),
-                        ssc_readx(params->ssc->regs, params->pdc->xncr));
+               pr_debug("atmel-pcm: trigger: "
+                       "period_ptr=%lx, xpr=%u, "
+                       "xcr=%u, xnpr=%u, xncr=%u\n",
+                       (unsigned long)prtd->period_ptr,
+                       ssc_readx(params->ssc->regs, params->pdc->xpr),
+                       ssc_readx(params->ssc->regs, params->pdc->xcr),
+                       ssc_readx(params->ssc->regs, params->pdc->xnpr),
+                       ssc_readx(params->ssc->regs, params->pdc->xncr));
 
                ssc_writex(params->ssc->regs, SSC_IER,
                           params->mask->ssc_endx | params->mask->ssc_endbuf);
                ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
                           params->mask->pdc_enable);
 
-               pr_debug("sr=%x, imr=%x\n",
-                        ssc_readx(params->ssc->regs, SSC_SR),
-                        ssc_readx(params->ssc->regs, SSC_IER));
+               pr_debug("sr=%u imr=%u\n",
+                       ssc_readx(params->ssc->regs, SSC_SR),
+                       ssc_readx(params->ssc->regs, SSC_IER));
                break;          /* SNDRV_PCM_TRIGGER_START */
 
-
-
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -264,7 +277,6 @@ static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                           params->mask->pdc_disable);
                break;
 
-
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
@@ -278,13 +290,12 @@ static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        return ret;
 }
 
-
-
-static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream)
+static snd_pcm_uframes_t atmel_pcm_pointer(
+       struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct at32_runtime_data *prtd = runtime->private_data;
-       struct at32_pcm_dma_params *params = prtd->params;
+       struct atmel_runtime_data *prtd = runtime->private_data;
+       struct atmel_pcm_dma_params *params = prtd->params;
        dma_addr_t ptr;
        snd_pcm_uframes_t x;
 
@@ -297,108 +308,95 @@ static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream)
        return x;
 }
 
-
-
-static int at32_pcm_open(struct snd_pcm_substream *substream)
+static int atmel_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct at32_runtime_data *prtd;
+       struct atmel_runtime_data *prtd;
        int ret = 0;
 
-       snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware);
+       snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware);
 
        /* ensure that buffer size is a multiple of period size */
        ret = snd_pcm_hw_constraint_integer(runtime,
-                                           SNDRV_PCM_HW_PARAM_PERIODS);
+                                               SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0)
                goto out;
 
-       prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+       prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL);
        if (prtd == NULL) {
                ret = -ENOMEM;
                goto out;
        }
        runtime->private_data = prtd;
 
-
-out:
+ out:
        return ret;
 }
 
-
-
-static int at32_pcm_close(struct snd_pcm_substream *substream)
+static int atmel_pcm_close(struct snd_pcm_substream *substream)
 {
-       struct at32_runtime_data *prtd = substream->runtime->private_data;
+       struct atmel_runtime_data *prtd = substream->runtime->private_data;
 
        kfree(prtd);
        return 0;
 }
 
-
-static int at32_pcm_mmap(struct snd_pcm_substream *substream,
-                        struct vm_area_struct *vma)
+static int atmel_pcm_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
 {
        return remap_pfn_range(vma, vma->vm_start,
-                              substream->dma_buffer.addr >> PAGE_SHIFT,
-                              vma->vm_end - vma->vm_start, vma->vm_page_prot);
+                      substream->dma_buffer.addr >> PAGE_SHIFT,
+                      vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
-
-
-static struct snd_pcm_ops at32_pcm_ops = {
-       .open = at32_pcm_open,
-       .close = at32_pcm_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = at32_pcm_hw_params,
-       .hw_free = at32_pcm_hw_free,
-       .prepare = at32_pcm_prepare,
-       .trigger = at32_pcm_trigger,
-       .pointer = at32_pcm_pointer,
-       .mmap = at32_pcm_mmap,
+struct snd_pcm_ops atmel_pcm_ops = {
+       .open           = atmel_pcm_open,
+       .close          = atmel_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = atmel_pcm_hw_params,
+       .hw_free        = atmel_pcm_hw_free,
+       .prepare        = atmel_pcm_prepare,
+       .trigger        = atmel_pcm_trigger,
+       .pointer        = atmel_pcm_pointer,
+       .mmap           = atmel_pcm_mmap,
 };
 
 
-
 /*--------------------------------------------------------------------------*\
  * ASoC platform driver
 \*--------------------------------------------------------------------------*/
-static u64 at32_pcm_dmamask = 0xffffffff;
+static u64 atmel_pcm_dmamask = 0xffffffff;
 
-static int at32_pcm_new(struct snd_card *card,
-                       struct snd_soc_dai *dai,
-                       struct snd_pcm *pcm)
+static int atmel_pcm_new(struct snd_card *card,
+       struct snd_soc_dai *dai, struct snd_pcm *pcm)
 {
        int ret = 0;
 
        if (!card->dev->dma_mask)
-               card->dev->dma_mask = &at32_pcm_dmamask;
+               card->dev->dma_mask = &atmel_pcm_dmamask;
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
        if (dai->playback.channels_min) {
-               ret = at32_pcm_preallocate_dma_buffer(
-                         pcm, SNDRV_PCM_STREAM_PLAYBACK);
+               ret = atmel_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
        if (dai->capture.channels_min) {
-               pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n");
-               ret = at32_pcm_preallocate_dma_buffer(
-                         pcm, SNDRV_PCM_STREAM_CAPTURE);
+               pr_debug("at32-pcm:"
+                               "Allocating PCM capture DMA buffer\n");
+               ret = atmel_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
                        goto out;
        }
-
-
-out:
+ out:
        return ret;
 }
 
-
-
-static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm)
+static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
 {
        struct snd_pcm_substream *substream;
        struct snd_dma_buffer *buf;
@@ -406,7 +404,7 @@ static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
        for (stream = 0; stream < 2; stream++) {
                substream = pcm->streams[stream].substream;
-               if (substream == NULL)
+               if (!substream)
                        continue;
 
                buf = &substream->dma_buffer;
@@ -418,24 +416,23 @@ static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
-
-
 #ifdef CONFIG_PM
-static int at32_pcm_suspend(struct platform_device *pdev,
-                           struct snd_soc_dai *dai)
+static int atmel_pcm_suspend(struct platform_device *pdev,
+       struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = dai->runtime;
-       struct at32_runtime_data *prtd;
-       struct at32_pcm_dma_params *params;
+       struct atmel_runtime_data *prtd;
+       struct atmel_pcm_dma_params *params;
 
-       if (runtime == NULL)
+       if (!runtime)
                return 0;
+
        prtd = runtime->private_data;
        params = prtd->params;
 
-       /* Disable the PDC and save the PDC registers */
-       ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-                  params->mask->pdc_disable);
+       /* disable the PDC and save the PDC registers */
+
+       ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
 
        prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
        prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
@@ -445,48 +442,43 @@ static int at32_pcm_suspend(struct platform_device *pdev,
        return 0;
 }
 
-
-
-static int at32_pcm_resume(struct platform_device *pdev,
-                          struct snd_soc_dai *dai)
+static int atmel_pcm_resume(struct platform_device *pdev,
+       struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = dai->runtime;
-       struct at32_runtime_data *prtd;
-       struct at32_pcm_dma_params *params;
+       struct atmel_runtime_data *prtd;
+       struct atmel_pcm_dma_params *params;
 
-       if (runtime == NULL)
+       if (!runtime)
                return 0;
+
        prtd = runtime->private_data;
        params = prtd->params;
 
-       /* Restore the PDC registers and enable the PDC */
+       /* restore the PDC registers and enable the PDC */
        ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
        ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
        ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
        ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
 
-       ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable);
+       ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
        return 0;
 }
-#else /* CONFIG_PM */
-#  define at32_pcm_suspend     NULL
-#  define at32_pcm_resume      NULL
-#endif /* CONFIG_PM */
-
-
-
-struct snd_soc_platform at32_soc_platform = {
-       .name = "at32-audio",
-       .pcm_ops = &at32_pcm_ops,
-       .pcm_new = at32_pcm_new,
-       .pcm_free = at32_pcm_free_dma_buffers,
-       .suspend = at32_pcm_suspend,
-       .resume = at32_pcm_resume,
+#else
+#define atmel_pcm_suspend      NULL
+#define atmel_pcm_resume       NULL
+#endif
+
+struct snd_soc_platform atmel_soc_platform = {
+       .name           = "atmel-audio",
+       .pcm_ops        = &atmel_pcm_ops,
+       .pcm_new        = atmel_pcm_new,
+       .pcm_free       = atmel_pcm_free_dma_buffers,
+       .suspend        = atmel_pcm_suspend,
+       .resume         = atmel_pcm_resume,
 };
-EXPORT_SYMBOL_GPL(at32_soc_platform);
-
-
+EXPORT_SYMBOL_GPL(atmel_soc_platform);
 
-MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
-MODULE_DESCRIPTION("Atmel AT32 PCM module");
+MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
+MODULE_DESCRIPTION("Atmel PCM module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
new file mode 100644 (file)
index 0000000..ec9b282
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *
+ * Based on at91-pcm. by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ *
+ * Based on pxa2xx-pcm.c by:
+ *
+ * Author:     Nicolas Pitre
+ * Created:    Nov 30, 2004
+ * Copyright:  (C) 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ATMEL_PCM_H
+#define _ATMEL_PCM_H
+
+#include <linux/atmel-ssc.h>
+
+/*
+ * Registers and status bits that are required by the PCM driver.
+ */
+struct atmel_pdc_regs {
+       unsigned int    xpr;            /* PDC recv/trans pointer */
+       unsigned int    xcr;            /* PDC recv/trans counter */
+       unsigned int    xnpr;           /* PDC next recv/trans pointer */
+       unsigned int    xncr;           /* PDC next recv/trans counter */
+       unsigned int    ptcr;           /* PDC transfer control */
+};
+
+struct atmel_ssc_mask {
+       u32     ssc_enable;             /* SSC recv/trans enable */
+       u32     ssc_disable;            /* SSC recv/trans disable */
+       u32     ssc_endx;               /* SSC ENDTX or ENDRX */
+       u32     ssc_endbuf;             /* SSC TXBUFE or RXBUFF */
+       u32     pdc_enable;             /* PDC recv/trans enable */
+       u32     pdc_disable;            /* PDC recv/trans disable */
+};
+
+/*
+ * This structure, shared between the PCM driver and the interface,
+ * contains all information required by the PCM driver to perform the
+ * PDC DMA operation.  All fields except dma_intr_handler() are initialized
+ * by the interface.  The dms_intr_handler() pointer is set by the PCM
+ * driver and called by the interface SSC interrupt handler if it is
+ * non-NULL.
+ */
+struct atmel_pcm_dma_params {
+       char *name;                     /* stream identifier */
+       int pdc_xfer_size;              /* PDC counter increment in bytes */
+       struct ssc_device *ssc;         /* SSC device for stream */
+       struct atmel_pdc_regs *pdc;     /* PDC receive or transmit registers */
+       struct atmel_ssc_mask *mask;    /* SSC & PDC status bits */
+       struct snd_pcm_substream *substream;
+       void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
+};
+
+extern struct snd_soc_platform atmel_soc_platform;
+
+
+/*
+ * SSC register access (since ssc_writel() / ssc_readl() require literal name)
+ */
+#define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
+#define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
+
+#endif /* _ATMEL_PCM_H */
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
new file mode 100644 (file)
index 0000000..0bb18df
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * atmel_ssc_dai.c  --  ALSA SoC ATMEL SSC Audio Layer Platform driver
+ *
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2008 Atmel
+ *
+ * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *         ATMEL CORP.
+ *
+ * Based on at91-ssc.c by
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Based on pxa2xx Platform drivers by
+ * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/atmel_pdc.h>
+
+#include <linux/atmel-ssc.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+
+#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
+#define NUM_SSC_DEVICES                1
+#else
+#define NUM_SSC_DEVICES                3
+#endif
+
+/*
+ * SSC PDC registers required by the PCM DMA engine.
+ */
+static struct atmel_pdc_regs pdc_tx_reg = {
+       .xpr            = ATMEL_PDC_TPR,
+       .xcr            = ATMEL_PDC_TCR,
+       .xnpr           = ATMEL_PDC_TNPR,
+       .xncr           = ATMEL_PDC_TNCR,
+};
+
+static struct atmel_pdc_regs pdc_rx_reg = {
+       .xpr            = ATMEL_PDC_RPR,
+       .xcr            = ATMEL_PDC_RCR,
+       .xnpr           = ATMEL_PDC_RNPR,
+       .xncr           = ATMEL_PDC_RNCR,
+};
+
+/*
+ * SSC & PDC status bits for transmit and receive.
+ */
+static struct atmel_ssc_mask ssc_tx_mask = {
+       .ssc_enable     = SSC_BIT(CR_TXEN),
+       .ssc_disable    = SSC_BIT(CR_TXDIS),
+       .ssc_endx       = SSC_BIT(SR_ENDTX),
+       .ssc_endbuf     = SSC_BIT(SR_TXBUFE),
+       .pdc_enable     = ATMEL_PDC_TXTEN,
+       .pdc_disable    = ATMEL_PDC_TXTDIS,
+};
+
+static struct atmel_ssc_mask ssc_rx_mask = {
+       .ssc_enable     = SSC_BIT(CR_RXEN),
+       .ssc_disable    = SSC_BIT(CR_RXDIS),
+       .ssc_endx       = SSC_BIT(SR_ENDRX),
+       .ssc_endbuf     = SSC_BIT(SR_RXBUFF),
+       .pdc_enable     = ATMEL_PDC_RXTEN,
+       .pdc_disable    = ATMEL_PDC_RXTDIS,
+};
+
+
+/*
+ * DMA parameters.
+ */
+static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
+       {{
+       .name           = "SSC0 PCM out",
+       .pdc            = &pdc_tx_reg,
+       .mask           = &ssc_tx_mask,
+       },
+       {
+       .name           = "SSC0 PCM in",
+       .pdc            = &pdc_rx_reg,
+       .mask           = &ssc_rx_mask,
+       } },
+#if NUM_SSC_DEVICES == 3
+       {{
+       .name           = "SSC1 PCM out",
+       .pdc            = &pdc_tx_reg,
+       .mask           = &ssc_tx_mask,
+       },
+       {
+       .name           = "SSC1 PCM in",
+       .pdc            = &pdc_rx_reg,
+       .mask           = &ssc_rx_mask,
+       } },
+       {{
+       .name           = "SSC2 PCM out",
+       .pdc            = &pdc_tx_reg,
+       .mask           = &ssc_tx_mask,
+       },
+       {
+       .name           = "SSC2 PCM in",
+       .pdc            = &pdc_rx_reg,
+       .mask           = &ssc_rx_mask,
+       } },
+#endif
+};
+
+
+static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
+       {
+       .name           = "ssc0",
+       .lock           = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
+       .dir_mask       = SSC_DIR_MASK_UNUSED,
+       .initialized    = 0,
+       },
+#if NUM_SSC_DEVICES == 3
+       {
+       .name           = "ssc1",
+       .lock           = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
+       .dir_mask       = SSC_DIR_MASK_UNUSED,
+       .initialized    = 0,
+       },
+       {
+       .name           = "ssc2",
+       .lock           = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
+       .dir_mask       = SSC_DIR_MASK_UNUSED,
+       .initialized    = 0,
+       },
+#endif
+};
+
+
+/*
+ * SSC interrupt handler.  Passes PDC interrupts to the DMA
+ * interrupt handler in the PCM driver.
+ */
+static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
+{
+       struct atmel_ssc_info *ssc_p = dev_id;
+       struct atmel_pcm_dma_params *dma_params;
+       u32 ssc_sr;
+       u32 ssc_substream_mask;
+       int i;
+
+       ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR)
+                       & (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR);
+
+       /*
+        * Loop through the substreams attached to this SSC.  If
+        * a DMA-related interrupt occurred on that substream, call
+        * the DMA interrupt handler function, if one has been
+        * registered in the dma_params structure by the PCM driver.
+        */
+       for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
+               dma_params = ssc_p->dma_params[i];
+
+               if ((dma_params != NULL) &&
+                       (dma_params->dma_intr_handler != NULL)) {
+                       ssc_substream_mask = (dma_params->mask->ssc_endx |
+                                       dma_params->mask->ssc_endbuf);
+                       if (ssc_sr & ssc_substream_mask) {
+                               dma_params->dma_intr_handler(ssc_sr,
+                                               dma_params->
+                                               substream);
+                       }
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+
+/*-------------------------------------------------------------------------*\
+ * DAI functions
+\*-------------------------------------------------------------------------*/
+/*
+ * Startup.  Only that one substream allowed in each direction.
+ */
+static int atmel_ssc_startup(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       int dir_mask;
+
+       pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
+               ssc_readl(ssc_p->ssc->regs, SR));
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dir_mask = SSC_DIR_MASK_PLAYBACK;
+       else
+               dir_mask = SSC_DIR_MASK_CAPTURE;
+
+       spin_lock_irq(&ssc_p->lock);
+       if (ssc_p->dir_mask & dir_mask) {
+               spin_unlock_irq(&ssc_p->lock);
+               return -EBUSY;
+       }
+       ssc_p->dir_mask |= dir_mask;
+       spin_unlock_irq(&ssc_p->lock);
+
+       return 0;
+}
+
+/*
+ * Shutdown.  Clear DMA parameters and shutdown the SSC if there
+ * are no other substreams open.
+ */
+static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_pcm_dma_params *dma_params;
+       int dir, dir_mask;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dir = 0;
+       else
+               dir = 1;
+
+       dma_params = ssc_p->dma_params[dir];
+
+       if (dma_params != NULL) {
+               ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
+               pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n",
+                       (dir ? "receive" : "transmit"),
+                       ssc_readl(ssc_p->ssc->regs, SR));
+
+               dma_params->ssc = NULL;
+               dma_params->substream = NULL;
+               ssc_p->dma_params[dir] = NULL;
+       }
+
+       dir_mask = 1 << dir;
+
+       spin_lock_irq(&ssc_p->lock);
+       ssc_p->dir_mask &= ~dir_mask;
+       if (!ssc_p->dir_mask) {
+               if (ssc_p->initialized) {
+                       /* Shutdown the SSC clock. */
+                       pr_debug("atmel_ssc_dau: Stopping clock\n");
+                       clk_disable(ssc_p->ssc->clk);
+
+                       free_irq(ssc_p->ssc->irq, ssc_p);
+                       ssc_p->initialized = 0;
+               }
+
+               /* Reset the SSC */
+               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+               /* Clear the SSC dividers */
+               ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
+       }
+       spin_unlock_irq(&ssc_p->lock);
+}
+
+
+/*
+ * Record the DAI format for use in hw_params().
+ */
+static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+               unsigned int fmt)
+{
+       struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+       ssc_p->daifmt = fmt;
+       return 0;
+}
+
+/*
+ * Record SSC clock dividers for use in hw_params().
+ */
+static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+       int div_id, int div)
+{
+       struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+       switch (div_id) {
+       case ATMEL_SSC_CMR_DIV:
+               /*
+                * The same master clock divider is used for both
+                * transmit and receive, so if a value has already
+                * been set, it must match this value.
+                */
+               if (ssc_p->cmr_div == 0)
+                       ssc_p->cmr_div = div;
+               else
+                       if (div != ssc_p->cmr_div)
+                               return -EBUSY;
+               break;
+
+       case ATMEL_SSC_TCMR_PERIOD:
+               ssc_p->tcmr_period = div;
+               break;
+
+       case ATMEL_SSC_RCMR_PERIOD:
+               ssc_p->rcmr_period = div;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Configure the SSC.
+ */
+static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       int id = rtd->dai->cpu_dai->id;
+       struct atmel_ssc_info *ssc_p = &ssc_info[id];
+       struct atmel_pcm_dma_params *dma_params;
+       int dir, channels, bits;
+       u32 tfmr, rfmr, tcmr, rcmr;
+       int start_event;
+       int ret;
+
+       /*
+        * Currently, there is only one set of dma params for
+        * each direction.  If more are added, this code will
+        * have to be changed to select the proper set.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dir = 0;
+       else
+               dir = 1;
+
+       dma_params = &ssc_dma_params[id][dir];
+       dma_params->ssc = ssc_p->ssc;
+       dma_params->substream = substream;
+
+       ssc_p->dma_params[dir] = dma_params;
+
+       /*
+        * The cpu_dai->dma_data field is only used to communicate the
+        * appropriate DMA parameters to the pcm driver hw_params()
+        * function.  It should not be used for other purposes
+        * as it is common to all substreams.
+        */
+       rtd->dai->cpu_dai->dma_data = dma_params;
+
+       channels = params_channels(params);
+
+       /*
+        * Determine sample size in bits and the PDC increment.
+        */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               bits = 8;
+               dma_params->pdc_xfer_size = 1;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bits = 16;
+               dma_params->pdc_xfer_size = 2;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               bits = 24;
+               dma_params->pdc_xfer_size = 4;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               bits = 32;
+               dma_params->pdc_xfer_size = 4;
+               break;
+       default:
+               printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format");
+               return -EINVAL;
+       }
+
+       /*
+        * The SSC only supports up to 16-bit samples in I2S format, due
+        * to the size of the Frame Mode Register FSLEN field.
+        */
+       if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
+               && bits > 16) {
+               printk(KERN_WARNING
+                               "atmel_ssc_dai: sample size %d"
+                               "is too large for I2S\n", bits);
+               return -EINVAL;
+       }
+
+       /*
+        * Compute SSC register settings.
+        */
+       switch (ssc_p->daifmt
+               & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+               /*
+                * I2S format, SSC provides BCLK and LRC clocks.
+                *
+                * The SSC transmit and receive clocks are generated
+                * from the MCK divider, and the BCLK signal
+                * is output on the SSC TK line.
+                */
+               rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+                       | SSC_BF(RCMR_STTDLY, START_DELAY)
+                       | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(RCMR_CKS, SSC_CKS_DIV);
+
+               rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
+                       | SSC_BF(RFMR_FSLEN, (bits - 1))
+                       | SSC_BF(RFMR_DATNB, (channels - 1))
+                       | SSC_BIT(RFMR_MSBF)
+                       | SSC_BF(RFMR_LOOP, 0)
+                       | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+               tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+                       | SSC_BF(TCMR_STTDLY, START_DELAY)
+                       | SSC_BF(TCMR_START, SSC_START_FALLING_RF)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+                       | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
+                       | SSC_BF(TCMR_CKS, SSC_CKS_DIV);
+
+               tfmr =    SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(TFMR_FSDEN, 0)
+                       | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
+                       | SSC_BF(TFMR_FSLEN, (bits - 1))
+                       | SSC_BF(TFMR_DATNB, (channels - 1))
+                       | SSC_BIT(TFMR_MSBF)
+                       | SSC_BF(TFMR_DATDEF, 0)
+                       | SSC_BF(TFMR_DATLEN, (bits - 1));
+               break;
+
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+               /*
+                * I2S format, CODEC supplies BCLK and LRC clocks.
+                *
+                * The SSC transmit clock is obtained from the BCLK signal on
+                * on the TK line, and the SSC receive clock is
+                * generated from the transmit clock.
+                *
+                *  For single channel data, one sample is transferred
+                * on the falling edge of the LRC clock.
+                * For two channel data, one sample is
+                * transferred on both edges of the LRC clock.
+                */
+               start_event = ((channels == 1)
+                               ? SSC_START_FALLING_RF
+                               : SSC_START_EDGE_RF);
+
+               rcmr =    SSC_BF(RCMR_PERIOD, 0)
+                       | SSC_BF(RCMR_STTDLY, START_DELAY)
+                       | SSC_BF(RCMR_START, start_event)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK);
+
+               rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
+                       | SSC_BF(RFMR_FSLEN, 0)
+                       | SSC_BF(RFMR_DATNB, 0)
+                       | SSC_BIT(RFMR_MSBF)
+                       | SSC_BF(RFMR_LOOP, 0)
+                       | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+               tcmr =    SSC_BF(TCMR_PERIOD, 0)
+                       | SSC_BF(TCMR_STTDLY, START_DELAY)
+                       | SSC_BF(TCMR_START, start_event)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+                       | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+
+               tfmr =    SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(TFMR_FSDEN, 0)
+                       | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
+                       | SSC_BF(TFMR_FSLEN, 0)
+                       | SSC_BF(TFMR_DATNB, 0)
+                       | SSC_BIT(TFMR_MSBF)
+                       | SSC_BF(TFMR_DATDEF, 0)
+                       | SSC_BF(TFMR_DATLEN, (bits - 1));
+               break;
+
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+               /*
+                * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
+                *
+                * The SSC transmit and receive clocks are generated from the
+                * MCK divider, and the BCLK signal is output
+                * on the SSC TK line.
+                */
+               rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+                       | SSC_BF(RCMR_STTDLY, 1)
+                       | SSC_BF(RCMR_START, SSC_START_RISING_RF)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(RCMR_CKS, SSC_CKS_DIV);
+
+               rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE)
+                       | SSC_BF(RFMR_FSLEN, 0)
+                       | SSC_BF(RFMR_DATNB, (channels - 1))
+                       | SSC_BIT(RFMR_MSBF)
+                       | SSC_BF(RFMR_LOOP, 0)
+                       | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+               tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+                       | SSC_BF(TCMR_STTDLY, 1)
+                       | SSC_BF(TCMR_START, SSC_START_RISING_RF)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
+                       | SSC_BF(TCMR_CKS, SSC_CKS_DIV);
+
+               tfmr =    SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(TFMR_FSDEN, 0)
+                       | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE)
+                       | SSC_BF(TFMR_FSLEN, 0)
+                       | SSC_BF(TFMR_DATNB, (channels - 1))
+                       | SSC_BIT(TFMR_MSBF)
+                       | SSC_BF(TFMR_DATDEF, 0)
+                       | SSC_BF(TFMR_DATLEN, (bits - 1));
+               break;
+
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+       default:
+               printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
+                       ssc_p->daifmt);
+               return -EINVAL;
+               break;
+       }
+       pr_debug("atmel_ssc_hw_params: "
+                       "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
+                       rcmr, rfmr, tcmr, tfmr);
+
+       if (!ssc_p->initialized) {
+
+               /* Enable PMC peripheral clock for this SSC */
+               pr_debug("atmel_ssc_dai: Starting clock\n");
+               clk_enable(ssc_p->ssc->clk);
+
+               /* Reset the SSC and its PDC registers */
+               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
+               ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+
+               ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+
+               ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
+                               ssc_p->name, ssc_p);
+               if (ret < 0) {
+                       printk(KERN_WARNING
+                                       "atmel_ssc_dai: request_irq failure\n");
+                       pr_debug("Atmel_ssc_dai: Stoping clock\n");
+                       clk_disable(ssc_p->ssc->clk);
+                       return ret;
+               }
+
+               ssc_p->initialized = 1;
+       }
+
+       /* set SSC clock mode register */
+       ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
+
+       /* set receive clock mode and format */
+       ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
+       ssc_writel(ssc_p->ssc->regs, RFMR, rfmr);
+
+       /* set transmit clock mode and format */
+       ssc_writel(ssc_p->ssc->regs, TCMR, tcmr);
+       ssc_writel(ssc_p->ssc->regs, TFMR, tfmr);
+
+       pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n");
+       return 0;
+}
+
+
+static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_pcm_dma_params *dma_params;
+       int dir;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dir = 0;
+       else
+               dir = 1;
+
+       dma_params = ssc_p->dma_params[dir];
+
+       ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
+
+       pr_debug("%s enabled SSC_SR=0x%08x\n",
+                       dir ? "receive" : "transmit",
+                       ssc_readl(ssc_p->ssc->regs, SR));
+       return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int atmel_ssc_suspend(struct platform_device *pdev,
+                           struct snd_soc_dai *cpu_dai)
+{
+       struct atmel_ssc_info *ssc_p;
+
+       if (!cpu_dai->active)
+               return 0;
+
+       ssc_p = &ssc_info[cpu_dai->id];
+
+       /* Save the status register before disabling transmit and receive */
+       ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
+       ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS));
+
+       /* Save the current interrupt mask, then disable unmasked interrupts */
+       ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR);
+       ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr);
+
+       ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR);
+       ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR);
+       ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR);
+       ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);
+       ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);
+
+       return 0;
+}
+
+
+
+static int atmel_ssc_resume(struct platform_device *pdev,
+                          struct snd_soc_dai *cpu_dai)
+{
+       struct atmel_ssc_info *ssc_p;
+       u32 cr;
+
+       if (!cpu_dai->active)
+               return 0;
+
+       ssc_p = &ssc_info[cpu_dai->id];
+
+       /* restore SSC register settings */
+       ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
+       ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);
+       ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr);
+       ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr);
+       ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr);
+
+       /* re-enable interrupts */
+       ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr);
+
+       /* Re-enable recieve and transmit as appropriate */
+       cr = 0;
+       cr |=
+           (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0;
+       cr |=
+           (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0;
+       ssc_writel(ssc_p->ssc->regs, CR, cr);
+
+       return 0;
+}
+#else /* CONFIG_PM */
+#  define atmel_ssc_suspend    NULL
+#  define atmel_ssc_resume     NULL
+#endif /* CONFIG_PM */
+
+
+#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
+                         SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
+       {       .name = "atmel-ssc0",
+               .id = 0,
+               .suspend = atmel_ssc_suspend,
+               .resume = atmel_ssc_resume,
+               .playback = {
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ATMEL_SSC_RATES,
+                       .formats = ATMEL_SSC_FORMATS,},
+               .capture = {
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ATMEL_SSC_RATES,
+                       .formats = ATMEL_SSC_FORMATS,},
+               .ops = {
+                       .startup = atmel_ssc_startup,
+                       .shutdown = atmel_ssc_shutdown,
+                       .prepare = atmel_ssc_prepare,
+                       .hw_params = atmel_ssc_hw_params,
+                       .set_fmt = atmel_ssc_set_dai_fmt,
+                       .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+               .private_data = &ssc_info[0],
+       },
+#if NUM_SSC_DEVICES == 3
+       {       .name = "atmel-ssc1",
+               .id = 1,
+               .suspend = atmel_ssc_suspend,
+               .resume = atmel_ssc_resume,
+               .playback = {
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ATMEL_SSC_RATES,
+                       .formats = ATMEL_SSC_FORMATS,},
+               .capture = {
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ATMEL_SSC_RATES,
+                       .formats = ATMEL_SSC_FORMATS,},
+               .ops = {
+                       .startup = atmel_ssc_startup,
+                       .shutdown = atmel_ssc_shutdown,
+                       .prepare = atmel_ssc_prepare,
+                       .hw_params = atmel_ssc_hw_params,
+                       .set_fmt = atmel_ssc_set_dai_fmt,
+                       .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+               .private_data = &ssc_info[1],
+       },
+       {       .name = "atmel-ssc2",
+               .id = 2,
+               .suspend = atmel_ssc_suspend,
+               .resume = atmel_ssc_resume,
+               .playback = {
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ATMEL_SSC_RATES,
+                       .formats = ATMEL_SSC_FORMATS,},
+               .capture = {
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ATMEL_SSC_RATES,
+                       .formats = ATMEL_SSC_FORMATS,},
+               .ops = {
+                       .startup = atmel_ssc_startup,
+                       .shutdown = atmel_ssc_shutdown,
+                       .prepare = atmel_ssc_prepare,
+                       .hw_params = atmel_ssc_hw_params,
+                       .set_fmt = atmel_ssc_set_dai_fmt,
+                       .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+               .private_data = &ssc_info[2],
+       },
+#endif
+};
+EXPORT_SYMBOL_GPL(atmel_ssc_dai);
+
+/* Module information */
+MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
+MODULE_DESCRIPTION("ATMEL SSC ASoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
new file mode 100644 (file)
index 0000000..a828746
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * atmel_ssc_dai.h - ALSA SSC interface for the Atmel  SoC
+ *
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2008 Atmel
+ *
+ * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *         ATMEL CORP.
+ *
+ * Based on at91-ssc.c by
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Based on pxa2xx Platform drivers by
+ * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ATMEL_SSC_DAI_H
+#define _ATMEL_SSC_DAI_H
+
+#include <linux/types.h>
+#include <linux/atmel-ssc.h>
+
+#include "atmel-pcm.h"
+
+/* SSC system clock ids */
+#define ATMEL_SYSCLK_MCK       0 /* SSC uses AT91 MCK as system clock */
+
+/* SSC divider ids */
+#define ATMEL_SSC_CMR_DIV      0 /* MCK divider for BCLK */
+#define ATMEL_SSC_TCMR_PERIOD  1 /* BCLK divider for transmit FS */
+#define ATMEL_SSC_RCMR_PERIOD  2 /* BCLK divider for receive FS */
+/*
+ * SSC direction masks
+ */
+#define SSC_DIR_MASK_UNUSED    0
+#define SSC_DIR_MASK_PLAYBACK  1
+#define SSC_DIR_MASK_CAPTURE   2
+
+/*
+ * SSC register values that Atmel left out of <linux/atmel-ssc.h>.  These
+ * are expected to be used with SSC_BF
+ */
+/* START bit field values */
+#define SSC_START_CONTINUOUS   0
+#define SSC_START_TX_RX                1
+#define SSC_START_LOW_RF       2
+#define SSC_START_HIGH_RF      3
+#define SSC_START_FALLING_RF   4
+#define SSC_START_RISING_RF    5
+#define SSC_START_LEVEL_RF     6
+#define SSC_START_EDGE_RF      7
+#define SSS_START_COMPARE_0    8
+
+/* CKI bit field values */
+#define SSC_CKI_FALLING                0
+#define SSC_CKI_RISING         1
+
+/* CKO bit field values */
+#define SSC_CKO_NONE           0
+#define SSC_CKO_CONTINUOUS     1
+#define SSC_CKO_TRANSFER       2
+
+/* CKS bit field values */
+#define SSC_CKS_DIV            0
+#define SSC_CKS_CLOCK          1
+#define SSC_CKS_PIN            2
+
+/* FSEDGE bit field values */
+#define SSC_FSEDGE_POSITIVE    0
+#define SSC_FSEDGE_NEGATIVE    1
+
+/* FSOS bit field values */
+#define SSC_FSOS_NONE          0
+#define SSC_FSOS_NEGATIVE      1
+#define SSC_FSOS_POSITIVE      2
+#define SSC_FSOS_LOW           3
+#define SSC_FSOS_HIGH          4
+#define SSC_FSOS_TOGGLE                5
+
+#define START_DELAY            1
+
+struct atmel_ssc_state {
+       u32 ssc_cmr;
+       u32 ssc_rcmr;
+       u32 ssc_rfmr;
+       u32 ssc_tcmr;
+       u32 ssc_tfmr;
+       u32 ssc_sr;
+       u32 ssc_imr;
+};
+
+
+struct atmel_ssc_info {
+       char *name;
+       struct ssc_device *ssc;
+       spinlock_t lock;        /* lock for dir_mask */
+       unsigned short dir_mask;        /* 0=unused, 1=playback, 2=capture */
+       unsigned short initialized;     /* true if SSC has been initialized */
+       unsigned short daifmt;
+       unsigned short cmr_div;
+       unsigned short tcmr_period;
+       unsigned short rcmr_period;
+       struct atmel_pcm_dma_params *dma_params[2];
+       struct atmel_ssc_state ssc_state;
+};
+extern struct snd_soc_dai atmel_ssc_dai[];
+
+#endif /* _AT91_SSC_DAI_H */
similarity index 98%
rename from sound/soc/at32/playpaq_wm8510.c
rename to sound/soc/atmel/playpaq_wm8510.c
index b1966e4..d40b5a5 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/clk.h>
@@ -40,8 +39,8 @@
 #include <mach/portmux.h>
 
 #include "../codecs/wm8510.h"
-#include "at32-pcm.h"
-#include "at32-ssc.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
 
 
 /*-------------------------------------------------------------------------*\
@@ -362,7 +361,7 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = {
 
 
 
-static struct snd_soc_machine snd_soc_machine_playpaq = {
+static struct snd_soc_card snd_soc_playpaq = {
        .name = "LRS_PlayPaq_WM8510",
        .dai_link = &playpaq_wm8510_dai,
        .num_links = 1,
@@ -378,7 +377,7 @@ static struct wm8510_setup_data playpaq_wm8510_setup = {
 
 
 static struct snd_soc_device playpaq_wm8510_snd_devdata = {
-       .machine = &snd_soc_machine_playpaq,
+       .card = &snd_soc_playpaq,
        .platform = &at32_soc_platform,
        .codec_dev = &soc_codec_dev_wm8510,
        .codec_data = &playpaq_wm8510_setup,
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
new file mode 100644 (file)
index 0000000..fdc1d02
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * sam9g20_wm8731  --  SoC audio for AT91SAM9G20-based
+ *                     ATMEL AT91SAM9G20ek board.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *
+ * Based on ati_b1_wm8731.c by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ * Based on corgi.c by:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <linux/atmel-ssc.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+
+#include "../codecs/wm8731.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+
+static int at91sam9g20ek_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       int ret;
+
+       /* codec system clock is supplied by PCK0, set to 12MHz */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+               12000000, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+       dev_dbg(rtd->socdev->dev, "shutdown");
+}
+
+static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct atmel_ssc_info *ssc_p = cpu_dai->private_data;
+       struct ssc_device *ssc = ssc_p->ssc;
+       int ret;
+
+       unsigned int rate;
+       int cmr_div, period;
+
+       if (ssc == NULL) {
+               printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n");
+               return -EINVAL;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The SSC clock dividers depend on the sample rate.  The CMR.DIV
+        * field divides the system master clock MCK to drive the SSC TK
+        * signal which provides the codec BCLK.  The TCMR.PERIOD and
+        * RCMR.PERIOD fields further divide the BCLK signal to drive
+        * the SSC TF and RF signals which provide the codec DACLRC and
+        * ADCLRC clocks.
+        *
+        * The dividers were determined through trial and error, where a
+        * CMR.DIV value is chosen such that the resulting BCLK value is
+        * divisible, or almost divisible, by (2 * sample rate), and then
+        * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
+        */
+       rate = params_rate(params);
+
+       switch (rate) {
+       case 8000:
+               cmr_div = 55;   /* BCLK = 133MHz/(2*55) = 1.209MHz */
+               period = 74;    /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */
+               break;
+       case 11025:
+               cmr_div = 67;   /* BCLK = 133MHz/(2*60) = 1.108MHz */
+               period = 45;    /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */
+               break;
+       case 16000:
+               cmr_div = 63;   /* BCLK = 133MHz/(2*63) = 1.055MHz */
+               period = 32;    /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */
+               break;
+       case 22050:
+               cmr_div = 52;   /* BCLK = 133MHz/(2*52) = 1.278MHz */
+               period = 28;    /* LRC = BCLK/(2*(28+1)) = 22049Hz */
+               break;
+       case 32000:
+               cmr_div = 66;   /* BCLK = 133MHz/(2*66) = 1.007MHz */
+               period = 15;    /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */
+               break;
+       case 44100:
+               cmr_div = 29;   /* BCLK = 133MHz/(2*29) = 2.293MHz */
+               period = 25;    /* LRC = BCLK/(2*(25+1)) = 44098Hz */
+               break;
+       case 48000:
+               cmr_div = 33;   /* BCLK = 133MHz/(2*33) = 2.015MHz */
+               period = 20;    /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */
+               break;
+       case 88200:
+               cmr_div = 29;   /* BCLK = 133MHz/(2*29) = 2.293MHz */
+               period = 12;    /* LRC = BCLK/(2*(12+1)) = 88196Hz */
+               break;
+       case 96000:
+               cmr_div = 23;   /* BCLK = 133MHz/(2*23) = 2.891MHz */
+               period = 14;    /* LRC = BCLK/(2*(14+1)) = 96376Hz */
+               break;
+       default:
+               printk(KERN_WARNING "unsupported rate %d"
+                               " on at91sam9g20ek board\n", rate);
+               return -EINVAL;
+       }
+
+       /* set the MCK divider for BCLK */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div);
+       if (ret < 0)
+               return ret;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* set the BCLK divider for DACLRC */
+               ret = snd_soc_dai_set_clkdiv(cpu_dai,
+                                               ATMEL_SSC_TCMR_PERIOD, period);
+       } else {
+               /* set the BCLK divider for ADCLRC */
+               ret = snd_soc_dai_set_clkdiv(cpu_dai,
+                                               ATMEL_SSC_RCMR_PERIOD, period);
+       }
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops at91sam9g20ek_ops = {
+       .startup = at91sam9g20ek_startup,
+       .hw_params = at91sam9g20ek_hw_params,
+       .shutdown = at91sam9g20ek_shutdown,
+};
+
+
+static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+
+       /* speaker connected to LHPOUT */
+       {"Ext Spk", NULL, "LHPOUT"},
+
+       /* mic is connected to Mic Jack, with WM8731 Mic Bias */
+       {"MICIN", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Int Mic"},
+};
+
+/*
+ * Logic for a wm8731 as connected on a at91sam9g20ek board.
+ */
+static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
+{
+       printk(KERN_DEBUG
+                       "at91sam9g20ek_wm8731 "
+                       ": at91sam9g20ek_wm8731_init() called\n");
+
+       /* Add specific widgets */
+       snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets,
+                                 ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
+       /* Set up specific audio path interconnects */
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+       /* not connected */
+       snd_soc_dapm_disable_pin(codec, "RLINEIN");
+       snd_soc_dapm_disable_pin(codec, "LLINEIN");
+
+       /* always connected */
+       snd_soc_dapm_enable_pin(codec, "Int Mic");
+       snd_soc_dapm_enable_pin(codec, "Ext Spk");
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link at91sam9g20ek_dai = {
+       .name = "WM8731",
+       .stream_name = "WM8731 PCM",
+       .cpu_dai = &atmel_ssc_dai[0],
+       .codec_dai = &wm8731_dai,
+       .init = at91sam9g20ek_wm8731_init,
+       .ops = &at91sam9g20ek_ops,
+};
+
+static struct snd_soc_card snd_soc_at91sam9g20ek = {
+       .name = "WM8731",
+       .dai_link = &at91sam9g20ek_dai,
+       .num_links = 1,
+};
+
+static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = {
+       .i2c_bus = 0,
+       .i2c_address = 0x1b,
+};
+
+static struct snd_soc_device at91sam9g20ek_snd_devdata = {
+       .card = &snd_soc_at91sam9g20ek,
+       .platform = &atmel_soc_platform,
+       .codec_dev = &soc_codec_dev_wm8731,
+       .codec_data = &at91sam9g20ek_wm8731_setup,
+};
+
+static struct platform_device *at91sam9g20ek_snd_device;
+
+static int __init at91sam9g20ek_init(void)
+{
+       struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
+       struct ssc_device *ssc = NULL;
+       int ret;
+
+       /*
+        * Request SSC device
+        */
+       ssc = ssc_request(0);
+       if (IS_ERR(ssc)) {
+               ret = PTR_ERR(ssc);
+               ssc = NULL;
+               goto err_ssc;
+       }
+       ssc_p->ssc = ssc;
+
+       at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!at91sam9g20ek_snd_device) {
+               printk(KERN_DEBUG
+                               "platform device allocation failed\n");
+               ret = -ENOMEM;
+       }
+
+       platform_set_drvdata(at91sam9g20ek_snd_device,
+                       &at91sam9g20ek_snd_devdata);
+       at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
+
+       ret = platform_device_add(at91sam9g20ek_snd_device);
+       if (ret) {
+               printk(KERN_DEBUG
+                               "platform device allocation failed\n");
+               platform_device_put(at91sam9g20ek_snd_device);
+       }
+
+       return ret;
+
+err_ssc:
+       return ret;
+}
+
+static void __exit at91sam9g20ek_exit(void)
+{
+       struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
+       struct ssc_device *ssc;
+
+       if (ssc_p != NULL) {
+               ssc = ssc_p->ssc;
+               if (ssc != NULL)
+                       ssc_free(ssc);
+               ssc_p->ssc = NULL;
+       }
+
+       platform_device_unregister(at91sam9g20ek_snd_device);
+       at91sam9g20ek_snd_device = NULL;
+}
+
+module_init(at91sam9g20ek_init);
+module_exit(at91sam9g20ek_exit);
+
+/* Module information */
+MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
+MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731");
+MODULE_LICENSE("GPL");
index 57facba..a0bcfea 100644 (file)
@@ -160,7 +160,8 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *params)
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
 {
        /* FIXME */
        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
@@ -210,7 +211,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
 }
 
 static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
-                               int cmd)
+                               int cmd, struct snd_soc_dai *dai)
 {
        /* FIXME */
        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
@@ -345,7 +346,7 @@ static int au1xpsc_ac97_resume(struct platform_device *pdev,
 
 struct snd_soc_dai au1xpsc_ac97_dai = {
        .name                   = "au1xpsc_ac97",
-       .type                   = SND_SOC_DAI_AC97,
+       .ac97_control           = 1,
        .probe                  = au1xpsc_ac97_probe,
        .remove                 = au1xpsc_ac97_remove,
        .suspend                = au1xpsc_ac97_suspend,
index 9384702..f4217e7 100644 (file)
@@ -116,7 +116,8 @@ out:
 }
 
 static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params)
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
 {
        struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
 
@@ -240,7 +241,8 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
        return 0;
 }
 
-static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
 {
        struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
        int ret, stype = SUBSTREAM_TYPE(substream);
@@ -369,7 +371,6 @@ static int au1xpsc_i2s_resume(struct platform_device *pdev,
 
 struct snd_soc_dai au1xpsc_i2s_dai = {
        .name                   = "au1xpsc_i2s",
-       .type                   = SND_SOC_DAI_I2S,
        .probe                  = au1xpsc_i2s_probe,
        .remove                 = au1xpsc_i2s_remove,
        .suspend                = au1xpsc_i2s_suspend,
@@ -389,8 +390,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
        .ops = {
                .trigger        = au1xpsc_i2s_trigger,
                .hw_params      = au1xpsc_i2s_hw_params,
-       },
-       .dai_ops = {
                .set_fmt        = au1xpsc_i2s_set_fmt,
        },
 };
index f75ae7f..27683eb 100644 (file)
@@ -42,14 +42,14 @@ static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = {
        .ops            = NULL,
 };
 
-static struct snd_soc_machine au1xpsc_sample_ac97_machine = {
+static struct snd_soc_card au1xpsc_sample_ac97_machine = {
        .name           = "Au1xxx PSC AC97 Audio",
        .dai_link       = &au1xpsc_sample_ac97_dai,
        .num_links      = 1,
 };
 
 static struct snd_soc_device au1xpsc_sample_ac97_devdata = {
-       .machine        = &au1xpsc_sample_ac97_machine,
+       .card           = &au1xpsc_sample_ac97_machine,
        .platform       = &au1xpsc_soc_platform, /* see dbdma2.c */
        .codec_dev      = &soc_codec_dev_ac97,
 };
index dc00620..e162cbb 100644 (file)
@@ -13,7 +13,6 @@ config SND_BF5XX_SOC_SSM2602
        select SND_BF5XX_SOC_I2S
        select SND_SOC_SSM2602
        select I2C
-       select I2C_BLACKFIN_TWI
        help
          Say Y if you want to add support for SoC audio on BF527-EZKIT.
 
@@ -47,7 +46,7 @@ config SND_BF5XX_AC97
          properly with this driver. This driver is known to work with the
          Analog Devices line of AC97 codecs.
 
-config SND_MMAP_SUPPORT
+config SND_BF5XX_MMAP_SUPPORT
        bool "Enable MMAP Support"
        depends on SND_BF5XX_AC97
        default y
@@ -55,9 +54,17 @@ config SND_MMAP_SUPPORT
          Say y if you want AC97 driver to support mmap mode.
          We introduce an intermediate buffer to simulate mmap.
 
+config SND_BF5XX_MULTICHAN_SUPPORT
+       bool "Enable Multichannel Support"
+       depends on SND_BF5XX_AC97
+       default n
+       help
+         Say y if you want AC97 driver to support up to 5.1 channel audio.
+         this mode will consume much more memory for DMA.
+
 config SND_BF5XX_SOC_SPORT
        tristate
-       
+
 config SND_BF5XX_SOC_I2S
        tristate
        select SND_BF5XX_SOC_SPORT
@@ -80,7 +87,7 @@ config SND_BF5XX_SPORT_NUM
        int "Set a SPORT for Sound chip"
        depends on (SND_BF5XX_I2S || SND_BF5XX_AC97)
        range 0 3 if BF54x
-       range 0 1 if (BF53x || BF561)
+       range 0 1 if !BF54x
        default 0
        help
          Set the correct SPORT for sound chip.
@@ -90,12 +97,13 @@ config SND_BF5XX_HAVE_COLD_RESET
        depends on SND_BF5XX_AC97
        default y if BFIN548_EZKIT
        default n if !BFIN548_EZKIT
-       
+
 config SND_BF5XX_RESET_GPIO_NUM
        int "Set a GPIO for cold reset"
        depends on SND_BF5XX_HAVE_COLD_RESET
        range 0 159
        default 19 if BFIN548_EZKIT
        default 5 if BFIN537_STAMP
+       default 0
        help
          Set the correct GPIO for RESET the sound chip.
index 25e50d2..d3d51bc 100644 (file)
 #include "bf5xx-ac97.h"
 #include "bf5xx-sport.h"
 
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+static unsigned int ac97_chan_mask[] = {
+       SP_FL, /* Mono */
+       SP_STEREO, /* Stereo */
+       SP_2DOT1, /* 2.1*/
+       SP_QUAD,/*Quadraquic*/
+       SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */
+       SP_5DOT1, /* 5.1 */
+};
+
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
         snd_pcm_uframes_t count)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct sport_device *sport = runtime->private_data;
+       unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               bf5xx_pcm_to_ac97(
-                       (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos,
-                       (__u32 *)runtime->dma_area + sport->tx_pos, count);
+               bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf +
+               sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos *
+               runtime->channels, count, chan_mask);
                sport->tx_pos += runtime->period_size;
                if (sport->tx_pos >= runtime->buffer_size)
                        sport->tx_pos %= runtime->buffer_size;
                sport->tx_delay_pos = sport->tx_pos;
        } else {
-               bf5xx_ac97_to_pcm(
-                       (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
-                       (__u32 *)runtime->dma_area + sport->rx_pos, count);
+               bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf +
+               sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos *
+               runtime->channels, count);
                sport->rx_pos += runtime->period_size;
                if (sport->rx_pos >= runtime->buffer_size)
                        sport->rx_pos %= runtime->buffer_size;
@@ -71,7 +81,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
 static void bf5xx_dma_irq(void *data)
 {
        struct snd_pcm_substream *pcm = data;
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        struct snd_pcm_runtime *runtime = pcm->runtime;
        struct sport_device *sport = runtime->private_data;
        bf5xx_mmap_copy(pcm, runtime->period_size);
@@ -90,17 +100,14 @@ static void bf5xx_dma_irq(void *data)
  * The total rx/tx buffer is for ac97 frame to hold all pcm data
  * is  0x20000 * sizeof(struct ac97_frame) / 4.
  */
-#ifdef CONFIG_SND_MMAP_SUPPORT
 static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
                                   SNDRV_PCM_INFO_MMAP |
                                   SNDRV_PCM_INFO_MMAP_VALID |
-                                  SNDRV_PCM_INFO_BLOCK_TRANSFER,
-#else
-static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
-                                 SNDRV_PCM_INFO_BLOCK_TRANSFER,
 #endif
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+
        .formats                = SNDRV_PCM_FMTBIT_S16_LE,
        .period_bytes_min       = 32,
        .period_bytes_max       = 0x10000,
@@ -123,10 +130,20 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-       memset(runtime->dma_area, 0, runtime->buffer_size);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               sport->once = 0;
+               if (runtime->dma_area)
+                       memset(runtime->dma_area, 0, runtime->buffer_size);
+               memset(sport->tx_dma_buf, 0, runtime->buffer_size *
+                       sizeof(struct ac97_frame));
+       } else
+               memset(sport->rx_dma_buf, 0, runtime->buffer_size *
+                       sizeof(struct ac97_frame));
+#endif
        snd_pcm_lib_free_pages(substream);
        return 0;
 }
@@ -139,7 +156,7 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
        /* An intermediate buffer is introduced for implementing mmap for
         * SPORT working in TMD mode(include AC97).
         */
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
                sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
@@ -173,24 +190,24 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
                        bf5xx_mmap_copy(substream, runtime->period_size);
-                       snd_pcm_period_elapsed(substream);
                        sport->tx_delay_pos = 0;
+#endif
                        sport_tx_start(sport);
-               }
-               else
+               } else
                        sport_rx_start(sport);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
                        sport->tx_pos = 0;
 #endif
                        sport_tx_stop(sport);
                } else {
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
                        sport->rx_pos = 0;
 #endif
                        sport_rx_stop(sport);
@@ -208,7 +225,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
        struct sport_device *sport = runtime->private_data;
        unsigned int curr;
 
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                curr = sport->tx_delay_pos;
        else
@@ -249,22 +266,7 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        return ret;
 }
 
-static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-
-       pr_debug("%s enter\n", __func__);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               sport->once = 0;
-               memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
-       } else
-               memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
-
-       return 0;
-}
-
-#ifdef CONFIG_SND_MMAP_SUPPORT
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
        struct vm_area_struct *vma)
 {
@@ -281,32 +283,29 @@ static    int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
                    void __user *buf, snd_pcm_uframes_t count)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-
+       unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
        pr_debug("%s copy pos:0x%lx count:0x%lx\n",
                        substream->stream ? "Capture" : "Playback", pos, count);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               bf5xx_pcm_to_ac97(
-                               (struct ac97_frame *)runtime->dma_area + pos,
-                               buf, count);
+               bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos,
+                       (__u16 *)buf, count, chan_mask);
        else
-               bf5xx_ac97_to_pcm(
-                               (struct ac97_frame *)runtime->dma_area + pos,
-                               buf, count);
+               bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos,
+                       (__u16 *)buf, count);
        return 0;
 }
 #endif
 
 struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
        .open           = bf5xx_pcm_open,
-       .close          = bf5xx_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = bf5xx_pcm_hw_params,
        .hw_free        = bf5xx_pcm_hw_free,
        .prepare        = bf5xx_pcm_prepare,
        .trigger        = bf5xx_pcm_trigger,
        .pointer        = bf5xx_pcm_pointer,
-#ifdef CONFIG_SND_MMAP_SUPPORT
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        .mmap           = bf5xx_pcm_mmap,
 #else
        .copy           = bf5xx_pcm_copy,
@@ -344,7 +343,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  * Need to allocate local buffer when enable
  * MMAP for SPORT working in TMD mode (include AC97).
  */
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (!sport_handle->tx_dma_buf) {
                        sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
@@ -381,7 +380,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
        struct snd_pcm_substream *substream;
        struct snd_dma_buffer *buf;
        int stream;
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
                sizeof(struct ac97_frame) / 4;
 #endif
@@ -395,7 +394,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
                        continue;
                dma_free_coherent(NULL, buf->bytes, buf->area, 0);
                buf->area = NULL;
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (sport_handle->tx_dma_buf)
                        dma_free_coherent(NULL, size, \
index 5e5aafb..709bdf0 100644 (file)
 static int *cmd_count;
 static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
 
-#if defined(CONFIG_BF54x)
+static u16 sport_req[][7] = {
+               PIN_REQ_SPORT_0,
+#ifdef PIN_REQ_SPORT_1
+               PIN_REQ_SPORT_1,
+#endif
+#ifdef PIN_REQ_SPORT_2
+               PIN_REQ_SPORT_2,
+#endif
+#ifdef PIN_REQ_SPORT_3
+               PIN_REQ_SPORT_3,
+#endif
+       };
+
 static struct sport_param sport_params[4] = {
        {
                .dma_rx_chan    = CH_SPORT0_RX,
                .dma_tx_chan    = CH_SPORT0_TX,
-               .err_irq        = IRQ_SPORT0_ERR,
+               .err_irq        = IRQ_SPORT0_ERROR,
                .regs           = (struct sport_register *)SPORT0_TCR1,
        },
+#ifdef PIN_REQ_SPORT_1
        {
                .dma_rx_chan    = CH_SPORT1_RX,
                .dma_tx_chan    = CH_SPORT1_TX,
-               .err_irq        = IRQ_SPORT1_ERR,
+               .err_irq        = IRQ_SPORT1_ERROR,
                .regs           = (struct sport_register *)SPORT1_TCR1,
        },
+#endif
+#ifdef PIN_REQ_SPORT_2
        {
                .dma_rx_chan    = CH_SPORT2_RX,
                .dma_tx_chan    = CH_SPORT2_TX,
-               .err_irq        = IRQ_SPORT2_ERR,
+               .err_irq        = IRQ_SPORT2_ERROR,
                .regs           = (struct sport_register *)SPORT2_TCR1,
        },
+#endif
+#ifdef PIN_REQ_SPORT_3
        {
                .dma_rx_chan    = CH_SPORT3_RX,
                .dma_tx_chan    = CH_SPORT3_TX,
-               .err_irq        = IRQ_SPORT3_ERR,
+               .err_irq        = IRQ_SPORT3_ERROR,
                .regs           = (struct sport_register *)SPORT3_TCR1,
        }
-};
-#else
-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,
-       }
-};
 #endif
+};
 
-void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
-               size_t count)
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
+               size_t count, unsigned int chan_mask)
 {
        while (count--) {
-               dst->ac97_tag = TAG_VALID | TAG_PCM;
-               (dst++)->ac97_pcm = *src++;
+               dst->ac97_tag = TAG_VALID;
+               if (chan_mask & SP_FL) {
+                       dst->ac97_pcm_r = *src++;
+                       dst->ac97_tag |= TAG_PCM_RIGHT;
+               }
+               if (chan_mask & SP_FR) {
+                       dst->ac97_pcm_l = *src++;
+                       dst->ac97_tag |= TAG_PCM_LEFT;
+
+               }
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+               if (chan_mask & SP_SR) {
+                       dst->ac97_sl = *src++;
+                       dst->ac97_tag |= TAG_PCM_SL;
+               }
+               if (chan_mask & SP_SL) {
+                       dst->ac97_sr = *src++;
+                       dst->ac97_tag |= TAG_PCM_SR;
+               }
+               if (chan_mask & SP_LFE) {
+                       dst->ac97_lfe = *src++;
+                       dst->ac97_tag |= TAG_PCM_LFE;
+               }
+               if (chan_mask & SP_FC) {
+                       dst->ac97_center = *src++;
+                       dst->ac97_tag |= TAG_PCM_CENTER;
+               }
+#endif
+               dst++;
        }
 }
 EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
 
-void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst,
                size_t count)
 {
-       while (count--)
-               *(dst++) = (src++)->ac97_pcm;
+       while (count--) {
+               *(dst++) = src->ac97_pcm_l;
+               *(dst++) = src->ac97_pcm_r;
+               src++;
+       }
 }
 EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
 
 static unsigned int sport_tx_curr_frag(struct sport_device *sport)
 {
-       return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \
+       return sport->tx_curr_frag = sport_curr_offset_tx(sport) /
                        sport->tx_fragsize;
 }
 
@@ -130,7 +162,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 
        sport_incfrag(sport, &nextfrag, 1);
 
-       nextwrite = (struct ac97_frame *)(sport->tx_buf + \
+       nextwrite = (struct ac97_frame *)(sport->tx_buf +
                        nextfrag * sport->tx_fragsize);
        pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
                sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
@@ -297,20 +329,15 @@ static int bf5xx_ac97_resume(struct platform_device *pdev,
 static int bf5xx_ac97_probe(struct platform_device *pdev,
                            struct snd_soc_dai *dai)
 {
-       int ret;
-#if defined(CONFIG_BF54x)
-       u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1,
-                                PIN_REQ_SPORT_2, PIN_REQ_SPORT_3};
-#else
-       u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1};
-#endif
+       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][0], "soc-audio")) {
                pr_err("Requesting Peripherals failed\n");
-               return -EFAULT;
+               ret =  -EFAULT;
+               goto peripheral_err;
                }
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
@@ -318,54 +345,54 @@ static int bf5xx_ac97_probe(struct platform_device *pdev,
        if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
                pr_err("Failed to request GPIO_%d for reset\n",
                                CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-               peripheral_free_list(&sport_req[sport_num][0]);
-               return -1;
+               ret =  -1;
+               goto gpio_err;
        }
        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);
        if (!sport_handle) {
-               peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-               return -ENODEV;
+               ret = -ENODEV;
+               goto sport_err;
        }
        /*SPORT works in TDM mode to simulate AC97 transfers*/
        ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
        if (ret) {
                pr_err("SPORT is busy!\n");
-               kfree(sport_handle);
-               peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-               return -EBUSY;
+               ret = -EBUSY;
+               goto sport_config_err;
        }
 
        ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
        if (ret) {
                pr_err("SPORT is busy!\n");
-               kfree(sport_handle);
-               peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-               return -EBUSY;
+               ret = -EBUSY;
+               goto sport_config_err;
        }
 
        ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
        if (ret) {
                pr_err("SPORT is busy!\n");
-               kfree(sport_handle);
-               peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-               gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-               return -EBUSY;
+               ret = -EBUSY;
+               goto sport_config_err;
        }
+
        return 0;
+
+sport_config_err:
+       kfree(sport_handle);
+sport_err:
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+       gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+gpio_err:
+       peripheral_free_list(&sport_req[sport_num][0]);
+peripheral_err:
+       free_page((unsigned long)cmd_count);
+       cmd_count = NULL;
+
+       return ret;
 }
 
 static void bf5xx_ac97_remove(struct platform_device *pdev,
@@ -373,6 +400,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
 {
        free_page((unsigned long)cmd_count);
        cmd_count = NULL;
+       peripheral_free_list(&sport_req[sport_num][0]);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
@@ -381,7 +409,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
 struct snd_soc_dai bfin_ac97_dai = {
        .name = "bf5xx-ac97",
        .id = 0,
-       .type = SND_SOC_DAI_AC97,
+       .ac97_control = 1,
        .probe = bf5xx_ac97_probe,
        .remove = bf5xx_ac97_remove,
        .suspend = bf5xx_ac97_suspend,
@@ -389,7 +417,11 @@ struct snd_soc_dai bfin_ac97_dai = {
        .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 = {
index 3f77cc5..3f2a911 100644 (file)
@@ -16,21 +16,46 @@ struct ac97_frame {
        u16 ac97_tag;           /* slot 0 */
        u16 ac97_addr;          /* slot 1 */
        u16 ac97_data;          /* slot 2 */
-       u32 ac97_pcm;           /* slot 3 and 4: left and right pcm data */
+       u16 ac97_pcm_l;         /*slot 3:front left*/
+       u16 ac97_pcm_r;         /*slot 4:front left*/
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+       u16 ac97_mdm_l1;
+       u16 ac97_center;        /*slot 6:center*/
+       u16 ac97_sl;            /*slot 7:surround left*/
+       u16 ac97_sr;            /*slot 8:surround right*/
+       u16 ac97_lfe;           /*slot 9:lfe*/
+#endif
 } __attribute__ ((packed));
 
+/* Speaker location */
+#define SP_FL          0x0001
+#define SP_FR          0x0010
+#define SP_FC          0x0002
+#define SP_LFE         0x0020
+#define SP_SL          0x0004
+#define SP_SR          0x0040
+
+#define SP_STEREO      (SP_FL | SP_FR)
+#define SP_2DOT1       (SP_FL | SP_FR | SP_LFE)
+#define SP_QUAD                (SP_FL | SP_FR | SP_SL | SP_SR)
+#define SP_5DOT1       (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR)
+
 #define TAG_VALID              0x8000
 #define TAG_CMD                        0x6000
 #define TAG_PCM_LEFT           0x1000
 #define TAG_PCM_RIGHT          0x0800
-#define TAG_PCM                        (TAG_PCM_LEFT | TAG_PCM_RIGHT)
+#define TAG_PCM_MDM_L1         0x0400
+#define TAG_PCM_CENTER         0x0200
+#define TAG_PCM_SL             0x0100
+#define TAG_PCM_SR             0x0080
+#define TAG_PCM_LFE            0x0040
 
 extern struct snd_soc_dai bfin_ac97_dai;
 
-void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
-               size_t count);
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
+               size_t count, unsigned int chan_mask);
 
-void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \
                size_t count);
 
 #endif
index 124425d..36c569a 100644 (file)
@@ -43,7 +43,7 @@
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 
-static struct snd_soc_machine bf5xx_board;
+static struct snd_soc_card bf5xx_board;
 
 static int bf5xx_board_startup(struct snd_pcm_substream *substream)
 {
@@ -67,14 +67,14 @@ static struct snd_soc_dai_link bf5xx_board_dai = {
        .ops = &bf5xx_board_ops,
 };
 
-static struct snd_soc_machine bf5xx_board = {
+static struct snd_soc_card bf5xx_board = {
        .name = "bf5xx-board",
        .dai_link = &bf5xx_board_dai,
        .num_links = 1,
 };
 
 static struct snd_soc_device bf5xx_board_snd_devdata = {
-       .machine = &bf5xx_board,
+       .card = &bf5xx_board,
        .platform = &bf5xx_ac97_soc_platform,
        .codec_dev = &soc_codec_dev_ad1980,
 };
index 622c9b9..57da147 100644 (file)
@@ -65,7 +65,7 @@
 
 #define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
 
-static struct snd_soc_machine bf5xx_ad73311;
+static struct snd_soc_card bf5xx_ad73311;
 
 static int snd_ad73311_startup(void)
 {
@@ -168,7 +168,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
                params_format(params));
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
@@ -190,7 +190,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai = {
        .ops = &bf5xx_ad73311_ops,
 };
 
-static struct snd_soc_machine bf5xx_ad73311 = {
+static struct snd_soc_card bf5xx_ad73311 = {
        .name = "bf5xx_ad73311",
        .probe = bf5xx_probe,
        .dai_link = &bf5xx_ad73311_dai,
@@ -198,7 +198,7 @@ static struct snd_soc_machine bf5xx_ad73311 = {
 };
 
 static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
-       .machine = &bf5xx_ad73311,
+       .card = &bf5xx_ad73311,
        .platform = &bf5xx_i2s_soc_platform,
        .codec_dev = &soc_codec_dev_ad73311,
 };
index e020c16..6e5036b 100644 (file)
@@ -132,7 +132,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        return ret;
 }
 
-static int bf5xx_i2s_startup(struct snd_pcm_substream *substream)
+static int bf5xx_i2s_startup(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
 {
        pr_debug("%s enter\n", __func__);
 
@@ -142,7 +143,8 @@ static int bf5xx_i2s_startup(struct snd_pcm_substream *substream)
 }
 
 static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
 {
        int ret = 0;
 
@@ -193,7 +195,8 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
+static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
 {
        pr_debug("%s enter\n", __func__);
        bf5xx_i2s.counter--;
@@ -289,7 +292,6 @@ static int bf5xx_i2s_resume(struct platform_device *pdev,
 struct snd_soc_dai bf5xx_i2s_dai = {
        .name = "bf5xx-i2s",
        .id = 0,
-       .type = SND_SOC_DAI_I2S,
        .probe = bf5xx_i2s_probe,
        .remove = bf5xx_i2s_remove,
        .suspend = bf5xx_i2s_suspend,
@@ -307,8 +309,7 @@ struct snd_soc_dai bf5xx_i2s_dai = {
        .ops = {
                .startup   = bf5xx_i2s_startup,
                .shutdown  = bf5xx_i2s_shutdown,
-               .hw_params = bf5xx_i2s_hw_params,},
-       .dai_ops = {
+               .hw_params = bf5xx_i2s_hw_params,
                .set_fmt = bf5xx_i2s_set_dai_fmt,
        },
 };
index fcadcc0..2e63dea 100644 (file)
@@ -116,7 +116,7 @@ struct sport_device {
        void *err_data;
        unsigned char *tx_dma_buf;
        unsigned char *rx_dma_buf;
-#ifdef CONFIG_SND_MMAP_SUPPORT
+#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT
        dma_addr_t tx_dma_phy;
        dma_addr_t rx_dma_phy;
        int tx_pos;/*pcm sample count*/
index e15f67f..0078dfc 100644 (file)
@@ -44,7 +44,7 @@
 #include "bf5xx-i2s-pcm.h"
 #include "bf5xx-i2s.h"
 
-static struct snd_soc_machine bf5xx_ssm2602;
+static struct snd_soc_card bf5xx_ssm2602;
 
 static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
 {
@@ -92,17 +92,17 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
         */
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
 
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -135,14 +135,14 @@ static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
        .i2c_address = 0x1b,
 };
 
-static struct snd_soc_machine bf5xx_ssm2602 = {
+static struct snd_soc_card bf5xx_ssm2602 = {
        .name = "bf5xx_ssm2602",
        .dai_link = &bf5xx_ssm2602_dai,
        .num_links = 1,
 };
 
 static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
-       .machine = &bf5xx_ssm2602,
+       .card = &bf5xx_ssm2602,
        .platform = &bf5xx_i2s_soc_platform,
        .codec_dev = &soc_codec_dev_ssm2602,
        .codec_data = &bf5xx_ssm2602_setup,
index 38a0e3b..bf68052 100644 (file)
@@ -1,31 +1,39 @@
 config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
-       depends on I2C
-       select SPI
-       select SPI_MASTER
-       select SND_SOC_AD73311
-       select SND_SOC_AK4535
-       select SND_SOC_CS4270
-       select SND_SOC_SSM2602
-       select SND_SOC_TLV320AIC23
-       select SND_SOC_TLV320AIC26
-       select SND_SOC_TLV320AIC3X
-       select SND_SOC_UDA1380
-       select SND_SOC_WM8510
-       select SND_SOC_WM8580
-       select SND_SOC_WM8731
-       select SND_SOC_WM8750
-       select SND_SOC_WM8753
-       select SND_SOC_WM8900
-       select SND_SOC_WM8903
-       select SND_SOC_WM8971
-       select SND_SOC_WM8990
+       select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
+       select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+       select SND_SOC_AD73311 if I2C
+       select SND_SOC_AK4535 if I2C
+       select SND_SOC_CS4270 if I2C
+       select SND_SOC_PCM3008
+       select SND_SOC_SSM2602 if I2C
+       select SND_SOC_TLV320AIC23 if I2C
+       select SND_SOC_TLV320AIC26 if SPI_MASTER
+       select SND_SOC_TLV320AIC3X if I2C
+       select SND_SOC_TWL4030 if TWL4030_CORE
+       select SND_SOC_UDA134X
+       select SND_SOC_UDA1380 if I2C
+       select SND_SOC_WM8510 if (I2C || SPI_MASTER)
+       select SND_SOC_WM8580 if I2C
+       select SND_SOC_WM8728 if (I2C || SPI_MASTER)
+       select SND_SOC_WM8731 if (I2C || SPI_MASTER)
+       select SND_SOC_WM8750 if (I2C || SPI_MASTER)
+       select SND_SOC_WM8753 if (I2C || SPI_MASTER)
+       select SND_SOC_WM8900 if I2C
+       select SND_SOC_WM8903 if I2C
+       select SND_SOC_WM8971 if I2C
+       select SND_SOC_WM8990 if I2C
+       select SND_SOC_WM9712 if SND_SOC_AC97_BUS
+       select SND_SOC_WM9713 if SND_SOC_AC97_BUS
         help
           Normally ASoC codec drivers are only built if a machine driver which
           uses them is also built since they are only usable with a machine
           driver.  Selecting this option will allow these drivers to be built
           without an explicit machine driver for test and development purposes.
 
+         Support for the bus types used to access the codecs to be built must
+         be selected separately.
+
           If unsure select "N".
 
 
@@ -60,6 +68,12 @@ config SND_SOC_CS4270_VD33_ERRATA
        bool
        depends on SND_SOC_CS4270
 
+config SND_SOC_L3
+       tristate
+
+config SND_SOC_PCM3008
+       tristate
+
 config SND_SOC_SSM2602
        tristate
 
@@ -75,6 +89,14 @@ config SND_SOC_TLV320AIC3X
        tristate
        depends on I2C
 
+config SND_SOC_TWL4030
+       tristate
+       depends on TWL4030_CORE
+
+config SND_SOC_UDA134X
+       tristate
+       select SND_SOC_L3
+
 config SND_SOC_UDA1380
         tristate
 
@@ -84,6 +106,9 @@ config SND_SOC_WM8510
 config SND_SOC_WM8580
        tristate
 
+config SND_SOC_WM8728
+       tristate
+
 config SND_SOC_WM8731
        tristate
 
index 90f0a58..9a20fdd 100644 (file)
@@ -3,13 +3,18 @@ snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-cs4270-objs := cs4270.o
+snd-soc-l3-objs := l3.o
+snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-twl4030-objs := twl4030.o
+snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8580-objs := wm8580.o
+snd-soc-wm8728-objs := wm8728.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
@@ -25,13 +30,18 @@ obj-$(CONFIG_SND_SOC_AD1980)        += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
+obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
+obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8580)   += snd-soc-wm8580.o
+obj-$(CONFIG_SND_SOC_WM8728)   += snd-soc-wm8728.o
 obj-$(CONFIG_SND_SOC_WM8731)   += snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8750)   += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
index bd1ebdc..c4208c8 100644 (file)
@@ -24,7 +24,8 @@
 
 #define AC97_VERSION "0.6"
 
-static int ac97_prepare(struct snd_pcm_substream *substream)
+static int ac97_prepare(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -42,7 +43,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream)
 
 struct snd_soc_dai ac97_dai = {
        .name = "AC97 HiFi",
-       .type = SND_SOC_DAI_AC97,
+       .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Playback",
                .channels_min = 1,
index 1397b8e..a9a2681 100644 (file)
@@ -85,6 +85,9 @@ SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0),
 SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
 SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
 
+SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1),
+
 SOC_ENUM("Capture Source", ad1980_cap_src),
 
 SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
@@ -142,10 +145,11 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 
 struct snd_soc_dai ad1980_dai = {
        .name = "AC97",
+       .ac97_control = 1,
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
-               .channels_max = 2,
+               .channels_max = 6,
                .rates = SNDRV_PCM_RATE_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE, },
        .capture = {
@@ -192,6 +196,7 @@ static int ad1980_soc_probe(struct platform_device *pdev)
        struct snd_soc_codec *codec;
        int ret = 0;
        u16 vendor_id2;
+       u16 ext_status;
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
@@ -234,7 +239,7 @@ static int ad1980_soc_probe(struct platform_device *pdev)
 
        ret = ad1980_reset(codec, 0);
        if (ret < 0) {
-               printk(KERN_ERR "AC97 link error\n");
+               printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
                goto reset_err;
        }
 
@@ -253,9 +258,16 @@ static int ad1980_soc_probe(struct platform_device *pdev)
                                "supported\n");
        }
 
-       ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */
-       ac97_write(codec, AC97_PCM, 0x0000);    /* unmute PCM out volume */
-       ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */
+       /* unmute captures and playbacks volume */
+       ac97_write(codec, AC97_MASTER, 0x0000);
+       ac97_write(codec, AC97_PCM, 0x0000);
+       ac97_write(codec, AC97_REC_GAIN, 0x0000);
+       ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
+       ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);
+
+       /*power on LFE/CENTER/Surround DACs*/
+       ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
+       ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
 
        ad1980_add_controls(codec);
        ret = snd_soc_register_card(socdev);
index 37af860..59c4c8f 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <sound/core.h>
index 2a89b58..c742290 100644 (file)
@@ -339,7 +339,8 @@ static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 }
 
 static int ak4535_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
@@ -451,8 +452,6 @@ struct snd_soc_dai ak4535_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = {
                .hw_params = ak4535_hw_params,
-       },
-       .dai_ops = {
                .set_fmt = ak4535_set_dai_fmt,
                .digital_mute = ak4535_mute,
                .set_sysclk = ak4535_set_dai_sysclk,
index 0bbd945..7507d46 100644 (file)
@@ -360,13 +360,14 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
 /*
  * Program the CS4270 with the given hardware parameters.
  *
- * The .dai_ops functions are used to provide board-specific data, like
+ * The .ops functions are used to provide board-specific data, like
  * input frequencies, to this driver.  This function takes that information,
  * combines it with the hardware parameters provided, and programs the
  * hardware accordingly.
  */
 static int cs4270_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params)
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
@@ -450,6 +451,19 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
+       /* Disable automatic volume control.  It's enabled by default, and
+        * it causes volume change commands to be delayed, sometimes until
+        * after playback has started.
+        */
+
+       reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
+       reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
+       ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
+       if (ret < 0) {
+               printk(KERN_ERR "I2C write failed\n");
+               return ret;
+       }
+
        /* Thaw and power-up the codec */
 
        ret = snd_soc_write(codec, CS4270_PWRCTL, 0);
@@ -697,10 +711,10 @@ static int cs4270_probe(struct platform_device *pdev)
        if (codec->control_data) {
                /* Initialize codec ops */
                cs4270_dai.ops.hw_params = cs4270_hw_params;
-               cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk;
-               cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt;
+               cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
+               cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
 #ifdef CONFIG_SND_SOC_CS4270_HWMUTE
-               cs4270_dai.dai_ops.digital_mute = cs4270_mute;
+               cs4270_dai.ops.digital_mute = cs4270_mute;
 #endif
        } else
                printk(KERN_INFO "cs4270: no I2C device found, "
diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c
new file mode 100644 (file)
index 0000000..5353af5
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * L3 code
+ *
+ *  Copyright (C) 2008, Christian Pellegrin <chripell@evolware.org>
+ *
+ * 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.
+ *
+ *
+ * based on:
+ *
+ * L3 bus algorithm module.
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <sound/l3.h>
+
+/*
+ * Send one byte of data to the chip.  Data is latched into the chip on
+ * the rising edge of the clock.
+ */
+static void sendbyte(struct l3_pins *adap, unsigned int byte)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               adap->setclk(0);
+               udelay(adap->data_hold);
+               adap->setdat(byte & 1);
+               udelay(adap->data_setup);
+               adap->setclk(1);
+               udelay(adap->clock_high);
+               byte >>= 1;
+       }
+}
+
+/*
+ * Send a set of bytes to the chip.  We need to pulse the MODE line
+ * between each byte, but never at the start nor at the end of the
+ * transfer.
+ */
+static void sendbytes(struct l3_pins *adap, const u8 *buf,
+                     int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               if (i) {
+                       udelay(adap->mode_hold);
+                       adap->setmode(0);
+                       udelay(adap->mode);
+               }
+               adap->setmode(1);
+               udelay(adap->mode_setup);
+               sendbyte(adap, buf[i]);
+       }
+}
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
+{
+       adap->setclk(1);
+       adap->setdat(1);
+       adap->setmode(1);
+       udelay(adap->mode);
+
+       adap->setmode(0);
+       udelay(adap->mode_setup);
+       sendbyte(adap, addr);
+       udelay(adap->mode_hold);
+
+       sendbytes(adap, data, len);
+
+       adap->setclk(1);
+       adap->setdat(1);
+       adap->setmode(0);
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(l3_write);
+
+MODULE_DESCRIPTION("L3 bit-banging driver");
+MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
new file mode 100644 (file)
index 0000000..651a15e
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * ALSA Soc PCM3008 codec support
+ *
+ * Author:     Hugo Villeneuve
+ * Copyright (C) 2008 Lyrtech inc
+ *
+ * Based on AC97 Soc codec, original copyright follow:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ * Generic PCM3008 support.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "pcm3008.h"
+
+#define PCM3008_VERSION "0.2"
+
+#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |   \
+                      SNDRV_PCM_RATE_48000)
+
+struct snd_soc_dai pcm3008_dai = {
+       .name = "PCM3008 HiFi",
+       .playback = {
+               .stream_name = "PCM3008 Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = PCM3008_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "PCM3008 Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = PCM3008_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+};
+EXPORT_SYMBOL_GPL(pcm3008_dai);
+
+static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
+{
+       gpio_free(setup->dem0_pin);
+       gpio_free(setup->dem1_pin);
+       gpio_free(setup->pdad_pin);
+       gpio_free(setup->pdda_pin);
+}
+
+static int pcm3008_soc_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       struct pcm3008_setup_data *setup = socdev->codec_data;
+       int ret = 0;
+
+       printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
+
+       socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (!socdev->codec)
+               return -ENOMEM;
+
+       codec = socdev->codec;
+       mutex_init(&codec->mutex);
+
+       codec->name = "PCM3008";
+       codec->owner = THIS_MODULE;
+       codec->dai = &pcm3008_dai;
+       codec->num_dai = 1;
+       codec->write = NULL;
+       codec->read = NULL;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       /* Register PCMs. */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "pcm3008: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* Register Card. */
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "pcm3008: failed to register card\n");
+               goto card_err;
+       }
+
+       /* DEM1  DEM0  DE-EMPHASIS_MODE
+        * Low   Low   De-emphasis 44.1 kHz ON
+        * Low   High  De-emphasis OFF
+        * High  Low   De-emphasis 48 kHz ON
+        * High  High  De-emphasis 32 kHz ON
+        */
+
+       /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
+       ret = gpio_request(setup->dem0_pin, "codec_dem0");
+       if (ret == 0)
+               ret = gpio_direction_output(setup->dem0_pin, 1);
+       if (ret != 0)
+               goto gpio_err;
+
+       /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
+       ret = gpio_request(setup->dem1_pin, "codec_dem1");
+       if (ret == 0)
+               ret = gpio_direction_output(setup->dem1_pin, 0);
+       if (ret != 0)
+               goto gpio_err;
+
+       /* Configure PDAD GPIO. */
+       ret = gpio_request(setup->pdad_pin, "codec_pdad");
+       if (ret == 0)
+               ret = gpio_direction_output(setup->pdad_pin, 1);
+       if (ret != 0)
+               goto gpio_err;
+
+       /* Configure PDDA GPIO. */
+       ret = gpio_request(setup->pdda_pin, "codec_pdda");
+       if (ret == 0)
+               ret = gpio_direction_output(setup->pdda_pin, 1);
+       if (ret != 0)
+               goto gpio_err;
+
+       return ret;
+
+gpio_err:
+       pcm3008_gpio_free(setup);
+card_err:
+       snd_soc_free_pcms(socdev);
+pcm_err:
+       kfree(socdev->codec);
+
+       return ret;
+}
+
+static int pcm3008_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       struct pcm3008_setup_data *setup = socdev->codec_data;
+
+       if (!codec)
+               return 0;
+
+       pcm3008_gpio_free(setup);
+       snd_soc_free_pcms(socdev);
+       kfree(socdev->codec);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct pcm3008_setup_data *setup = socdev->codec_data;
+
+       gpio_set_value(setup->pdad_pin, 0);
+       gpio_set_value(setup->pdda_pin, 0);
+
+       return 0;
+}
+
+static int pcm3008_soc_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct pcm3008_setup_data *setup = socdev->codec_data;
+
+       gpio_set_value(setup->pdad_pin, 1);
+       gpio_set_value(setup->pdda_pin, 1);
+
+       return 0;
+}
+#else
+#define pcm3008_soc_suspend NULL
+#define pcm3008_soc_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
+       .probe =        pcm3008_soc_probe,
+       .remove =       pcm3008_soc_remove,
+       .suspend =      pcm3008_soc_suspend,
+       .resume =       pcm3008_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
+
+MODULE_DESCRIPTION("Soc PCM3008 driver");
+MODULE_AUTHOR("Hugo Villeneuve");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h
new file mode 100644 (file)
index 0000000..d04e87d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * PCM3008 ALSA SoC Layer
+ *
+ * Author:     Hugo Villeneuve
+ * Copyright (C) 2008 Lyrtech inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_PCM3008_H
+#define __LINUX_SND_SOC_PCM3008_H
+
+struct pcm3008_setup_data {
+       unsigned dem0_pin;
+       unsigned dem1_pin;
+       unsigned pdad_pin;
+       unsigned pdda_pin;
+};
+
+extern struct snd_soc_codec_device soc_codec_dev_pcm3008;
+extern struct snd_soc_dai pcm3008_dai;
+
+#endif
index 44ef0da..0c5884e 100644 (file)
@@ -285,16 +285,23 @@ static inline int get_coeff(int mclk, int rate)
 }
 
 static int ssm2602_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
 {
        u16 srate;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
+       struct i2c_client *i2c = codec->control_data;
        u16 iface = ssm2602_read_reg_cache(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");
+               return 0;
+       }
+
        /*no match is found*/
        if (i == ARRAY_SIZE(coeff_div))
                return -EINVAL;
@@ -324,19 +331,26 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ssm2602_startup(struct snd_pcm_substream *substream)
+static int ssm2602_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
+       struct i2c_client *i2c = codec->control_data;
        struct snd_pcm_runtime *master_runtime;
 
        /* The DAI has shared clocks so if we already have a playback or
         * capture going then constrain this substream to match it.
+        * TODO: the ssm2602 allows pairs of non-matching PB/REC rates
         */
        if (ssm2602->master_substream) {
                master_runtime = ssm2602->master_substream->runtime;
+               dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
+                       master_runtime->sample_bits,
+                       master_runtime->rate);
+
                snd_pcm_hw_constraint_minmax(substream->runtime,
                                             SNDRV_PCM_HW_PARAM_RATE,
                                             master_runtime->rate,
@@ -354,7 +368,8 @@ static int ssm2602_startup(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream)
+static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
@@ -365,14 +380,21 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static void ssm2602_shutdown(struct snd_pcm_substream *substream)
+static void ssm2602_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->codec;
+       struct ssm2602_priv *ssm2602 = codec->private_data;
        /* deactivate */
        if (!codec->active)
                ssm2602_write(codec, SSM2602_ACTIVE, 0);
+
+       if (ssm2602->master_substream == substream)
+               ssm2602->master_substream = ssm2602->slave_substream;
+
+       ssm2602->slave_substream = NULL;
 }
 
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
@@ -496,6 +518,9 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
                SNDRV_PCM_RATE_96000)
 
+#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
 struct snd_soc_dai ssm2602_dai = {
        .name = "SSM2602",
        .playback = {
@@ -503,20 +528,18 @@ struct snd_soc_dai ssm2602_dai = {
                .channels_min = 2,
                .channels_max = 2,
                .rates = SSM2602_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
+               .formats = SSM2602_FORMATS,},
        .capture = {
                .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SSM2602_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
+               .formats = SSM2602_FORMATS,},
        .ops = {
                .startup = ssm2602_startup,
                .prepare = ssm2602_pcm_prepare,
                .hw_params = ssm2602_hw_params,
                .shutdown = ssm2602_shutdown,
-       },
-       .dai_ops = {
                .digital_mute = ssm2602_mute,
                .set_sysclk = ssm2602_set_dai_sysclk,
                .set_fmt = ssm2602_set_dai_fmt,
index 44308da..a4e13d0 100644 (file)
 
 #define AIC23_VERSION "0.1"
 
-struct tlv320aic23_srate_reg_info {
-       u32 sample_rate;
-       u8 control;             /* SR3, SR2, SR1, SR0 and BOSR */
-       u8 divider;             /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
-};
-
 /*
  * AIC23 register cache
  */
@@ -261,20 +255,156 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 };
 
-/* tlv320aic23 related */
-static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
-       {4000, 0x06, 1},        /*  4000 */
-       {8000, 0x06, 0},        /*  8000 */
-       {16000, 0x0C, 1},       /* 16000 */
-       {22050, 0x11, 1},       /* 22050 */
-       {24000, 0x00, 1},       /* 24000 */
-       {32000, 0x0C, 0},       /* 32000 */
-       {44100, 0x11, 0},       /* 44100 */
-       {48000, 0x00, 0},       /* 48000 */
-       {88200, 0x1F, 0},       /* 88200 */
-       {96000, 0x0E, 0},       /* 96000 */
+/* AIC23 driver data */
+struct aic23 {
+       struct snd_soc_codec codec;
+       int mclk;
+       int requested_adc;
+       int requested_dac;
+};
+
+/*
+ * Common Crystals used
+ * 11.2896 Mhz /128 = *88.2k  /192 = 58.8k
+ * 12.0000 Mhz /125 = *96k    /136 = 88.235K
+ * 12.2880 Mhz /128 = *96k    /192 = 64k
+ * 16.9344 Mhz /128 = 132.3k /192 = *88.2k
+ * 18.4320 Mhz /128 = 144k   /192 = *96k
+ */
+
+/*
+ * Normal BOSR 0-256/2 = 128, 1-384/2 = 192
+ * USB BOSR 0-250/2 = 125, 1-272/2 = 136
+ */
+static const int bosr_usb_divisor_table[] = {
+       128, 125, 192, 136
+};
+#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7))
+#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11)        | (1<<15))
+static const unsigned short sr_valid_mask[] = {
+       LOWER_GROUP|UPPER_GROUP,        /* Normal, bosr - 0*/
+       LOWER_GROUP|UPPER_GROUP,        /* Normal, bosr - 1*/
+       LOWER_GROUP,                    /* Usb, bosr - 0*/
+       UPPER_GROUP,                    /* Usb, bosr - 1*/
+};
+/*
+ * Every divisor is a factor of 11*12
+ */
+#define SR_MULT (11*12)
+#define A(x) (x) ? (SR_MULT/x) : 0
+static const unsigned char sr_adc_mult_table[] = {
+       A(2), A(2), A(12), A(12),  A(0), A(0), A(3), A(1),
+       A(2), A(2), A(11), A(11),  A(0), A(0), A(0), A(1)
+};
+static const unsigned char sr_dac_mult_table[] = {
+       A(2), A(12), A(2), A(12),  A(0), A(0), A(3), A(1),
+       A(2), A(11), A(2), A(11),  A(0), A(0), A(0), A(1)
 };
 
+static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc,
+               int dac, int dac_l, int dac_h, int need_dac)
+{
+       if ((adc >= adc_l) && (adc <= adc_h) &&
+                       (dac >= dac_l) && (dac <= dac_h)) {
+               int diff_adc = need_adc - adc;
+               int diff_dac = need_dac - dac;
+               return abs(diff_adc) + abs(diff_dac);
+       }
+       return UINT_MAX;
+}
+
+static int find_rate(int mclk, u32 need_adc, u32 need_dac)
+{
+       int i, j;
+       int best_i = -1;
+       int best_j = -1;
+       int best_div = 0;
+       unsigned best_score = UINT_MAX;
+       int adc_l, adc_h, dac_l, dac_h;
+
+       need_adc *= SR_MULT;
+       need_dac *= SR_MULT;
+       /*
+        * rates given are +/- 1/32
+        */
+       adc_l = need_adc - (need_adc >> 5);
+       adc_h = need_adc + (need_adc >> 5);
+       dac_l = need_dac - (need_dac >> 5);
+       dac_h = need_dac + (need_dac >> 5);
+       for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) {
+               int base = mclk / bosr_usb_divisor_table[i];
+               int mask = sr_valid_mask[i];
+               for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table);
+                               j++, mask >>= 1) {
+                       int adc;
+                       int dac;
+                       int score;
+                       if ((mask & 1) == 0)
+                               continue;
+                       adc = base * sr_adc_mult_table[j];
+                       dac = base * sr_dac_mult_table[j];
+                       score = get_score(adc, adc_l, adc_h, need_adc,
+                                       dac, dac_l, dac_h, need_dac);
+                       if (best_score > score) {
+                               best_score = score;
+                               best_i = i;
+                               best_j = j;
+                               best_div = 0;
+                       }
+                       score = get_score((adc >> 1), adc_l, adc_h, need_adc,
+                                       (dac >> 1), dac_l, dac_h, need_dac);
+                       /* prefer to have a /2 */
+                       if ((score != UINT_MAX) && (best_score >= score)) {
+                               best_score = score;
+                               best_i = i;
+                               best_j = j;
+                               best_div = 1;
+                       }
+               }
+       }
+       return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT);
+}
+
+#ifdef DEBUG
+static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk,
+               u32 *sample_rate_adc, u32 *sample_rate_dac)
+{
+       int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE);
+       int sr = (src >> 2) & 0x0f;
+       int val = (mclk / bosr_usb_divisor_table[src & 3]);
+       int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
+       int dac = (val * sr_dac_mult_table[sr]) / SR_MULT;
+       if (src & TLV320AIC23_CLKIN_HALF) {
+               adc >>= 1;
+               dac >>= 1;
+       }
+       *sample_rate_adc = adc;
+       *sample_rate_dac = dac;
+}
+#endif
+
+static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
+               u32 sample_rate_adc, u32 sample_rate_dac)
+{
+       /* Search for the right sample rate */
+       int data = find_rate(mclk, sample_rate_adc, sample_rate_dac);
+       if (data < 0) {
+               printk(KERN_ERR "%s:Invalid rate %u,%u requested\n",
+                               __func__, sample_rate_adc, sample_rate_dac);
+               return -EINVAL;
+       }
+       tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+#ifdef DEBUG
+       {
+               u32 adc, dac;
+               get_current_sample_rates(codec, mclk, &adc, &dac);
+               printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n",
+                       adc, dac, data);
+       }
+#endif
+       return 0;
+}
+
 static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
 {
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -288,32 +418,36 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
 }
 
 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params)
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->codec;
-       u16 iface_reg, data;
-       u8 count = 0;
+       u16 iface_reg;
+       int ret;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       u32 sample_rate_adc = aic23->requested_adc;
+       u32 sample_rate_dac = aic23->requested_dac;
+       u32 sample_rate = params_rate(params);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               aic23->requested_dac = sample_rate_dac = sample_rate;
+               if (!sample_rate_adc)
+                       sample_rate_adc = sample_rate;
+       } else {
+               aic23->requested_adc = sample_rate_adc = sample_rate;
+               if (!sample_rate_dac)
+                       sample_rate_dac = sample_rate;
+       }
+       ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc,
+                       sample_rate_dac);
+       if (ret < 0)
+               return ret;
 
        iface_reg =
            tlv320aic23_read_reg_cache(codec,
                                       TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
-
-       /* Search for the right sample rate */
-       /* Verify what happens if the rate is not supported
-        * now it goes to 96Khz */
-       while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
-              (count < ARRAY_SIZE(srate_reg_info))) {
-               count++;
-       }
-
-       data =  (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
-               (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
-               TLV320AIC23_USB_CLK_ON;
-
-       tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
-
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                break;
@@ -332,7 +466,8 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
+                                  struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
@@ -344,17 +479,23 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->codec;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
        /* deactivate */
        if (!codec->active) {
                udelay(50);
                tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
        }
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               aic23->requested_dac = 0;
+       else
+               aic23->requested_adc = 0;
 }
 
 static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
@@ -422,12 +563,9 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                      int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-
-       switch (freq) {
-       case 12000000:
-               return 0;
-       }
-       return -EINVAL;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       aic23->mclk = freq;
+       return 0;
 }
 
 static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
@@ -478,12 +616,10 @@ struct snd_soc_dai tlv320aic23_dai = {
                .prepare = tlv320aic23_pcm_prepare,
                .hw_params = tlv320aic23_hw_params,
                .shutdown = tlv320aic23_shutdown,
-               },
-       .dai_ops = {
-                   .digital_mute = tlv320aic23_mute,
-                   .set_fmt = tlv320aic23_set_dai_fmt,
-                   .set_sysclk = tlv320aic23_set_dai_sysclk,
-                   }
+               .digital_mute = tlv320aic23_mute,
+               .set_fmt = tlv320aic23_set_dai_fmt,
+               .set_sysclk = tlv320aic23_set_dai_sysclk,
+       }
 };
 EXPORT_SYMBOL_GPL(tlv320aic23_dai);
 
@@ -659,14 +795,15 @@ static int tlv320aic23_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec;
+       struct aic23 *aic23;
        int ret = 0;
 
        printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
 
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
+       aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+       if (aic23 == NULL)
                return -ENOMEM;
-
+       codec = &aic23->codec;
        socdev->codec = codec;
        mutex_init(&codec->mutex);
        INIT_LIST_HEAD(&codec->dapm_widgets);
@@ -687,6 +824,7 @@ static int tlv320aic23_remove(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->codec;
+       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
        if (codec->control_data)
                tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -697,7 +835,7 @@ static int tlv320aic23_remove(struct platform_device *pdev)
        i2c_del_driver(&tlv320aic23_i2c_driver);
 #endif
        kfree(codec->reg_cache);
-       kfree(codec);
+       kfree(aic23);
 
        return 0;
 }
index bed8a9e..6b7ddfc 100644 (file)
@@ -125,7 +125,8 @@ static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
  * Digital Audio Interface Operations
  */
 static int aic26_hw_params(struct snd_pcm_substream *substream,
-                          struct snd_pcm_hw_params *params)
+                          struct snd_pcm_hw_params *params,
+                          struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
@@ -287,8 +288,6 @@ struct snd_soc_dai aic26_dai = {
        },
        .ops = {
                .hw_params = aic26_hw_params,
-       },
-       .dai_ops = {
                .digital_mute = aic26_mute,
                .set_sysclk = aic26_set_sysclk,
                .set_fmt = aic26_set_fmt,
index cff276e..255e784 100644 (file)
@@ -272,8 +272,10 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
                     DACR1_2_HPROUT_VOL, 0, 0x7f, 1),
        SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
                     0x01, 0),
-       SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
-                    PGAR_2_HPROUT_VOL, 0, 0x7f, 1),
+       SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
+                    0, 0x7f, 1),
+       SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL,
+                    0, 0x7f, 1),
        SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL,
                     LINE2R_2_HPROUT_VOL, 0, 0x7f, 1),
 
@@ -281,8 +283,10 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
                     DACR1_2_HPRCOM_VOL, 0, 0x7f, 1),
        SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
                     0x01, 0),
-       SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
-                    PGAR_2_HPRCOM_VOL, 0, 0x7f, 1),
+       SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
+                    0, 0x7f, 1),
+       SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL,
+                    0, 0x7f, 1),
        SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL,
                     LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1),
 
@@ -333,7 +337,8 @@ SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
 
 /* Left DAC_L1 Mixer */
 static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
@@ -341,7 +346,8 @@ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
 
 /* Right DAC_R1 Mixer */
 static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
@@ -350,14 +356,18 @@ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
 /* Left PGA Mixer */
 static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = {
        SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
        SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1),
        SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
 };
 
 /* Right PGA Mixer */
 static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
        SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
        SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
        SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
 };
 
@@ -379,34 +389,42 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
 
 /* Left PGA Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Right PGA Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Left Line2 Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
 };
 
 /* Right Line2 Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
@@ -439,22 +457,26 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        /* Mono Output */
        SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
 
-       /* Left Inputs to Left ADC */
+       /* Inputs to Left ADC */
        SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
        SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
                           &aic3x_left_pga_mixer_controls[0],
                           ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_line1_mux_controls),
+       SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_left_line1_mux_controls),
        SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_line2_mux_controls),
 
-       /* Right Inputs to Right ADC */
+       /* Inputs to Right ADC */
        SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
                         LINE1R_2_RADC_CTRL, 2, 0),
        SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
                           &aic3x_right_pga_mixer_controls[0],
                           ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
+       SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_right_line1_mux_controls),
        SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line1_mux_controls),
        SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
@@ -531,7 +553,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Left DAC Mux", "DAC_L2", "Left DAC"},
        {"Left DAC Mux", "DAC_L3", "Left DAC"},
 
-       {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"},
+       {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"},
+       {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"},
        {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
        {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
        {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
@@ -557,7 +580,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right DAC Mux", "DAC_R2", "Right DAC"},
        {"Right DAC Mux", "DAC_R3", "Right DAC"},
 
-       {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"},
+       {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"},
+       {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"},
        {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
        {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
        {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
@@ -592,8 +616,10 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Left Line2L Mux", "differential", "LINE2L"},
 
        {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
+       {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
        {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
        {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
+       {"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
 
        {"Left ADC", NULL, "Left PGA Mixer"},
        {"Left ADC", NULL, "GPIO1 dmic modclk"},
@@ -605,18 +631,23 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right Line2R Mux", "single-ended", "LINE2R"},
        {"Right Line2R Mux", "differential", "LINE2R"},
 
+       {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
        {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
        {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
+       {"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
        {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
 
        {"Right ADC", NULL, "Right PGA Mixer"},
        {"Right ADC", NULL, "GPIO1 dmic modclk"},
 
        /* Left PGA Bypass */
-       {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"},
        {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"},
 
        {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
        {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
@@ -627,10 +658,13 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
 
        /* Right PGA Bypass */
-       {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"},
        {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"},
 
        {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
        {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
@@ -643,10 +677,11 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right HP Out", NULL, "Right PGA Bypass Mixer"}