Merge remote-tracking branch 'asoc/topic/wm9090' into asoc-next
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 9 Dec 2012 15:22:39 +0000 (00:22 +0900)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 9 Dec 2012 15:22:39 +0000 (00:22 +0900)
191 files changed:
Documentation/devicetree/bindings/misc/atmel-ssc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ak4104.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs4271.txt
Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/at91sam9x5.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-exynos/mach-armlex4210.c
arch/arm/mach-exynos/mach-smdkv310.c
arch/arm/mach-s3c24xx/mach-gta02.c
arch/arm/mach-s3c24xx/mach-h1940.c
arch/arm/mach-s3c24xx/mach-mini2440.c
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s5p64x0/mach-smdk6440.c
arch/arm/mach-s5p64x0/mach-smdk6450.c
arch/arm/mach-s5pc100/mach-smdkc100.c
arch/arm/mach-s5pv210/mach-smdkc110.c
arch/arm/mach-s5pv210/mach-smdkv210.c
arch/arm/plat-samsung/devs.c
arch/arm/plat-samsung/include/plat/devs.h
drivers/base/regmap/internal.h
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/arizona-haptics.c [new file with mode: 0644]
drivers/mfd/arizona-core.c
drivers/mfd/wm8994-core.c
drivers/misc/atmel-ssc.c
include/linux/atmel-ssc.h
include/linux/mfd/arizona/core.h
include/linux/mfd/arizona/pdata.h
include/linux/mfd/wm8994/core.h
include/linux/mfd/wm8994/pdata.h
include/linux/platform_data/asoc-s3c.h
include/linux/platform_data/davinci_asp.h
include/linux/platform_data/omap-twl4030.h
include/linux/regmap.h
include/sound/cs4271.h
include/sound/sh_fsi.h
include/sound/tlv320aic32x4.h
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel-pcm-dma.c [new file with mode: 0644]
sound/soc/atmel/atmel-pcm-pdc.c [new file with mode: 0644]
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_ssc_dai.h
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs4271.c
sound/soc/codecs/da7210.c
sound/soc/codecs/da9055.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/lm49453.c
sound/soc/codecs/max9768.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98090.c [new file with mode: 0644]
sound/soc/codecs/rt5631.c
sound/soc/codecs/si476x.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic32x4.h
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm_adsp.c [new file with mode: 0644]
sound/soc/codecs/wm_adsp.h [new file with mode: 0644]
sound/soc/codecs/wmfw.h [new file with mode: 0644]
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/imx-pcm.c
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/p1022_rdk.c [new file with mode: 0644]
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood.h
sound/soc/mxs/mxs-saif.c
sound/soc/omap/mcbsp.c
sound/soc/omap/mcbsp.h
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/zoom2.c
sound/soc/samsung/ac97.c
sound/soc/samsung/bells.c
sound/soc/samsung/dma.c
sound/soc/samsung/dma.h
sound/soc/samsung/goni_wm8994.c
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/jive_wm8750.c
sound/soc/samsung/littlemill.c
sound/soc/samsung/ln2440sbc_alc650.c
sound/soc/samsung/lowland.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/pcm.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/s3c24xx_simtec_hermes.c
sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/smdk2443_wm9710.c
sound/soc/samsung/smdk_spdif.c
sound/soc/samsung/smdk_wm8580.c
sound/soc/samsung/smdk_wm8580pcm.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/smdk_wm8994pcm.c
sound/soc/samsung/smdk_wm9713.c
sound/soc/samsung/spdif.c
sound/soc/samsung/speyside.c
sound/soc/samsung/tobermory.c
sound/soc/sh/fsi.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-dmaengine-pcm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/tegra/tegra20_das.c
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_wm8753.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/tegra/trimslice.c
sound/soc/ux500/mop500.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_dai.h
sound/soc/ux500/ux500_pcm.c
sound/soc/ux500/ux500_pcm.h

diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
new file mode 100644 (file)
index 0000000..38e51ad
--- /dev/null
@@ -0,0 +1,15 @@
+* Atmel SSC driver.
+
+Required properties:
+- compatible: "atmel,at91rm9200-ssc" or "atmel,at91sam9g45-ssc"
+       - atmel,at91rm9200-ssc: support pdc transfer
+       - atmel,at91sam9g45-ssc: support dma transfer
+- reg: Should contain SSC registers location and length
+- interrupts: Should contain SSC interrupt
+
+Example:
+ssc0: ssc@fffbc000 {
+       compatible = "atmel,at91rm9200-ssc";
+       reg = <0xfffbc000 0x4000>;
+       interrupts = <14 4 5>;
+};
diff --git a/Documentation/devicetree/bindings/sound/ak4104.txt b/Documentation/devicetree/bindings/sound/ak4104.txt
new file mode 100644 (file)
index 0000000..b902ee3
--- /dev/null
@@ -0,0 +1,22 @@
+AK4104 S/PDIF transmitter
+
+This device supports SPI mode only.
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak4104"
+
+  - reg : The chip select number on the SPI bus
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
+                deasserted before communication to the device starts.
+
+Example:
+
+spdif: ak4104@0 {
+       compatible = "asahi-kasei,ak4104";
+       reg = <0>;
+       spi-max-frequency = <5000000>;
+};
diff --git a/Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt b/Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt
new file mode 100644 (file)
index 0000000..9c5a994
--- /dev/null
@@ -0,0 +1,26 @@
+* Atmel at91sam9g20ek wm8731 audio complex
+
+Required properties:
+  - compatible: "atmel,at91sam9g20ek-wm8731-audio"
+  - atmel,model: The user-visible name of this sound complex.
+  - atmel,audio-routing: A list of the connections between audio components.
+  - atmel,ssc-controller: The phandle of the SSC controller
+  - atmel,audio-codec: The phandle of the WM8731 audio codec
+Optional properties:
+  - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
+
+Example:
+sound {
+       compatible = "atmel,at91sam9g20ek-wm8731-audio";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pck0_as_mck>;
+
+       atmel,model = "wm8731 @ AT91SAMG20EK";
+
+       atmel,audio-routing =
+               "Ext Spk", "LHPOUT",
+               "Int MIC", "MICIN";
+
+       atmel,ssc-controller = <&ssc0>;
+       atmel,audio-codec = <&wm8731>;
+};
index c81b5fd5a5bc80459a1b2d626c9f20b5a86bfbe9..a850fb9c88eab2156ec89f0c76d8ca59073540f8 100644 (file)
@@ -18,6 +18,8 @@ Optional properties:
 
  - reset-gpio:         a GPIO spec to define which pin is connected to the chip's
                !RESET pin
+ - cirrus,amuteb-eq-bmutec:    When given, the Codec's AMUTEB=BMUTEC flag
+                               is enabled.
 
 Examples:
 
index 65dec876cb2d792813abc050833950ef48b53a66..fd40c852d7c7e18c12e5fabc49f0b141614267ac 100644 (file)
@@ -12,7 +12,7 @@ Required properties:
 
 Optional properties:
 - ti,dmic: phandle for the OMAP dmic node if the machine have it connected
-- ti,jack_detection: Need to be set to <1> if the board capable to detect jack
+- ti,jack_detection: Need to be present if the board capable to detect jack
   insertion, removal.
 
 Available audio endpoints for the audio-routing table:
@@ -59,7 +59,7 @@ sound {
        compatible = "ti,abe-twl6040";
        ti,model = "SDP4430";
 
-       ti,jack-detection = <1>;
+       ti,jack-detection;
        ti,mclk-freq = <38400000>;
 
        ti,mcpdm = <&mcpdm>;
index d410581a5a859901b32a49a1f037356c9f22e294..aaa42d8d4f8895233bdaddc00b3bdf69775e0379 100644 (file)
@@ -29,6 +29,7 @@
                tcb0 = &tcb0;
                tcb1 = &tcb1;
                i2c0 = &i2c0;
+               ssc0 = &ssc0;
        };
        cpus {
                cpu@0 {
                                status = "disabled";
                        };
 
+                       ssc0: ssc@fffbc000 {
+                               compatible = "atmel,at91rm9200-ssc";
+                               reg = <0xfffbc000 0x4000>;
+                               interrupts = <14 4 5>;
+                               status = "disable";
+                       };
+
                        adc0: adc@fffe0000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xfffe0000 0x100>;
index 3e6e5c1abbf37184a44237e464080a52f4312e9f..3b721ee59b109500b688bebff12e098f0aaf05ce 100644 (file)
@@ -25,6 +25,8 @@
                gpio4 = &pioE;
                tcb0 = &tcb0;
                i2c0 = &i2c0;
+               ssc0 = &ssc0;
+               ssc1 = &ssc1;
        };
        cpus {
                cpu@0 {
                                status = "disabled";
                        };
 
+                       ssc0: ssc@fff98000 {
+                               compatible = "atmel,at91rm9200-ssc";
+                               reg = <0xfff98000 0x4000>;
+                               interrupts = <16 4 5>;
+                               status = "disable";
+                       };
+
+                       ssc1: ssc@fff9c000 {
+                               compatible = "atmel,at91rm9200-ssc";
+                               reg = <0xfff9c000 0x4000>;
+                               interrupts = <17 4 5>;
+                               status = "disable";
+                       };
+
                        macb0: ethernet@fffbc000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffbc000 0x100>;
index e6391a4e6649cc3787ba14d7ed1d190b2d932964..2dcec8de759f97c31780027614f99866bb0c8a58 100644 (file)
 
        ahb {
                apb {
+                       pinctrl@fffff400 {
+                               board {
+                                       pinctrl_pck0_as_mck: pck0_as_mck {
+                                               atmel,pins =
+                                                       <2 1 0x2 0x0>;  /* PC1 periph B */
+                                       };
+
+                               };
+                       };
+
                        dbgu: serial@fffff200 {
                                status = "okay";
                        };
                                atmel,vbus-gpio = <&pioC 5 0>;
                                status = "okay";
                        };
+
+                       ssc0: ssc@fffbc000 {
+                               status = "okay";
+                               pinctrl-0 = <&pinctrl_ssc0_tx>;
+                       };
                };
 
                nand0: nand@40000000 {
                        reg = <0x50>;
                };
 
-               wm8731@1b {
+               wm8731: wm8731@1b {
                        compatible = "wm8731";
                        reg = <0x1b>;
                };
                        gpio-key,wakeup;
                };
        };
+
+       sound {
+               compatible = "atmel,at91sam9g20ek-wm8731-audio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pck0_as_mck>;
+
+               atmel,model = "wm8731 @ AT91SAMG20EK";
+
+               atmel,audio-routing =
+                       "Ext Spk", "LHPOUT",
+                       "Int Mic", "MICIN";
+
+               atmel,ssc-controller = <&ssc0>;
+               atmel,audio-codec = <&wm8731>;
+       };
 };
index 3add030d61f8651fcf5a0476b11423897de71560..acfa207162ff581eaaf063c4d3154a6f658ea177 100644 (file)
@@ -31,6 +31,8 @@
                tcb1 = &tcb1;
                i2c0 = &i2c0;
                i2c1 = &i2c1;
+               ssc0 = &ssc0;
+               ssc1 = &ssc1;
        };
        cpus {
                cpu@0 {
                                status = "disabled";
                        };
 
+                       ssc0: ssc@fff9c000 {
+                               compatible = "atmel,at91sam9g45-ssc";
+                               reg = <0xfff9c000 0x4000>;
+                               interrupts = <16 4 5>;
+                               status = "disable";
+                       };
+
+                       ssc1: ssc@fffa0000 {
+                               compatible = "atmel,at91sam9g45-ssc";
+                               reg = <0xfffa0000 0x4000>;
+                               interrupts = <17 4 5>;
+                               status = "disable";
+                       };
+
                        adc0: adc@fffb0000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xfffb0000 0x100>;
index 03fc136421c5e31b01649c9caacdaf134bef4560..69667d0ac347f142a51c5acc704e731763ec2144 100644 (file)
@@ -30,6 +30,7 @@
                i2c0 = &i2c0;
                i2c1 = &i2c1;
                i2c2 = &i2c2;
+               ssc0 = &ssc0;
        };
        cpus {
                cpu@0 {
                                interrupts = <1 4 7>;
                        };
 
+                       ssc0: ssc@f0010000 {
+                               compatible = "atmel,at91sam9g45-ssc";
+                               reg = <0xf0010000 0x4000>;
+                               interrupts = <28 4 5>;
+                               status = "disable";
+                       };
+
                        tcb0: timer@f8008000 {
                                compatible = "atmel,at91sam9x5-tcb";
                                reg = <0xf8008000 0x100>;
index 5269825194a8a41c620ffa3da9f5a2cf5269bcb5..af47c75db513b58a88be84e52f2e681ec863908c 100644 (file)
@@ -184,9 +184,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
        CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
        CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffd0000.ssc", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffd4000.ssc", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffd8000.ssc", &ssc2_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200.0", &twi_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
index 3cee0e6ea7c3c126ec3b319497b01cf335f3f16a..9e76427aaec29a0065963e8633196f598bc9d2bc 100644 (file)
@@ -752,7 +752,7 @@ static struct resource ssc0_resources[] = {
 };
 
 static struct platform_device at91rm9200_ssc0_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 0,
        .dev    = {
                .dma_mask               = &ssc0_dmamask,
@@ -794,7 +794,7 @@ static struct resource ssc1_resources[] = {
 };
 
 static struct platform_device at91rm9200_ssc1_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 1,
        .dev    = {
                .dma_mask               = &ssc1_dmamask,
@@ -836,7 +836,7 @@ static struct resource ssc2_resources[] = {
 };
 
 static struct platform_device at91rm9200_ssc2_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 2,
        .dev    = {
                .dma_mask               = &ssc2_dmamask,
index f8202615f4a867f32ffe970cde12f0b6887d2375..a41eb3d23f68dc282cc51117427ea446db7b97e5 100644 (file)
@@ -210,7 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
        CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
        CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi_clk),
        /* more usart lookup table for DT entries */
index 414bd855fb0cb7fd1d0295012016937175d9c449..e67cfa2acbe00d05fe773630113b3331cc4661eb 100644 (file)
@@ -742,7 +742,7 @@ static struct resource ssc_resources[] = {
 };
 
 static struct platform_device at91sam9260_ssc_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 0,
        .dev    = {
                .dma_mask               = &ssc_dmamask,
index 04295c04b3e03cb99d31aa2f226908ab2a975ec4..7fcbe05833426b7b648a145b796619f4e47d7d5b 100644 (file)
@@ -174,9 +174,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
        CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
        CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc2_clk),
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261.0", &twi_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi_clk),
index cd604aad8e963c217301df7fa421637d1b0315a3..a27d9dd0faa4a99b9a07e5416c7f0cc96ee18f73 100644 (file)
@@ -706,7 +706,7 @@ static struct resource ssc0_resources[] = {
 };
 
 static struct platform_device at91sam9261_ssc0_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 0,
        .dev    = {
                .dma_mask               = &ssc0_dmamask,
@@ -748,7 +748,7 @@ static struct resource ssc1_resources[] = {
 };
 
 static struct platform_device at91sam9261_ssc1_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 1,
        .dev    = {
                .dma_mask               = &ssc1_dmamask,
@@ -790,7 +790,7 @@ static struct resource ssc2_resources[] = {
 };
 
 static struct platform_device at91sam9261_ssc2_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 2,
        .dev    = {
                .dma_mask               = &ssc2_dmamask,
index d6f9c23927c48c92202776d049a582af01b8f520..c0f4c8c1f4ed59ad31cd004a317e7f436181285c 100644 (file)
@@ -186,8 +186,10 @@ static struct clk *periph_clocks[] __initdata = {
 static struct clk_lookup periph_clocks_lookups[] = {
        /* One additional fake clock for macb_hclk */
        CLKDEV_CON_ID("hclk", &macb_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fff98000.ssc", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc1_clk),
        CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
        CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
        CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
index 9c61e59a2104e7f0399fc0dca4ea926d7136d4f9..8215839f2d540a46db98a83eeddf4228122c75b8 100644 (file)
@@ -1199,7 +1199,7 @@ static struct resource ssc0_resources[] = {
 };
 
 static struct platform_device at91sam9263_ssc0_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 0,
        .dev    = {
                .dma_mask               = &ssc0_dmamask,
@@ -1241,7 +1241,7 @@ static struct resource ssc1_resources[] = {
 };
 
 static struct platform_device at91sam9263_ssc1_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 1,
        .dev    = {
                .dma_mask               = &ssc1_dmamask,
index 84af1b506d92a0b1e9e88c885b1d57be95fbf40b..a4282d3742bf11098fed3a8101285b94eafeddbe 100644 (file)
@@ -239,8 +239,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffa0000.ssc", &ssc1_clk),
        CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
        CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk),
        CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk),
index fcd233cb33d25d68417a992c3b09fac45e63501a..d26474a97fec884e1ef0338400cbf68b00d0ceae 100644 (file)
@@ -1459,7 +1459,7 @@ static struct resource ssc0_resources[] = {
 };
 
 static struct platform_device at91sam9g45_ssc0_device = {
-       .name   = "ssc",
+       .name   = "at91sam9g45_ssc",
        .id     = 0,
        .dev    = {
                .dma_mask               = &ssc0_dmamask,
@@ -1501,7 +1501,7 @@ static struct resource ssc1_resources[] = {
 };
 
 static struct platform_device at91sam9g45_ssc1_device = {
-       .name   = "ssc",
+       .name   = "at91sam9g45_ssc",
        .id     = 1,
        .dev    = {
                .dma_mask               = &ssc1_dmamask,
index 72e908412222615134fc0530cc339348093f76be..b683fdc699f12e1a97dc3c60fdf07f9abd7a02f1 100644 (file)
@@ -184,8 +184,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
        CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
        CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc1_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
        CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
index 5047bdc92adfdb79395143d973468862219d33c4..b656110e8afe6fec0a55fa15edc3084301f54409 100644 (file)
@@ -832,7 +832,7 @@ static struct resource ssc0_resources[] = {
 };
 
 static struct platform_device at91sam9rl_ssc0_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 0,
        .dev    = {
                .dma_mask               = &ssc0_dmamask,
@@ -874,7 +874,7 @@ static struct resource ssc1_resources[] = {
 };
 
 static struct platform_device at91sam9rl_ssc1_device = {
-       .name   = "ssc",
+       .name   = "at91rm9200_ssc",
        .id     = 1,
        .dev    = {
                .dma_mask               = &ssc1_dmamask,
index e5035380dcbce16e806fb460625fd73d9a3c1153..18fbbb27f97fcbb7a191867af7edaa0c2c1f4e8a 100644 (file)
@@ -231,6 +231,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
        CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
        CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "f0010000.ssc", &ssc_clk),
        CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
        CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
        CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
index 3ab2b86a3762a67da9b808386d39c51fb8cd2544..ebdbf42c02c19db171239a3d84add8da572135af 100644 (file)
@@ -353,6 +353,16 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = {
         },
 };
 
+static struct platform_device sam9g20ek_audio_device = {
+       .name   = "at91sam9g20ek-audio",
+       .id     = -1,
+};
+
+static void __init ek_add_device_audio(void)
+{
+       platform_device_register(&sam9g20ek_audio_device);
+}
+
 
 static void __init ek_board_init(void)
 {
@@ -394,6 +404,7 @@ static void __init ek_board_init(void)
        at91_set_B_periph(AT91_PIN_PC1, 0);
        /* SSC (for WM8731) */
        at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
+       ek_add_device_audio();
 }
 
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
index 32ee3f89596738d988a00105c0358d4ff1a61f1b..d9bc3fa7bb228a8c9e7f2feca9bac83b88ac16f5 100644 (file)
@@ -762,16 +762,19 @@ static u8 da850_iis_serializer_direction[] = {
 };
 
 static struct snd_platform_data da850_evm_snd_data = {
-       .tx_dma_offset  = 0x2000,
-       .rx_dma_offset  = 0x2000,
-       .op_mode        = DAVINCI_MCASP_IIS_MODE,
-       .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction),
-       .tdm_slots      = 2,
-       .serial_dir     = da850_iis_serializer_direction,
-       .asp_chan_q     = EVENTQ_0,
-       .version        = MCASP_VERSION_2,
-       .txnumevt       = 1,
-       .rxnumevt       = 1,
+       .tx_dma_offset          = 0x2000,
+       .rx_dma_offset          = 0x2000,
+       .op_mode                = DAVINCI_MCASP_IIS_MODE,
+       .num_serializer         = ARRAY_SIZE(da850_iis_serializer_direction),
+       .tdm_slots              = 2,
+       .serial_dir             = da850_iis_serializer_direction,
+       .asp_chan_q             = EVENTQ_0,
+       .ram_chan_q             = EVENTQ_1,
+       .version                = MCASP_VERSION_2,
+       .txnumevt               = 1,
+       .rxnumevt               = 1,
+       .sram_size_playback     = SZ_8K,
+       .sram_size_capture      = SZ_8K,
 };
 
 static const short da850_evm_mcasp_pins[] __initconst = {
@@ -1509,6 +1512,7 @@ static __init void da850_evm_init(void)
                pr_warning("da850_evm_init: mcasp mux setup failed: %d\n",
                                ret);
 
+       da850_evm_snd_data.sram_pool = sram_get_gen_pool();
        da8xx_register_mcasp(0, &da850_evm_snd_data);
 
        ret = davinci_cfg_reg_list(da850_lcdcntl_pins);
index 3f37a5e8a1f450d4d4e6797d0570c51df5b2805c..b938f9fc1dd1288d781241366daaa90d65582907 100644 (file)
@@ -147,7 +147,6 @@ static struct platform_device *armlex4210_devices[] __initdata = {
        &s3c_device_hsmmc3,
        &s3c_device_rtc,
        &s3c_device_wdt,
-       &samsung_asoc_dma,
        &armlex4210_smsc911x,
        &exynos4_device_ahci,
 };
index ee4fb1a9cb7207b226fdffc24f4e4016fafc7618..5de9ee28a50892fad491e5a1425ff448eed9f892 100644 (file)
@@ -311,7 +311,6 @@ static struct platform_device *smdkv310_devices[] __initdata = {
        &s5p_device_mfc_l,
        &s5p_device_mfc_r,
        &exynos4_device_spdif,
-       &samsung_asoc_dma,
        &samsung_asoc_idma,
        &s5p_device_fimd0,
        &smdkv310_device_audio,
index 4a963467b7eeb46b272d13dde73ea652473961d9..973b87ca87f4a065fd212090ab67eb68fbfe5b73 100644 (file)
@@ -521,7 +521,6 @@ static struct platform_device *gta02_devices[] __initdata = {
        &gta02_nor_flash,
        &s3c24xx_pwm_device,
        &s3c_device_iis,
-       &samsung_asoc_dma,
        &s3c_device_i2c0,
        &gta02_dfbmcs320_device,
        &gta02_buttons_device,
index 63aaf076f61198cb6cdad6e69a93c443b46eaa5a..b23dd1b106e8a6d132578097aba863d48750a18c 100644 (file)
@@ -632,7 +632,6 @@ static struct platform_device *h1940_devices[] __initdata = {
        &s3c_device_wdt,
        &s3c_device_i2c0,
        &s3c_device_iis,
-       &samsung_asoc_dma,
        &s3c_device_usbgadget,
        &h1940_device_leds,
        &h1940_device_bluetooth,
index 393c0f1ac11aa38c5921827b9e6229ec61bcea16..a31d5b83e5f77f9218f19b959ea5ccb0f6d0be39 100644 (file)
@@ -519,7 +519,6 @@ static struct platform_device *mini2440_devices[] __initdata = {
        &s3c_device_iis,
        &uda1340_codec,
        &mini2440_audio,
-       &samsung_asoc_dma,
 };
 
 static void __init mini2440_map_io(void)
index 379fde521d3704cee3817aff65e01b7390f0bf3e..0606f2faaa5c5261eaa916fe374aa21f7bb5da4f 100644 (file)
@@ -712,7 +712,6 @@ static struct platform_device *rx1950_devices[] __initdata = {
        &s3c_device_wdt,
        &s3c_device_i2c0,
        &s3c_device_iis,
-       &samsung_asoc_dma,
        &s3c_device_usbgadget,
        &s3c_device_rtc,
        &s3c_device_nand,
index 13b7eaa45fd04de2627e35111526a38737567d5f..ef2117d7391b6423743b3734e8516981d02d052e 100644 (file)
@@ -357,7 +357,6 @@ static struct platform_device *crag6410_devices[] __initdata = {
        &s3c_device_timer[0],
        &s3c64xx_device_iis0,
        &s3c64xx_device_iis1,
-       &samsung_asoc_dma,
        &samsung_device_keypad,
        &crag6410_gpio_keydev,
        &crag6410_dm9k_device,
index da1a771a29e9f1493ce192d35fde34f6fa23ed01..574a9eef588dc4b6fd764449d3893811e27e7c3f 100644 (file)
@@ -275,7 +275,6 @@ static struct platform_device *smdk6410_devices[] __initdata = {
        &s3c_device_fb,
        &s3c_device_ohci,
        &s3c_device_usb_hsotg,
-       &samsung_asoc_dma,
        &s3c64xx_device_iisv4,
        &samsung_device_keypad,
 
index 96ea1fe0ec94a9d3b0393704b9bf63cbd63bf89b..1af823558c60509d571ee0024b9fca2492496ba4 100644 (file)
@@ -165,7 +165,6 @@ static struct platform_device *smdk6440_devices[] __initdata = {
        &s3c_device_i2c1,
        &s3c_device_ts,
        &s3c_device_wdt,
-       &samsung_asoc_dma,
        &s5p6440_device_iis,
        &s3c_device_fb,
        &smdk6440_lcd_lte480wv,
index 12748b6eaa7b8af25e6ab9033a535e61cae98326..62526ccf6b70243be2e6e4c2f5834b7a87f0aedb 100644 (file)
@@ -183,7 +183,6 @@ static struct platform_device *smdk6450_devices[] __initdata = {
        &s3c_device_i2c1,
        &s3c_device_ts,
        &s3c_device_wdt,
-       &samsung_asoc_dma,
        &s5p6450_device_iis0,
        &s3c_device_fb,
        &smdk6450_lcd_lte480wv,
index dba7384a87bde67d48256dd3e0a95cc61735be55..9abe95e806abfe3bd9a85bc6eee3cd964d9d92af 100644 (file)
@@ -197,7 +197,6 @@ static struct platform_device *smdkc100_devices[] __initdata = {
        &s3c_device_ts,
        &s3c_device_wdt,
        &smdkc100_lcd_powerdev,
-       &samsung_asoc_dma,
        &s5pc100_device_iis0,
        &samsung_device_keypad,
        &s5pc100_device_ac97,
index d9c99fcc1aa7fa97e81b1d930e2523457128f836..f1f3bd37ecda7d53db021a9f69d1cc3432b3159f 100644 (file)
@@ -85,7 +85,6 @@ static struct s3c_ide_platdata smdkc110_ide_pdata __initdata = {
 };
 
 static struct platform_device *smdkc110_devices[] __initdata = {
-       &samsung_asoc_dma,
        &s5pv210_device_iis0,
        &s5pv210_device_ac97,
        &s5pv210_device_spdif,
index 4cdb5bb7bbcf024613689228d746b914c9140de5..6bc8404bf6784cfee3751eed9e6fdd0f24b18152 100644 (file)
@@ -234,7 +234,6 @@ static struct platform_device *smdkv210_devices[] __initdata = {
        &s5pv210_device_ac97,
        &s5pv210_device_iis0,
        &s5pv210_device_spdif,
-       &samsung_asoc_dma,
        &samsung_asoc_idma,
        &samsung_device_keypad,
        &smdkv210_dm9000,
index 03f654d55effb2f10355c914ab206730928759f7..7d27a241f98413701f4305b75bd12269b235bb41 100644 (file)
@@ -146,15 +146,6 @@ struct platform_device s3c_device_camif = {
 
 /* ASOC DMA */
 
-struct platform_device samsung_asoc_dma = {
-       .name           = "samsung-audio",
-       .id             = -1,
-       .dev            = {
-               .dma_mask               = &samsung_device_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       }
-};
-
 struct platform_device samsung_asoc_idma = {
        .name           = "samsung-idma",
        .id             = -1,
index 5da4b4f38f40ebb41c076fbe74bd205aefefdacf..c45f70cbbfb701703f6eb1e6fe9cb71d5391d131 100644 (file)
@@ -135,7 +135,6 @@ extern struct platform_device exynos4_device_spdif;
 
 extern struct platform_device exynos_device_drm;
 
-extern struct platform_device samsung_asoc_dma;
 extern struct platform_device samsung_asoc_idma;
 extern struct platform_device samsung_device_keypad;
 
index 80f9ab9c3aa4b7eba89b436d0dcd6a96b3623558..ac869d28d5ba42d7340122d46885c820aebdfb64 100644 (file)
@@ -120,6 +120,8 @@ int _regmap_write(struct regmap *map, unsigned int reg,
 
 struct regmap_range_node {
        struct rb_node node;
+       const char *name;
+       struct regmap *map;
 
        unsigned int range_min;
        unsigned int range_max;
index bb1ff175b9629083a4d5d6e4e0e6811de3b2f808..f4b9dd01c9819ad4e1bc789593876a1f449eb8e3 100644 (file)
@@ -56,15 +56,15 @@ static const struct file_operations regmap_name_fops = {
        .llseek = default_llseek,
 };
 
-static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
-                                   size_t count, loff_t *ppos)
+static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
+                                  unsigned int to, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
 {
        int reg_len, val_len, tot_len;
        size_t buf_pos = 0;
        loff_t p = 0;
        ssize_t ret;
        int i;
-       struct regmap *map = file->private_data;
        char *buf;
        unsigned int val;
 
@@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
        val_len = 2 * map->format.val_bytes;
        tot_len = reg_len + val_len + 3;      /* : \n */
 
-       for (i = 0; i <= map->max_register; i += map->reg_stride) {
+       for (i = from; i <= to; i += map->reg_stride) {
                if (!regmap_readable(map, i))
                        continue;
 
@@ -95,7 +95,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
 
                        /* Format the register */
                        snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
-                                reg_len, i);
+                                reg_len, i - from);
                        buf_pos += reg_len + 2;
 
                        /* Format the value, write all X if we can't read */
@@ -126,6 +126,15 @@ out:
        return ret;
 }
 
+static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct regmap *map = file->private_data;
+
+       return regmap_read_debugfs(map, 0, map->max_register, user_buf,
+                                  count, ppos);
+}
+
 #undef REGMAP_ALLOW_WRITE_DEBUGFS
 #ifdef REGMAP_ALLOW_WRITE_DEBUGFS
 /*
@@ -174,6 +183,22 @@ static const struct file_operations regmap_map_fops = {
        .llseek = default_llseek,
 };
 
+static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct regmap_range_node *range = file->private_data;
+       struct regmap *map = range->map;
+
+       return regmap_read_debugfs(map, range->range_min, range->range_max,
+                                  user_buf, count, ppos);
+}
+
+static const struct file_operations regmap_range_fops = {
+       .open = simple_open,
+       .read = regmap_range_read_file,
+       .llseek = default_llseek,
+};
+
 static ssize_t regmap_access_read_file(struct file *file,
                                       char __user *user_buf, size_t count,
                                       loff_t *ppos)
@@ -244,6 +269,9 @@ static const struct file_operations regmap_access_fops = {
 
 void regmap_debugfs_init(struct regmap *map, const char *name)
 {
+       struct rb_node *next;
+       struct regmap_range_node *range_node;
+
        if (name) {
                map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
                                              dev_name(map->dev), name);
@@ -276,6 +304,18 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
                debugfs_create_bool("cache_bypass", 0400, map->debugfs,
                                    &map->cache_bypass);
        }
+
+       next = rb_first(&map->range_tree);
+       while (next) {
+               range_node = rb_entry(next, struct regmap_range_node, node);
+
+               if (range_node->name)
+                       debugfs_create_file(range_node->name, 0400,
+                                           map->debugfs, range_node,
+                                           &regmap_range_fops);
+
+               next = rb_next(&range_node->node);
+       }
 }
 
 void regmap_debugfs_exit(struct regmap *map)
index 52069d29ff12ef197c7d8a447ab27ffb7096d85e..96253cd949e98cddbf433e68913b6c4051d337fa 100644 (file)
@@ -519,20 +519,38 @@ struct regmap *regmap_init(struct device *dev,
        }
 
        map->range_tree = RB_ROOT;
-       for (i = 0; i < config->n_ranges; i++) {
+       for (i = 0; i < config->num_ranges; i++) {
                const struct regmap_range_cfg *range_cfg = &config->ranges[i];
                struct regmap_range_node *new;
 
                /* Sanity check */
-               if (range_cfg->range_max < range_cfg->range_min ||
-                   range_cfg->range_max > map->max_register ||
-                   range_cfg->selector_reg > map->max_register ||
-                   range_cfg->window_len == 0)
+               if (range_cfg->range_max < range_cfg->range_min) {
+                       dev_err(map->dev, "Invalid range %d: %d < %d\n", i,
+                               range_cfg->range_max, range_cfg->range_min);
                        goto err_range;
+               }
+
+               if (range_cfg->range_max > map->max_register) {
+                       dev_err(map->dev, "Invalid range %d: %d > %d\n", i,
+                               range_cfg->range_max, map->max_register);
+                       goto err_range;
+               }
+
+               if (range_cfg->selector_reg > map->max_register) {
+                       dev_err(map->dev,
+                               "Invalid range %d: selector out of map\n", i);
+                       goto err_range;
+               }
+
+               if (range_cfg->window_len == 0) {
+                       dev_err(map->dev, "Invalid range %d: window_len 0\n",
+                               i);
+                       goto err_range;
+               }
 
                /* Make sure, that this register range has no selector
                   or data window within its boundary */
-               for (j = 0; j < config->n_ranges; j++) {
+               for (j = 0; j < config->num_ranges; j++) {
                        unsigned sel_reg = config->ranges[j].selector_reg;
                        unsigned win_min = config->ranges[j].window_start;
                        unsigned win_max = win_min +
@@ -540,11 +558,17 @@ struct regmap *regmap_init(struct device *dev,
 
                        if (range_cfg->range_min <= sel_reg &&
                            sel_reg <= range_cfg->range_max) {
+                               dev_err(map->dev,
+                                       "Range %d: selector for %d in window\n",
+                                       i, j);
                                goto err_range;
                        }
 
                        if (!(win_max < range_cfg->range_min ||
                              win_min > range_cfg->range_max)) {
+                               dev_err(map->dev,
+                                       "Range %d: window for %d in window\n",
+                                       i, j);
                                goto err_range;
                        }
                }
@@ -555,6 +579,8 @@ struct regmap *regmap_init(struct device *dev,
                        goto err_range;
                }
 
+               new->map = map;
+               new->name = range_cfg->name;
                new->range_min = range_cfg->range_min;
                new->range_max = range_cfg->range_max;
                new->selector_reg = range_cfg->selector_reg;
@@ -564,6 +590,7 @@ struct regmap *regmap_init(struct device *dev,
                new->window_len = range_cfg->window_len;
 
                if (_regmap_range_add(map, new) == false) {
+                       dev_err(map->dev, "Failed to add range %d\n", i);
                        kfree(new);
                        goto err_range;
                }
@@ -579,7 +606,7 @@ struct regmap *regmap_init(struct device *dev,
        }
 
        ret = regcache_init(map, config);
-       if (ret < 0)
+       if (ret != 0)
                goto err_range;
 
        regmap_debugfs_init(map, config->name);
@@ -738,59 +765,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name)
 EXPORT_SYMBOL_GPL(dev_get_regmap);
 
 static int _regmap_select_page(struct regmap *map, unsigned int *reg,
+                              struct regmap_range_node *range,
                               unsigned int val_num)
 {
-       struct regmap_range_node *range;
        void *orig_work_buf;
        unsigned int win_offset;
        unsigned int win_page;
        bool page_chg;
        int ret;
 
-       range = _regmap_range_lookup(map, *reg);
-       if (range) {
-               win_offset = (*reg - range->range_min) % range->window_len;
-               win_page = (*reg - range->range_min) / range->window_len;
-
-               if (val_num > 1) {
-                       /* Bulk write shouldn't cross range boundary */
-                       if (*reg + val_num - 1 > range->range_max)
-                               return -EINVAL;
+       win_offset = (*reg - range->range_min) % range->window_len;
+       win_page = (*reg - range->range_min) / range->window_len;
 
-                       /* ... or single page boundary */
-                       if (val_num > range->window_len - win_offset)
-                               return -EINVAL;
-               }
+       if (val_num > 1) {
+               /* Bulk write shouldn't cross range boundary */
+               if (*reg + val_num - 1 > range->range_max)
+                       return -EINVAL;
 
-               /* It is possible to have selector register inside data window.
-                  In that case, selector register is located on every page and
-                  it needs no page switching, when accessed alone. */
-               if (val_num > 1 ||
-                   range->window_start + win_offset != range->selector_reg) {
-                       /* Use separate work_buf during page switching */
-                       orig_work_buf = map->work_buf;
-                       map->work_buf = map->selector_work_buf;
+               /* ... or single page boundary */
+               if (val_num > range->window_len - win_offset)
+                       return -EINVAL;
+       }
 
-                       ret = _regmap_update_bits(map, range->selector_reg,
-                                       range->selector_mask,
-                                       win_page << range->selector_shift,
-                                       &page_chg);
+       /* It is possible to have selector register inside data window.
+          In that case, selector register is located on every page and
+          it needs no page switching, when accessed alone. */
+       if (val_num > 1 ||
+           range->window_start + win_offset != range->selector_reg) {
+               /* Use separate work_buf during page switching */
+               orig_work_buf = map->work_buf;
+               map->work_buf = map->selector_work_buf;
 
-                       map->work_buf = orig_work_buf;
+               ret = _regmap_update_bits(map, range->selector_reg,
+                                         range->selector_mask,
+                                         win_page << range->selector_shift,
+                                         &page_chg);
 
-                       if (ret < 0)
-                               return ret;
-               }
+               map->work_buf = orig_work_buf;
 
-               *reg = range->window_start + win_offset;
+               if (ret != 0)
+                       return ret;
        }
 
+       *reg = range->window_start + win_offset;
+
        return 0;
 }
 
 static int _regmap_raw_write(struct regmap *map, unsigned int reg,
                             const void *val, size_t val_len)
 {
+       struct regmap_range_node *range;
        u8 *u8 = map->work_buf;
        void *buf;
        int ret = -ENOTSUPP;
@@ -825,9 +850,35 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
                }
        }
 
-       ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
-       if (ret < 0)
-               return ret;
+       range = _regmap_range_lookup(map, reg);
+       if (range) {
+               int val_num = val_len / map->format.val_bytes;
+               int win_offset = (reg - range->range_min) % range->window_len;
+               int win_residue = range->window_len - win_offset;
+
+               /* If the write goes beyond the end of the window split it */
+               while (val_num > win_residue) {
+                       dev_dbg(map->dev, "Writing window %d/%d\n",
+                               win_residue, val_len / map->format.val_bytes);
+                       ret = _regmap_raw_write(map, reg, val, win_residue *
+                                               map->format.val_bytes);
+                       if (ret != 0)
+                               return ret;
+
+                       reg += win_residue;
+                       val_num -= win_residue;
+                       val += win_residue * map->format.val_bytes;
+                       val_len -= win_residue * map->format.val_bytes;
+
+                       win_offset = (reg - range->range_min) %
+                               range->window_len;
+                       win_residue = range->window_len - win_offset;
+               }
+
+               ret = _regmap_select_page(map, &reg, range, val_num);
+               if (ret != 0)
+                       return ret;
+       }
 
        map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
@@ -876,6 +927,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 int _regmap_write(struct regmap *map, unsigned int reg,
                  unsigned int val)
 {
+       struct regmap_range_node *range;
        int ret;
        BUG_ON(!map->format.format_write && !map->format.format_val);
 
@@ -897,9 +949,12 @@ int _regmap_write(struct regmap *map, unsigned int reg,
        trace_regmap_reg_write(map->dev, reg, val);
 
        if (map->format.format_write) {
-               ret = _regmap_select_page(map, &reg, 1);
-               if (ret < 0)
-                       return ret;
+               range = _regmap_range_lookup(map, reg);
+               if (range) {
+                       ret = _regmap_select_page(map, &reg, range, 1);
+                       if (ret != 0)
+                               return ret;
+               }
 
                map->format.format_write(map, reg, val);
 
@@ -1055,12 +1110,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
 static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                            unsigned int val_len)
 {
+       struct regmap_range_node *range;
        u8 *u8 = map->work_buf;
        int ret;
 
-       ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
-       if (ret < 0)
-               return ret;
+       range = _regmap_range_lookup(map, reg);
+       if (range) {
+               ret = _regmap_select_page(map, &reg, range,
+                                         val_len / map->format.val_bytes);
+               if (ret != 0)
+                       return ret;
+       }
 
        map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
index 7c0f1ecfdd7a3ff88fed02671e1cf0fba5847b24..104a7c3153c0c4ce5fd695403bfb8a263da992d7 100644 (file)
@@ -72,6 +72,16 @@ config INPUT_AD714X_SPI
          To compile this driver as a module, choose M here: the
          module will be called ad714x-spi.
 
+config INPUT_ARIZONA_HAPTICS
+       tristate "Arizona haptics support"
+       depends on MFD_ARIZONA && SND_SOC
+       select INPUT_FF_MEMLESS
+       help
+         Say Y to enable support for the haptics module in Arizona CODECs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called arizona-haptics.
+
 config INPUT_BMA150
        tristate "BMA150/SMB380 acceleration sensor support"
        depends on I2C
index 83fe6f5b77d120e9b3194325f0fc83879a474a0a..5ea769eda999ff1fa35954bdc6bf467c22ebbf99 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_INPUT_ADXL34X)           += adxl34x.o
 obj-$(CONFIG_INPUT_ADXL34X_I2C)                += adxl34x-i2c.o
 obj-$(CONFIG_INPUT_ADXL34X_SPI)                += adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)             += apanel.o
+obj-$(CONFIG_INPUT_ARIZONA_HAPTICS)    += arizona-haptics.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)                += ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
 obj-$(CONFIG_INPUT_BFIN_ROTARY)                += bfin_rotary.o
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c
new file mode 100644 (file)
index 0000000..7a04f54
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Arizona haptics driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+struct arizona_haptics {
+       struct arizona *arizona;
+       struct input_dev *input_dev;
+       struct work_struct work;
+
+       struct mutex mutex;
+       u8 intensity;
+};
+
+static void arizona_haptics_work(struct work_struct *work)
+{
+       struct arizona_haptics *haptics = container_of(work,
+                                                      struct arizona_haptics,
+                                                      work);
+       struct arizona *arizona = haptics->arizona;
+       struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex;
+       int ret;
+
+       if (!haptics->arizona->dapm) {
+               dev_err(arizona->dev, "No DAPM context\n");
+               return;
+       }
+
+       if (haptics->intensity) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_HAPTICS_PHASE_2_INTENSITY,
+                                        ARIZONA_PHASE2_INTENSITY_MASK,
+                                        haptics->intensity);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to set intensity: %d\n",
+                               ret);
+                       return;
+               }
+
+               /* This enable sequence will be a noop if already enabled */
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_HAPTICS_CONTROL_1,
+                                        ARIZONA_HAP_CTRL_MASK,
+                                        1 << ARIZONA_HAP_CTRL_SHIFT);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to start haptics: %d\n",
+                               ret);
+                       return;
+               }
+
+               mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+               ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
+                               ret);
+                       mutex_unlock(dapm_mutex);
+                       return;
+               }
+
+               ret = snd_soc_dapm_sync(arizona->dapm);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
+                               ret);
+                       mutex_unlock(dapm_mutex);
+                       return;
+               }
+
+               mutex_unlock(dapm_mutex);
+
+       } else {
+               /* This disable sequence will be a noop if already enabled */
+               mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+               ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
+                               ret);
+                       mutex_unlock(dapm_mutex);
+                       return;
+               }
+
+               ret = snd_soc_dapm_sync(arizona->dapm);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
+                               ret);
+                       mutex_unlock(dapm_mutex);
+                       return;
+               }
+
+               mutex_unlock(dapm_mutex);
+
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_HAPTICS_CONTROL_1,
+                                        ARIZONA_HAP_CTRL_MASK,
+                                        1 << ARIZONA_HAP_CTRL_SHIFT);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to stop haptics: %d\n",
+                               ret);
+                       return;
+               }
+       }
+}
+
+static int arizona_haptics_play(struct input_dev *input, void *data,
+                               struct ff_effect *effect)
+{
+       struct arizona_haptics *haptics = input_get_drvdata(input);
+       struct arizona *arizona = haptics->arizona;
+
+       if (!arizona->dapm) {
+               dev_err(arizona->dev, "No DAPM context\n");
+               return -EBUSY;
+       }
+
+       if (effect->u.rumble.strong_magnitude) {
+               /* Scale the magnitude into the range the device supports */
+               if (arizona->pdata.hap_act) {
+                       haptics->intensity =
+                               effect->u.rumble.strong_magnitude >> 9;
+                       if (effect->direction < 0x8000)
+                               haptics->intensity += 0x7f;
+               } else {
+                       haptics->intensity =
+                               effect->u.rumble.strong_magnitude >> 8;
+               }
+       } else {
+               haptics->intensity = 0;
+       }
+
+       schedule_work(&haptics->work);
+
+       return 0;
+}
+
+static void arizona_haptics_close(struct input_dev *input)
+{
+       struct arizona_haptics *haptics = input_get_drvdata(input);
+       struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex;
+
+       cancel_work_sync(&haptics->work);
+
+       mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       if (haptics->arizona->dapm)
+               snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
+
+       mutex_unlock(dapm_mutex);
+}
+
+static int arizona_haptics_probe(struct platform_device *pdev)
+{
+       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+       struct arizona_haptics *haptics;
+       int ret;
+
+       haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL);
+       if (!haptics)
+               return -ENOMEM;
+
+       haptics->arizona = arizona;
+
+       ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1,
+                                ARIZONA_HAP_ACT, arizona->pdata.hap_act);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to set haptics actuator: %d\n",
+                       ret);
+               return ret;
+       }
+
+       INIT_WORK(&haptics->work, arizona_haptics_work);
+
+       haptics->input_dev = input_allocate_device();
+       if (haptics->input_dev == NULL) {
+               dev_err(arizona->dev, "Failed to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       input_set_drvdata(haptics->input_dev, haptics);
+
+       haptics->input_dev->name = "arizona:haptics";
+       haptics->input_dev->dev.parent = pdev->dev.parent;
+       haptics->input_dev->close = arizona_haptics_close;
+       __set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
+
+       ret = input_ff_create_memless(haptics->input_dev, NULL,
+                                     arizona_haptics_play);
+       if (ret < 0) {
+               dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
+                       ret);
+               goto err_ialloc;
+       }
+
+       ret = input_register_device(haptics->input_dev);
+       if (ret < 0) {
+               dev_err(arizona->dev, "couldn't register input device: %d\n",
+                       ret);
+               goto err_iff;
+       }
+
+       platform_set_drvdata(pdev, haptics);
+
+       return 0;
+
+err_iff:
+       if (haptics->input_dev)
+               input_ff_destroy(haptics->input_dev);
+err_ialloc:
+       input_free_device(haptics->input_dev);
+
+       return ret;
+}
+
+static int arizona_haptics_remove(struct platform_device *pdev)
+{
+       struct arizona_haptics *haptics = platform_get_drvdata(pdev);
+
+       input_unregister_device(haptics->input_dev);
+
+       return 0;
+}
+
+static struct platform_driver arizona_haptics_driver = {
+       .probe          = arizona_haptics_probe,
+       .remove         = arizona_haptics_remove,
+       .driver         = {
+               .name   = "arizona-haptics",
+               .owner  = THIS_MODULE,
+       },
+};
+module_platform_driver(arizona_haptics_driver);
+
+MODULE_ALIAS("platform:arizona-haptics");
+MODULE_DESCRIPTION("Arizona haptics driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 1b48f2094806c75fa8914657978f1b7bf814ae93..75619711a9e7904000f89b30769a084b4094a27a 100644 (file)
@@ -272,6 +272,7 @@ static struct mfd_cell early_devs[] = {
 static struct mfd_cell wm5102_devs[] = {
        { .name = "arizona-extcon" },
        { .name = "arizona-gpio" },
+       { .name = "arizona-haptics" },
        { .name = "arizona-micsupp" },
        { .name = "arizona-pwm" },
        { .name = "wm5102-codec" },
@@ -280,6 +281,7 @@ static struct mfd_cell wm5102_devs[] = {
 static struct mfd_cell wm5110_devs[] = {
        { .name = "arizona-extcon" },
        { .name = "arizona-gpio" },
+       { .name = "arizona-haptics" },
        { .name = "arizona-micsupp" },
        { .name = "arizona-pwm" },
        { .name = "wm5110-codec" },
index 8fefc961ec0663ef4d8147e52058c942bb94a2df..45a20c573aa3d50ae026470fe53f65aeb1e71b37 100644 (file)
@@ -401,13 +401,19 @@ static const __devinitconst struct reg_default wm1811_reva_patch[] = {
  */
 static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
 {
-       struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+       struct wm8994_pdata *pdata;
        struct regmap_config *regmap_config;
        const struct reg_default *regmap_patch = NULL;
        const char *devname;
        int ret, i, patch_regs;
        int pulls = 0;
 
+       if (dev_get_platdata(wm8994->dev)) {
+               pdata = dev_get_platdata(wm8994->dev);
+               wm8994->pdata = *pdata;
+       }
+       pdata = &wm8994->pdata;
+
        dev_set_drvdata(wm8994->dev, wm8994);
 
        /* Add the on-chip regulators first for bootstrapping */
@@ -604,24 +610,21 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
                }
        }
 
-       if (pdata) {
-               wm8994->irq_base = pdata->irq_base;
-               wm8994->gpio_base = pdata->gpio_base;
-
-               /* GPIO configuration is only applied if it's non-zero */
-               for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
-                       if (pdata->gpio_defaults[i]) {
-                               wm8994_set_bits(wm8994, WM8994_GPIO_1 + i,
-                                               0xffff,
-                                               pdata->gpio_defaults[i]);
-                       }
+       wm8994->irq_base = pdata->irq_base;
+       wm8994->gpio_base = pdata->gpio_base;
+
+       /* GPIO configuration is only applied if it's non-zero */
+       for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
+               if (pdata->gpio_defaults[i]) {
+                       wm8994_set_bits(wm8994, WM8994_GPIO_1 + i,
+                                       0xffff, pdata->gpio_defaults[i]);
                }
+       }
 
-               wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
+       wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
 
-               if (pdata->spkmode_pu)
-                       pulls |= WM8994_SPKMODE_PU;
-       }
+       if (pdata->spkmode_pu)
+               pulls |= WM8994_SPKMODE_PU;
 
        /* Disable unneeded pulls */
        wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
index 5bb1877810749da2581aff03c6d7d50c18b875c3..d07a9eda7fff4a29aebc43892658b339b4ebb196 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 
+#include <linux/of.h>
+
 /* Serialize access to ssc_list and user count */
 static DEFINE_SPINLOCK(user_lock);
 static LIST_HEAD(ssc_list);
@@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
 
        spin_lock(&user_lock);
        list_for_each_entry(ssc, &ssc_list, list) {
-               if (ssc->pdev->id == ssc_num) {
+               if (ssc->pdev->dev.of_node) {
+                       if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc")
+                               == ssc_num) {
+                               ssc_valid = 1;
+                               break;
+                       }
+               } else if (ssc->pdev->id == ssc_num) {
                        ssc_valid = 1;
                        break;
                }
@@ -68,39 +76,93 @@ void ssc_free(struct ssc_device *ssc)
 }
 EXPORT_SYMBOL(ssc_free);
 
-static int __init ssc_probe(struct platform_device *pdev)
+static struct atmel_ssc_platform_data at91rm9200_config = {
+       .use_dma = 0,
+};
+
+static struct atmel_ssc_platform_data at91sam9g45_config = {
+       .use_dma = 1,
+};
+
+static const struct platform_device_id atmel_ssc_devtypes[] = {
+       {
+               .name = "at91rm9200_ssc",
+               .driver_data = (unsigned long) &at91rm9200_config,
+       }, {
+               .name = "at91sam9g45_ssc",
+               .driver_data = (unsigned long) &at91sam9g45_config,
+       }, {
+               /* sentinel */
+       }
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ssc_dt_ids[] = {
+       {
+               .compatible = "atmel,at91rm9200-ssc",
+               .data = &at91rm9200_config,
+       }, {
+               .compatible = "atmel,at91sam9g45-ssc",
+               .data = &at91sam9g45_config,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids);
+#endif
+
+static inline const struct atmel_ssc_platform_data * __init
+       atmel_ssc_get_driver_data(struct platform_device *pdev)
+{
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(atmel_ssc_dt_ids, pdev->dev.of_node);
+               if (match == NULL)
+                       return NULL;
+               return match->data;
+       }
+
+       return (struct atmel_ssc_platform_data *)
+               platform_get_device_id(pdev)->driver_data;
+}
+
+static int ssc_probe(struct platform_device *pdev)
 {
-       int retval = 0;
        struct resource *regs;
        struct ssc_device *ssc;
+       const struct atmel_ssc_platform_data *plat_dat;
 
-       ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL);
+       ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL);
        if (!ssc) {
                dev_dbg(&pdev->dev, "out of memory\n");
-               retval = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
 
+       ssc->pdev = pdev;
+
+       plat_dat = atmel_ssc_get_driver_data(pdev);
+       if (!plat_dat)
+               return -ENODEV;
+       ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat;
+
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs) {
                dev_dbg(&pdev->dev, "no mmio resource defined\n");
-               retval = -ENXIO;
-               goto out_free;
+               return -ENXIO;
        }
 
-       ssc->clk = clk_get(&pdev->dev, "pclk");
-       if (IS_ERR(ssc->clk)) {
-               dev_dbg(&pdev->dev, "no pclk clock defined\n");
-               retval = -ENXIO;
-               goto out_free;
-       }
-
-       ssc->pdev = pdev;
-       ssc->regs = ioremap(regs->start, resource_size(regs));
+       ssc->regs = devm_request_and_ioremap(&pdev->dev, regs);
        if (!ssc->regs) {
                dev_dbg(&pdev->dev, "ioremap failed\n");
-               retval = -EINVAL;
-               goto out_clk;
+               return -EINVAL;
+       }
+
+       ssc->phybase = regs->start;
+
+       ssc->clk = devm_clk_get(&pdev->dev, "pclk");
+       if (IS_ERR(ssc->clk)) {
+               dev_dbg(&pdev->dev, "no pclk clock defined\n");
+               return -ENXIO;
        }
 
        /* disable all interrupts */
@@ -112,8 +174,7 @@ static int __init ssc_probe(struct platform_device *pdev)
        ssc->irq = platform_get_irq(pdev, 0);
        if (!ssc->irq) {
                dev_dbg(&pdev->dev, "could not get irq\n");
-               retval = -ENXIO;
-               goto out_unmap;
+               return -ENXIO;
        }
 
        spin_lock(&user_lock);
@@ -125,16 +186,7 @@ static int __init ssc_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n",
                        ssc->regs, ssc->irq);
 
-       goto out;
-
-out_unmap:
-       iounmap(ssc->regs);
-out_clk:
-       clk_put(ssc->clk);
-out_free:
-       kfree(ssc);
-out:
-       return retval;
+       return 0;
 }
 
 static int __devexit ssc_remove(struct platform_device *pdev)
@@ -142,34 +194,23 @@ static int __devexit ssc_remove(struct platform_device *pdev)
        struct ssc_device *ssc = platform_get_drvdata(pdev);
 
        spin_lock(&user_lock);
-       iounmap(ssc->regs);
-       clk_put(ssc->clk);
        list_del(&ssc->list);
-       kfree(ssc);
        spin_unlock(&user_lock);
 
        return 0;
 }
 
 static struct platform_driver ssc_driver = {
-       .remove         = __devexit_p(ssc_remove),
        .driver         = {
                .name           = "ssc",
                .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_ssc_dt_ids),
        },
+       .id_table       = atmel_ssc_devtypes,
+       .probe          = ssc_probe,
+       .remove         = __devexit_p(ssc_remove),
 };
-
-static int __init ssc_init(void)
-{
-       return platform_driver_probe(&ssc_driver, ssc_probe);
-}
-module_init(ssc_init);
-
-static void __exit ssc_exit(void)
-{
-       platform_driver_unregister(&ssc_driver);
-}
-module_exit(ssc_exit);
+module_platform_driver(ssc_driver);
 
 MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
 MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91");
index 4eb31752e2b77592e8a2fdbf3fde779d4851504d..deb0ae58b99bb3724bee4376b0a376b563c29cff 100644 (file)
@@ -5,10 +5,16 @@
 #include <linux/list.h>
 #include <linux/io.h>
 
+struct atmel_ssc_platform_data {
+       int                     use_dma;
+};
+
 struct ssc_device {
        struct list_head        list;
+       resource_size_t         phybase;
        void __iomem            *regs;
        struct platform_device  *pdev;
+       struct atmel_ssc_platform_data *pdata;
        struct clk              *clk;
        int                     user;
        int                     irq;
index dd231ac0bb1fd8ac678d475404bc95ebaa104cec..a580363a7d29723e6656cbed8d9d94b4b1801bea 100644 (file)
@@ -78,6 +78,8 @@ enum arizona_type {
 
 #define ARIZONA_NUM_IRQ                   50
 
+struct snd_soc_dapm_context;
+
 struct arizona {
        struct regmap *regmap;
        struct device *dev;
@@ -98,6 +100,8 @@ struct arizona {
 
        struct mutex clk_lock;
        int clk32k_ref;
+
+       struct snd_soc_dapm_context *dapm;
 };
 
 int arizona_clk32k_enable(struct arizona *arizona);
index 7ab442905a57b209b10c042cf141ac2b2ba2275e..8b1d1daaae16c27e59d037f46899a1f6c631acc4 100644 (file)
@@ -62,6 +62,9 @@
 
 #define ARIZONA_MAX_OUTPUT 6
 
+#define ARIZONA_HAP_ACT_ERM 0
+#define ARIZONA_HAP_ACT_LRA 2
+
 #define ARIZONA_MAX_PDM_SPK 2
 
 struct regulator_init_data;
@@ -114,6 +117,9 @@ struct arizona_pdata {
 
        /** PDM speaker format */
        unsigned int spk_fmt[ARIZONA_MAX_PDM_SPK];
+
+       /** Haptic actuator type */
+       unsigned int hap_act;
 };
 
 #endif
index 1f173306bf0508ddeb3a18de8175fac44c857ee3..ae5c249530b4e7f527a22f44e242d4d4bce66419 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/interrupt.h>
 #include <linux/regmap.h>
 
+#include <linux/mfd/wm8994/pdata.h>
+
 enum wm8994_type {
        WM8994 = 0,
        WM8958 = 1,
@@ -55,6 +57,8 @@ struct regulator_bulk_data;
 struct wm8994 {
        struct mutex irq_lock;
 
+       struct wm8994_pdata pdata;
+
        enum wm8994_type type;
        int revision;
        int cust_id;
index fc87be4fdc2501a8106b18664102c793ccdb588b..8e21a094836d21566bec6f08c027ad5c765fa715 100644 (file)
@@ -176,6 +176,11 @@ struct wm8994_pdata {
         unsigned int lineout1fb:1;
         unsigned int lineout2fb:1;
 
+       /* Delay between detecting a jack and starting microphone
+        * detect (specified in ms)
+        */
+       int micdet_delay;
+
        /* IRQ for microphone detection if brought out directly as a
         * signal.
         */
index aa9875f77c40489527279342ca8b1d1da89866c4..88272591a8951d09fb18d8b7967ed3e885ca8855 100644 (file)
@@ -38,12 +38,6 @@ struct samsung_i2s {
 #define QUIRK_NEED_RSTCLR      (1 << 3)
        /* Quirks of the I2S controller */
        u32 quirks;
-
-       /*
-        * Array of clock names that can be used to generate I2S signals.
-        * Also corresponds to clocks of I2SMOD[10]
-        */
-       const char **src_clk;
        dma_addr_t idma_addr;
 };
 
index d0c5825876f8a2d1d124a3d51fac880951a63b2f..8db5ae03b6e3f679c16988e492e8241f1567b2f5 100644 (file)
 #ifndef __DAVINCI_ASP_H
 #define __DAVINCI_ASP_H
 
+#include <linux/genalloc.h>
+
 struct snd_platform_data {
        u32 tx_dma_offset;
        u32 rx_dma_offset;
        int asp_chan_q; /* event queue number for ASP channel */
        int ram_chan_q; /* event queue number for RAM channel */
-       unsigned int codec_fmt;
        /*
         * Allowing this is more efficient and eliminates left and right swaps
         * caused by underruns, but will swap the left and right channels
@@ -30,6 +31,7 @@ struct snd_platform_data {
        unsigned enable_channel_combine:1;
        unsigned sram_size_playback;
        unsigned sram_size_capture;
+       struct gen_pool *sram_pool;
 
        /*
         * If McBSP peripheral gets the clock from an external pin,
index c7bef788daabd14735d053e5c8ad680b247e11f1..ee60ef79d79270262bfb1992f4f7695f422323fc 100644 (file)
 #ifndef _OMAP_TWL4030_H_
 #define _OMAP_TWL4030_H_
 
+/* To select if only one channel is connected in a stereo port */
+#define OMAP_TWL4030_LEFT      (1 << 0)
+#define OMAP_TWL4030_RIGHT     (1 << 1)
+
 struct omap_tw4030_pdata {
        const char *card_name;
+       /* Voice port is connected to McBSP3 */
+       bool voice_connected;
+
+       /* The driver will parse the connection flags if this flag is set */
+       bool    custom_routing;
+       /* Flags to indicate connected audio ports. */
+       u8      has_hs;
+       u8      has_hf;
+       u8      has_predriv;
+       u8      has_carkit;
+       bool    has_ear;
+
+       bool    has_mainmic;
+       bool    has_submic;
+       bool    has_hsmic;
+       bool    has_carkitmic;
+       bool    has_digimic0;
+       bool    has_digimic1;
+       u8      has_linein;
+
+       /* Jack detect GPIO or  <= 0 if it is not implemented */
+       int jack_detect;
 };
 
 #endif /* _OMAP_TWL4030_H_ */
index e3bcc3f4dcb8426c4e5e487016417e0e43113666..9f228d7f7ac48da7e8875a816a73b505686a586c 100644 (file)
@@ -133,7 +133,7 @@ struct regmap_config {
        enum regmap_endian val_format_endian;
 
        const struct regmap_range_cfg *ranges;
-       unsigned int n_ranges;
+       unsigned int num_ranges;
 };
 
 /**
@@ -142,6 +142,8 @@ struct regmap_config {
  *     1. page selector register update;
  *     2. access through data window registers.
  *
+ * @name: Descriptive name for diagnostics
+ *
  * @range_min: Address of the lowest register address in virtual range.
  * @range_max: Address of the highest register in virtual range.
  *
@@ -153,6 +155,8 @@ struct regmap_config {
  * @window_len: Number of registers in data window.
  */
 struct regmap_range_cfg {
+       const char *name;
+
        /* Registers of virtual address range */
        unsigned int range_min;
        unsigned int range_max;
index 50a059e7d11616d4eb836cf7f0cc738cc0eaed3f..6d9e15ed1dcf0cb2875a10ca6795b14f3d4e0c51 100644 (file)
@@ -19,6 +19,7 @@
 
 struct cs4271_platform_data {
        int gpio_nreset;        /* GPIO driving Reset pin, if any */
+       int amutec_eq_bmutec:1; /* flag to enable AMUTEC=BMUTEC */
 };
 
 #endif /* __CS4271_H */
index 906010344dd7e0a227449f674d64b00a07dc1e86..cc1c919c64365898c47f7f6871b906dce0e5e1d4 100644 (file)
@@ -26,6 +26,7 @@
  * A:  inversion
  * B:  format mode
  * C:  chip specific
+ * D:  clock selecter if master mode
  */
 
 /* A: clock inversion */
 #define SH_FSI_OPTION_MASK     0x00000F00
 #define SH_FSI_ENABLE_STREAM_MODE      (1 << 8) /* for 16bit data */
 
+/* D:  clock selecter if master mode */
+#define SH_FSI_CLK_MASK                0x0000F000
+#define SH_FSI_CLK_EXTERNAL    (0 << 12)
+#define SH_FSI_CLK_CPG         (1 << 12) /* FSIxCK + FSI-DIV */
+
 /*
  * set_rate return value
  *
index c009f70b40293a70fa4b54afeb8fb4b879cac449..24e5d991f148be2d8b16cc309e1af7dca5f5f14b 100644 (file)
@@ -26,6 +26,7 @@ struct aic32x4_pdata {
        u32 power_cfg;
        u32 micpga_routing;
        bool swapdacs;
+       int rstn_gpio;
 };
 
 #endif
index 72b09cfd3dc367d4aa28826e750e27aa2ffb1885..d1b691bf8e2d918cb3e8fd97e61cce74c464cd76 100644 (file)
@@ -6,6 +6,14 @@ config SND_ATMEL_SOC
          the ATMEL SSC interface. You will also need
          to select the audio interfaces to support below.
 
+config SND_ATMEL_SOC_PDC
+       tristate
+       depends on SND_ATMEL_SOC
+
+config SND_ATMEL_SOC_DMA
+       tristate
+       depends on SND_ATMEL_SOC
+
 config SND_ATMEL_SOC_SSC
        tristate
        depends on SND_ATMEL_SOC
@@ -16,8 +24,8 @@ config SND_ATMEL_SOC_SSC
 
 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 && \
-                   AT91_PROGRAMMABLE_CLOCKS
+       depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
+       select SND_ATMEL_SOC_PDC
        select SND_ATMEL_SOC_SSC
        select SND_SOC_WM8731
        help
@@ -27,6 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
 config SND_AT91_SOC_AFEB9260
        tristate "SoC Audio support for AFEB9260 board"
        depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
+       select SND_ATMEL_SOC_PDC
        select SND_ATMEL_SOC_SSC
        select SND_SOC_TLV320AIC23
        help
index a5c0bf19da78f01e823fc614c61528c30272a67c..41967ccb6f41e3968753d4922ad03f2439ad81b9 100644 (file)
@@ -1,8 +1,12 @@
 # AT91 Platform Support
 snd-soc-atmel-pcm-objs := atmel-pcm.o
+snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
+snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.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_PDC) += snd-soc-atmel-pcm-pdc.o
+obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
 obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
 
 # AT91 Machine Support
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
new file mode 100644 (file)
index 0000000..30184a4
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * atmel-pcm-dma.c  --  ALSA PCM DMA support for the Atmel SoC.
+ *
+ *  Copyright (C) 2012 Atmel
+ *
+ * Author: Bo Shen <voice.shen@atmel.com>
+ *
+ * Based on atmel-pcm by:
+ * Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ * Copyright 2008 Atmel
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/atmel-ssc.h>
+#include <linux/platform_data/dma-atmel.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "atmel-pcm.h"
+
+/*--------------------------------------------------------------------------*\
+ * Hardware definition
+\*--------------------------------------------------------------------------*/
+static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_PAUSE,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .period_bytes_min       = 256,          /* lighting DMA overhead */
+       .period_bytes_max       = 2 * 0xffff,   /* if 2 bytes format */
+       .periods_min            = 8,
+       .periods_max            = 1024,         /* no limit */
+       .buffer_bytes_max       = ATMEL_SSC_DMABUF_SIZE,
+};
+
+/**
+ * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC
+ *
+ * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to
+ * check if any overrun occured.
+ */
+static void atmel_pcm_dma_irq(u32 ssc_sr,
+       struct snd_pcm_substream *substream)
+{
+       struct atmel_pcm_dma_params *prtd;
+
+       prtd = snd_dmaengine_pcm_get_data(substream);
+
+       if (ssc_sr & prtd->mask->ssc_error) {
+               if (snd_pcm_running(substream))
+                       pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x)\n",
+                               substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+                               ? "underrun" : "overrun", prtd->name,
+                               ssc_sr);
+
+               /* stop RX and capture: will be enabled again at restart */
+               ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable);
+               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+
+               /* now drain RHR and read status to remove xrun condition */
+               ssc_readx(prtd->ssc->regs, SSC_RHR);
+               ssc_readx(prtd->ssc->regs, SSC_SR);
+       }
+}
+
+/*--------------------------------------------------------------------------*\
+ * DMAENGINE operations
+\*--------------------------------------------------------------------------*/
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct at_dma_slave *sl = slave;
+
+       if (sl->dma_dev == chan->device->dev) {
+               chan->private = sl;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct atmel_pcm_dma_params *prtd;
+       struct ssc_device *ssc;
+       struct dma_chan *dma_chan;
+       struct dma_slave_config slave_config;
+       int ret;
+
+       prtd = snd_dmaengine_pcm_get_data(substream);
+       ssc = prtd->ssc;
+
+       ret = snd_hwparams_to_dma_slave_config(substream, params,
+                       &slave_config);
+       if (ret) {
+               pr_err("atmel-pcm: hwparams to dma slave configure failed\n");
+               return ret;
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR;
+               slave_config.dst_maxburst = 1;
+       } else {
+               slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR;
+               slave_config.src_maxburst = 1;
+       }
+
+       slave_config.device_fc = false;
+
+       dma_chan = snd_dmaengine_pcm_get_chan(substream);
+       if (dmaengine_slave_config(dma_chan, &slave_config)) {
+               pr_err("atmel-pcm: failed to configure dma channel\n");
+               ret = -EBUSY;
+               return ret;
+       }
+
+       return 0;
+}
+
+static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pcm_dma_params *prtd;
+       struct ssc_device *ssc;
+       struct at_dma_slave *sdata = NULL;
+       int ret;
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       ssc = prtd->ssc;
+       if (ssc->pdev)
+               sdata = ssc->pdev->dev.platform_data;
+
+       ret = snd_dmaengine_pcm_open(substream, filter, sdata);
+       if (ret) {
+               pr_err("atmel-pcm: dmaengine pcm open failed\n");
+               return -EINVAL;
+       }
+
+       snd_dmaengine_pcm_set_data(substream, prtd);
+
+       ret = atmel_pcm_configure_dma(substream, params);
+       if (ret) {
+               pr_err("atmel-pcm: failed to configure dmai\n");
+               goto err;
+       }
+
+       prtd->dma_intr_handler = atmel_pcm_dma_irq;
+
+       return 0;
+err:
+       snd_dmaengine_pcm_close(substream);
+       return ret;
+}
+
+static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
+{
+       struct atmel_pcm_dma_params *prtd;
+
+       prtd = snd_dmaengine_pcm_get_data(substream);
+
+       ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
+       ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
+
+       return 0;
+}
+
+static int atmel_pcm_open(struct snd_pcm_substream *substream)
+{
+       snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware);
+
+       return 0;
+}
+
+static int atmel_pcm_close(struct snd_pcm_substream *substream)
+{
+       snd_dmaengine_pcm_close(substream);
+
+       return 0;
+}
+
+static 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,
+       .prepare        = atmel_pcm_dma_prepare,
+       .trigger        = snd_dmaengine_pcm_trigger,
+       .pointer        = snd_dmaengine_pcm_pointer_no_residue,
+       .mmap           = atmel_pcm_mmap,
+};
+
+static struct snd_soc_platform_driver atmel_soc_platform = {
+       .ops            = &atmel_pcm_ops,
+       .pcm_new        = atmel_pcm_new,
+       .pcm_free       = atmel_pcm_free,
+};
+
+int atmel_pcm_dma_platform_register(struct device *dev)
+{
+       return snd_soc_register_platform(dev, &atmel_soc_platform);
+}
+EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
+
+void atmel_pcm_dma_platform_unregister(struct device *dev)
+{
+       snd_soc_unregister_platform(dev);
+}
+EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister);
+
+MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
+MODULE_DESCRIPTION("Atmel DMA based PCM module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
new file mode 100644 (file)
index 0000000..6a293c7
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * atmel-pcm.c  --  ALSA PCM interface for the Atmel atmel 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
+ */
+
+#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 <linux/atmel-ssc.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "atmel-pcm.h"
+
+
+/*--------------------------------------------------------------------------*\
+ * Hardware definition
+\*--------------------------------------------------------------------------*/
+/* TODO: These values were taken from the AT91 platform driver, check
+ *      them against real values for AT32
+ */
+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       = ATMEL_SSC_DMABUF_SIZE,
+};
+
+
+/*--------------------------------------------------------------------------*\
+ * Data types
+\*--------------------------------------------------------------------------*/
+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 */
+
+       /* PDC register save */
+       u32 pdc_xpr_save;
+       u32 pdc_xcr_save;
+       u32 pdc_xnpr_save;
+       u32 pdc_xncr_save;
+};
+
+/*--------------------------------------------------------------------------*\
+ * ISR
+\*--------------------------------------------------------------------------*/
+static void atmel_pcm_dma_irq(u32 ssc_sr,
+       struct snd_pcm_substream *substream)
+{
+       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_warn("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,
+                          params->mask->pdc_disable);
+               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->xpr,
+                          prtd->period_ptr);
+               ssc_writex(params->ssc->regs, params->pdc->xcr,
+                          prtd->period_size / params->pdc_xfer_size);
+               ssc_writex(params->ssc->regs, 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;
+
+               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 atmel_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       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 */
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       runtime->dma_bytes = params_buffer_bytes(params);
+
+       prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       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("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 atmel_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       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,
+                          params->mask->pdc_disable);
+               prtd->params->dma_intr_handler = NULL;
+       }
+
+       return 0;
+}
+
+static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       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 atmel_pcm_trigger(struct snd_pcm_substream *substream,
+       int cmd)
+{
+       struct snd_pcm_runtime *rtd = substream->runtime;
+       struct atmel_runtime_data *prtd = rtd->private_data;
+       struct atmel_pcm_dma_params *params = prtd->params;
+       int ret = 0;
+
+       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:
+               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,
+                          prtd->period_size / params->pdc_xfer_size);
+
+               prtd->period_ptr += prtd->period_size;
+               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);
+
+               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=%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:
+               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+                          params->mask->pdc_disable);
+               break;
+
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+                          params->mask->pdc_enable);
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static snd_pcm_uframes_t atmel_pcm_pointer(
+       struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       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;
+
+       ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
+       x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
+
+       if (x == runtime->buffer_size)
+               x = 0;
+
+       return x;
+}
+
+static int atmel_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct atmel_runtime_data *prtd;
+       int ret = 0;
+
+       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);
+       if (ret < 0)
+               goto out;
+
+       prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL);
+       if (prtd == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       runtime->private_data = prtd;
+
+ out:
+       return ret;
+}
+
+static int atmel_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct atmel_runtime_data *prtd = substream->runtime->private_data;
+
+       kfree(prtd);
+       return 0;
+}
+
+static 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
+\*--------------------------------------------------------------------------*/
+#ifdef CONFIG_PM
+static int atmel_pcm_suspend(struct snd_soc_dai *dai)
+{
+       struct snd_pcm_runtime *runtime = dai->runtime;
+       struct atmel_runtime_data *prtd;
+       struct atmel_pcm_dma_params *params;
+
+       if (!runtime)
+               return 0;
+
+       prtd = runtime->private_data;
+       params = prtd->params;
+
+       /* disable the PDC and save the PDC registers */
+
+       ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
+
+       prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
+       prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
+       prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
+       prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
+
+       return 0;
+}
+
+static int atmel_pcm_resume(struct snd_soc_dai *dai)
+{
+       struct snd_pcm_runtime *runtime = dai->runtime;
+       struct atmel_runtime_data *prtd;
+       struct atmel_pcm_dma_params *params;
+
+       if (!runtime)
+               return 0;
+
+       prtd = runtime->private_data;
+       params = prtd->params;
+
+       /* restore the PDC registers and enable the PDC */
+       ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
+       ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
+       ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
+       ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
+
+       ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
+       return 0;
+}
+#else
+#define atmel_pcm_suspend      NULL
+#define atmel_pcm_resume       NULL
+#endif
+
+static struct snd_soc_platform_driver atmel_soc_platform = {
+       .ops            = &atmel_pcm_ops,
+       .pcm_new        = atmel_pcm_new,
+       .pcm_free       = atmel_pcm_free,
+       .suspend        = atmel_pcm_suspend,
+       .resume         = atmel_pcm_resume,
+};
+
+int atmel_pcm_pdc_platform_register(struct device *dev)
+{
+       return snd_soc_register_platform(dev, &atmel_soc_platform);
+}
+EXPORT_SYMBOL(atmel_pcm_pdc_platform_register);
+
+void atmel_pcm_pdc_platform_unregister(struct device *dev)
+{
+       snd_soc_unregister_platform(dev);
+}
+EXPORT_SYMBOL(atmel_pcm_pdc_platform_unregister);
+
+MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
+MODULE_DESCRIPTION("Atmel PCM module");
+MODULE_LICENSE("GPL");
index 9b84f985770ee4e09ca1d7a8ab04cbe410fda037..e99f1811300aef179a5c1d5c33dc702249175681 100644 (file)
  */
 
 #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 <linux/atmel-ssc.h>
-
-#include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
-
 #include "atmel-pcm.h"
 
-
-/*--------------------------------------------------------------------------*\
- * Hardware definition
-\*--------------------------------------------------------------------------*/
-/* TODO: These values were taken from the AT91 platform driver, check
- *      them against real values for AT32
- */
-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 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 */
-
-       /* PDC register save */
-       u32 pdc_xpr_save;
-       u32 pdc_xcr_save;
-       u32 pdc_xnpr_save;
-       u32 pdc_xncr_save;
-};
-
-
-/*--------------------------------------------------------------------------*\
- * Helper functions
-\*--------------------------------------------------------------------------*/
 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 *buf = &substream->dma_buffer;
-       size_t size = atmel_pcm_hardware.buffer_bytes_max;
+       size_t size = ATMEL_SSC_DMABUF_SIZE;
 
        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);
+                       &buf->addr, GFP_KERNEL);
+       pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n",
+                       (void *)buf->area, (void *)buf->addr, size);
 
        if (!buf->area)
                return -ENOMEM;
@@ -113,258 +58,19 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
        buf->bytes = size;
        return 0;
 }
-/*--------------------------------------------------------------------------*\
- * ISR
-\*--------------------------------------------------------------------------*/
-static void atmel_pcm_dma_irq(u32 ssc_sr,
-       struct snd_pcm_substream *substream)
-{
-       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("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,
-                          params->mask->pdc_disable);
-               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->xpr,
-                          prtd->period_ptr);
-               ssc_writex(params->ssc->regs, params->pdc->xcr,
-                          prtd->period_size / params->pdc_xfer_size);
-               ssc_writex(params->ssc->regs, 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;
-
-               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 atmel_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       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 */
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = params_buffer_bytes(params);
-
-       prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       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("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 atmel_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       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,
-                          params->mask->pdc_disable);
-               prtd->params->dma_intr_handler = NULL;
-       }
-
-       return 0;
-}
-
-static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       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 atmel_pcm_trigger(struct snd_pcm_substream *substream,
-       int cmd)
-{
-       struct snd_pcm_runtime *rtd = substream->runtime;
-       struct atmel_runtime_data *prtd = rtd->private_data;
-       struct atmel_pcm_dma_params *params = prtd->params;
-       int ret = 0;
-
-       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:
-               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,
-                          prtd->period_size / params->pdc_xfer_size);
-
-               prtd->period_ptr += prtd->period_size;
-               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);
-
-               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=%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:
-               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-                          params->mask->pdc_disable);
-               break;
-
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-                          params->mask->pdc_enable);
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
 
-       return ret;
-}
-
-static snd_pcm_uframes_t atmel_pcm_pointer(
-       struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       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;
-
-       ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
-       x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
-
-       if (x == runtime->buffer_size)
-               x = 0;
-
-       return x;
-}
-
-static int atmel_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct atmel_runtime_data *prtd;
-       int ret = 0;
-
-       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);
-       if (ret < 0)
-               goto out;
-
-       prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL);
-       if (prtd == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       runtime->private_data = prtd;
-
- out:
-       return ret;
-}
-
-static int atmel_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct atmel_runtime_data *prtd = substream->runtime->private_data;
-
-       kfree(prtd);
-       return 0;
-}
-
-static int atmel_pcm_mmap(struct snd_pcm_substream *substream,
+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);
 }
+EXPORT_SYMBOL_GPL(atmel_pcm_mmap);
 
-static 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 atmel_pcm_dmamask = DMA_BIT_MASK(32);
 
-static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
+int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
        struct snd_pcm *pcm = rtd->pcm;
@@ -376,6 +82,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
        if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+               pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
@@ -383,8 +90,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
        }
 
        if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               pr_debug("atmel-pcm:"
-                               "Allocating PCM capture DMA buffer\n");
+               pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n");
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -393,8 +99,9 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
  out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(atmel_pcm_new);
 
-static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
+void atmel_pcm_free(struct snd_pcm *pcm)
 {
        struct snd_pcm_substream *substream;
        struct snd_dma_buffer *buf;
@@ -413,89 +120,5 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
                buf->area = NULL;
        }
 }
+EXPORT_SYMBOL_GPL(atmel_pcm_free);
 
-#ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai *dai)
-{
-       struct snd_pcm_runtime *runtime = dai->runtime;
-       struct atmel_runtime_data *prtd;
-       struct atmel_pcm_dma_params *params;
-
-       if (!runtime)
-               return 0;
-
-       prtd = runtime->private_data;
-       params = prtd->params;
-
-       /* disable the PDC and save the PDC registers */
-
-       ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
-
-       prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
-       prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
-       prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
-       prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
-
-       return 0;
-}
-
-static int atmel_pcm_resume(struct snd_soc_dai *dai)
-{
-       struct snd_pcm_runtime *runtime = dai->runtime;
-       struct atmel_runtime_data *prtd;
-       struct atmel_pcm_dma_params *params;
-
-       if (!runtime)
-               return 0;
-
-       prtd = runtime->private_data;
-       params = prtd->params;
-
-       /* restore the PDC registers and enable the PDC */
-       ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
-       ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
-       ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
-       ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
-
-       ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
-       return 0;
-}
-#else
-#define atmel_pcm_suspend      NULL
-#define atmel_pcm_resume       NULL
-#endif
-
-static struct snd_soc_platform_driver atmel_soc_platform = {
-       .ops            = &atmel_pcm_ops,
-       .pcm_new        = atmel_pcm_new,
-       .pcm_free       = atmel_pcm_free_dma_buffers,
-       .suspend        = atmel_pcm_suspend,
-       .resume         = atmel_pcm_resume,
-};
-
-static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
-}
-
-static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver atmel_pcm_driver = {
-       .driver = {
-                       .name = "atmel-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-
-       .probe = atmel_soc_platform_probe,
-       .remove = __devexit_p(atmel_soc_platform_remove),
-};
-
-module_platform_driver(atmel_pcm_driver);
-
-MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
-MODULE_DESCRIPTION("Atmel PCM module");
-MODULE_LICENSE("GPL");
index 5e0a95e643298b8f5210e7619139b48a02ae939f..bb45d20e7250aeace79a2595f5f9676349ba05d9 100644 (file)
@@ -36,6 +36,8 @@
 
 #include <linux/atmel-ssc.h>
 
+#define ATMEL_SSC_DMABUF_SIZE  (64 * 1024)
+
 /*
  * Registers and status bits that are required by the PCM driver.
  */
@@ -50,6 +52,7 @@ struct atmel_pdc_regs {
 struct atmel_ssc_mask {
        u32     ssc_enable;             /* SSC recv/trans enable */
        u32     ssc_disable;            /* SSC recv/trans disable */
+       u32     ssc_error;              /* SSC error conditions */
        u32     ssc_endx;               /* SSC ENDTX or ENDRX */
        u32     ssc_endbuf;             /* SSC TXBUFE or RXBUFF */
        u32     pdc_enable;             /* PDC recv/trans enable */
@@ -80,4 +83,35 @@ struct atmel_pcm_dma_params {
 #define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
 #define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
 
+int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd);
+void atmel_pcm_free(struct snd_pcm *pcm);
+int atmel_pcm_mmap(struct snd_pcm_substream *substream,
+               struct vm_area_struct *vma);
+
+#ifdef CONFIG_SND_ATMEL_SOC_PDC
+int atmel_pcm_pdc_platform_register(struct device *dev);
+void atmel_pcm_pdc_platform_unregister(struct device *dev);
+#else
+static inline int atmel_pcm_pdc_platform_register(struct device *dev)
+{
+       return 0;
+}
+static inline void atmel_pcm_pdc_platform_unregister(struct device *dev)
+{
+}
+#endif
+
+#ifdef CONFIG_SND_ATMEL_SOC_DMA
+int atmel_pcm_dma_platform_register(struct device *dev);
+void atmel_pcm_dma_platform_unregister(struct device *dev);
+#else
+static inline int atmel_pcm_dma_platform_register(struct device *dev)
+{
+       return 0;
+}
+static inline void atmel_pcm_dma_platform_unregister(struct device *dev)
+{
+}
+#endif
+
 #endif /* _ATMEL_PCM_H */
index 354341ec0f42f1129adbaaf310366af46b866229..1c7663422054049265957743bad8c6f8678e9e17 100644 (file)
 #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.
@@ -107,7 +103,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
        .pdc            = &pdc_rx_reg,
        .mask           = &ssc_rx_mask,
        } },
-#if NUM_SSC_DEVICES == 3
        {{
        .name           = "SSC1 PCM out",
        .pdc            = &pdc_tx_reg,
@@ -128,7 +123,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
        .pdc            = &pdc_rx_reg,
        .mask           = &ssc_rx_mask,
        } },
-#endif
 };
 
 
@@ -139,7 +133,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
        .dir_mask       = SSC_DIR_MASK_UNUSED,
        .initialized    = 0,
        },
-#if NUM_SSC_DEVICES == 3
        {
        .name           = "ssc1",
        .lock           = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
@@ -152,7 +145,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
        .dir_mask       = SSC_DIR_MASK_UNUSED,
        .initialized    = 0,
        },
-#endif
 };
 
 
@@ -690,27 +682,9 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
 static int atmel_ssc_probe(struct snd_soc_dai *dai)
 {
        struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
-       int ret = 0;
 
        snd_soc_dai_set_drvdata(dai, ssc_p);
 
-       /*
-        * Request SSC device
-        */
-       ssc_p->ssc = ssc_request(dai->id);
-       if (IS_ERR(ssc_p->ssc)) {
-               printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
-               ret = PTR_ERR(ssc_p->ssc);
-       }
-
-       return ret;
-}
-
-static int atmel_ssc_remove(struct snd_soc_dai *dai)
-{
-       struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
-
-       ssc_free(ssc_p->ssc);
        return 0;
 }
 
@@ -728,30 +702,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
        .set_clkdiv     = atmel_ssc_set_dai_clkdiv,
 };
 
-static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
-       {
-               .name = "atmel-ssc-dai.0",
-               .probe = atmel_ssc_probe,
-               .remove = atmel_ssc_remove,
-               .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 = &atmel_ssc_dai_ops,
-       },
-#if NUM_SSC_DEVICES == 3
-       {
-               .name = "atmel-ssc-dai.1",
+static struct snd_soc_dai_driver atmel_ssc_dai = {
                .probe = atmel_ssc_probe,
-               .remove = atmel_ssc_remove,
                .suspend = atmel_ssc_suspend,
                .resume = atmel_ssc_resume,
                .playback = {
@@ -765,50 +717,50 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
-       },
-       {
-               .name = "atmel-ssc-dai.2",
-               .probe = atmel_ssc_probe,
-               .remove = atmel_ssc_remove,
-               .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 = &atmel_ssc_dai_ops,
-       },
-#endif
 };
 
-static __devinit int asoc_ssc_probe(struct platform_device *pdev)
+static int asoc_ssc_init(struct device *dev)
 {
-       BUG_ON(pdev->id < 0);
-       BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
-       return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
-}
+       struct platform_device *pdev = to_platform_device(dev);
+       struct ssc_device *ssc = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = snd_soc_register_dai(dev, &atmel_ssc_dai);
+       if (ret) {
+               dev_err(dev, "Could not register DAI: %d\n", ret);
+               goto err;
+       }
+
+       if (ssc->pdata->use_dma)
+               ret = atmel_pcm_dma_platform_register(dev);
+       else
+               ret = atmel_pcm_pdc_platform_register(dev);
+
+       if (ret) {
+               dev_err(dev, "Could not register PCM: %d\n", ret);
+               goto err_unregister_dai;
+       };
 
-static int __devexit asoc_ssc_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_dai(&pdev->dev);
        return 0;
+
+err_unregister_dai:
+       snd_soc_unregister_dai(dev);
+err:
+       return ret;
 }
 
-static struct platform_driver asoc_ssc_driver = {
-       .driver = {
-                       .name = "atmel-ssc-dai",
-                       .owner = THIS_MODULE,
-       },
+static void asoc_ssc_exit(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct ssc_device *ssc = platform_get_drvdata(pdev);
 
-       .probe = asoc_ssc_probe,
-       .remove = __devexit_p(asoc_ssc_remove),
-};
+       if (ssc->pdata->use_dma)
+               atmel_pcm_dma_platform_unregister(dev);
+       else
+               atmel_pcm_pdc_platform_unregister(dev);
+
+       snd_soc_unregister_dai(dev);
+}
 
 /**
  * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
@@ -816,50 +768,32 @@ static struct platform_driver asoc_ssc_driver = {
 int atmel_ssc_set_audio(int ssc_id)
 {
        struct ssc_device *ssc;
-       static struct platform_device *dma_pdev;
-       struct platform_device *ssc_pdev;
        int ret;
 
-       if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
-               return -EINVAL;
-
-       /* Allocate a dummy device for DMA if we don't have one already */
-       if (!dma_pdev) {
-               dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
-               if (!dma_pdev)
-                       return -ENOMEM;
-
-               ret = platform_device_add(dma_pdev);
-               if (ret < 0) {
-                       platform_device_put(dma_pdev);
-                       dma_pdev = NULL;
-                       return ret;
-               }
-       }
-
-       ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
-       if (!ssc_pdev)
-               return -ENOMEM;
-
        /* If we can grab the SSC briefly to parent the DAI device off it */
        ssc = ssc_request(ssc_id);
-       if (IS_ERR(ssc))
-               pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
+       if (IS_ERR(ssc)) {
+               pr_err("Unable to parent ASoC SSC DAI on SSC: %ld\n",
                        PTR_ERR(ssc));
-       else {
-               ssc_pdev->dev.parent = &(ssc->pdev->dev);
-               ssc_free(ssc);
+               return PTR_ERR(ssc);
+       } else {
+               ssc_info[ssc_id].ssc = ssc;
        }
 
-       ret = platform_device_add(ssc_pdev);
-       if (ret < 0)
-               platform_device_put(ssc_pdev);
+       ret = asoc_ssc_init(&ssc->pdev->dev);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
 
-module_platform_driver(asoc_ssc_driver);
+void atmel_ssc_put_audio(int ssc_id)
+{
+       struct ssc_device *ssc = ssc_info[ssc_id].ssc;
+
+       ssc_free(ssc);
+       asoc_ssc_exit(&ssc->pdev->dev);
+}
+EXPORT_SYMBOL_GPL(atmel_ssc_put_audio);
 
 /* Module information */
 MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
index 5d4f0f9b4d9a875eb935ec79488b76ff17073ab0..b1f08d51149526006021c7314aa4f3e15847de3d 100644 (file)
@@ -117,6 +117,7 @@ struct atmel_ssc_info {
        struct atmel_ssc_state ssc_state;
 };
 
-int atmel_ssc_set_audio(int ssc);
+int atmel_ssc_set_audio(int ssc_id);
+void atmel_ssc_put_audio(int ssc_id);
 
 #endif /* _AT91_SSC_DAI_H */
index c88351488f45c5c6adb0529a212ab257531a90fd..0744610e53dd97201d4a5e24099aa58e337b44fc 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 
+#include <linux/pinctrl/consumer.h>
+
 #include <linux/atmel-ssc.h>
 
 #include <sound/core.h>
@@ -179,10 +181,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link at91sam9g20ek_dai = {
        .name = "WM8731",
        .stream_name = "WM8731 PCM",
-       .cpu_dai_name = "atmel-ssc-dai.0",
+       .cpu_dai_name = "at91rm9200_ssc.0",
        .codec_dai_name = "wm8731-hifi",
        .init = at91sam9g20ek_wm8731_init,
-       .platform_name = "atmel-pcm-audio",
+       .platform_name = "at91rm9200_ssc.0",
        .codec_name = "wm8731.0-001b",
        .ops = &at91sam9g20ek_ops,
 };
@@ -195,20 +197,31 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
        .set_bias_level = at91sam9g20ek_set_bias_level,
 };
 
-static struct platform_device *at91sam9g20ek_snd_device;
-
-static int __init at91sam9g20ek_init(void)
+static int __devinit at91sam9g20ek_audio_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *codec_np, *cpu_np;
        struct clk *pllb;
+       struct snd_soc_card *card = &snd_soc_at91sam9g20ek;
+       struct pinctrl *pinctrl;
        int ret;
 
-       if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
-               return -ENODEV;
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl)) {
+               dev_err(&pdev->dev, "Failed to request pinctrl for mck\n");
+               return PTR_ERR(pinctrl);
+       }
+
+       if (!np) {
+               if (!(machine_is_at91sam9g20ek() ||
+                       machine_is_at91sam9g20ek_2mmc()))
+                       return -ENODEV;
+       }
 
        ret = atmel_ssc_set_audio(0);
-       if (ret != 0) {
-               pr_err("Failed to set SSC 0 for audio: %d\n", ret);
-               return ret;
+       if (ret) {
+               dev_err(&pdev->dev, "ssc channel is not valid\n");
+               return -EINVAL;
        }
 
        /*
@@ -236,45 +249,92 @@ static int __init at91sam9g20ek_init(void)
 
        clk_set_rate(mclk, MCLK_RATE);
 
-       at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!at91sam9g20ek_snd_device) {
-               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-               ret = -ENOMEM;
-               goto err_mclk;
+       card->dev = &pdev->dev;
+
+       /* Parse device node info */
+       if (np) {
+               ret = snd_soc_of_parse_card_name(card, "atmel,model");
+               if (ret)
+                       goto err;
+
+               ret = snd_soc_of_parse_audio_routing(card,
+                       "atmel,audio-routing");
+               if (ret)
+                       goto err;
+
+               /* Parse codec info */
+               at91sam9g20ek_dai.codec_name = NULL;
+               codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+               if (!codec_np) {
+                       dev_err(&pdev->dev, "codec info missing\n");
+                       return -EINVAL;
+               }
+               at91sam9g20ek_dai.codec_of_node = codec_np;
+
+               /* Parse dai and platform info */
+               at91sam9g20ek_dai.cpu_dai_name = NULL;
+               at91sam9g20ek_dai.platform_name = NULL;
+               cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+               if (!cpu_np) {
+                       dev_err(&pdev->dev, "dai and pcm info missing\n");
+                       return -EINVAL;
+               }
+               at91sam9g20ek_dai.cpu_of_node = cpu_np;
+               at91sam9g20ek_dai.platform_of_node = cpu_np;
+
+               of_node_put(codec_np);
+               of_node_put(cpu_np);
        }
 
-       platform_set_drvdata(at91sam9g20ek_snd_device,
-                       &snd_soc_at91sam9g20ek);
-
-       ret = platform_device_add(at91sam9g20ek_snd_device);
+       ret = snd_soc_register_card(card);
        if (ret) {
-               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-               goto err_device_add;
+               printk(KERN_ERR "ASoC: snd_soc_register_card() failed\n");
        }
 
        return ret;
 
-err_device_add:
-       platform_device_put(at91sam9g20ek_snd_device);
 err_mclk:
        clk_put(mclk);
        mclk = NULL;
 err:
+       atmel_ssc_put_audio(0);
        return ret;
 }
 
-static void __exit at91sam9g20ek_exit(void)
+static int __devexit at91sam9g20ek_audio_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(at91sam9g20ek_snd_device);
-       at91sam9g20ek_snd_device = NULL;
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       atmel_ssc_put_audio(0);
+       snd_soc_unregister_card(card);
        clk_put(mclk);
        mclk = NULL;
+
+       return 0;
 }
 
-module_init(at91sam9g20ek_init);
-module_exit(at91sam9g20ek_exit);
+#ifdef CONFIG_OF
+static const struct of_device_id at91sam9g20ek_wm8731_dt_ids[] = {
+       { .compatible = "atmel,at91sam9g20ek-wm8731-audio", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, at91sam9g20ek_wm8731_dt_ids);
+#endif
+
+static struct platform_driver at91sam9g20ek_audio_driver = {
+       .driver = {
+               .name   = "at91sam9g20ek-audio",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(at91sam9g20ek_wm8731_dt_ids),
+       },
+       .probe  = at91sam9g20ek_audio_probe,
+       .remove = __devexit_p(at91sam9g20ek_audio_remove),
+};
+
+module_platform_driver(at91sam9g20ek_audio_driver);
 
 /* Module information */
 MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
 MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731");
+MODULE_ALIAS("platform:at91sam9g20ek-audio");
 MODULE_LICENSE("GPL");
index b92759a3936157e0884b98f752935ccbef7b8945..3a847828932ae01e13b2be5ca8f587c0048f17eb 100644 (file)
@@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_LM4857 if I2C
        select SND_SOC_LM49453 if I2C
        select SND_SOC_MAX98088 if I2C
+       select SND_SOC_MAX98090 if I2C
        select SND_SOC_MAX98095 if I2C
        select SND_SOC_MAX9850 if I2C
        select SND_SOC_MAX9768 if I2C
@@ -54,6 +55,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_PCM3008
        select SND_SOC_RT5631 if I2C
        select SND_SOC_SGTL5000 if I2C
+       select SND_SOC_SI476X if MFD_SI476X_CORE
        select SND_SOC_SN95031 if INTEL_SCU_IPC
        select SND_SOC_SPDIF
        select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
@@ -146,6 +148,13 @@ config SND_SOC_WM_HUBS
        default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
        default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
 
+config SND_SOC_WM_ADSP
+       tristate
+       default y if SND_SOC_WM5102=y
+       default y if SND_SOC_WM2200=y
+       default m if SND_SOC_WM5102=m
+       default m if SND_SOC_WM2200=m
+
 config SND_SOC_AB8500_CODEC
        tristate
 
@@ -229,6 +238,7 @@ config SND_SOC_CX20442
        tristate
 
 config SND_SOC_JZ4740_CODEC
+       select REGMAP_MMIO
        tristate
 
 config SND_SOC_L3
@@ -258,6 +268,9 @@ config SND_SOC_LM49453
 config SND_SOC_MAX98088
        tristate
 
+config SND_SOC_MAX98090
+       tristate
+
 config SND_SOC_MAX98095
        tristate
 
@@ -277,6 +290,9 @@ config SND_SOC_RT5631
 config SND_SOC_SGTL5000
        tristate
 
+config SND_SOC_SI476X
+       tristate
+
 config SND_SOC_SIGMADSP
        tristate
        select CRC32
index 9bd4d95aab4ffcecb9abf5bff4e0c94d7203adee..f6e8e36cceb77b60d5c34fc5bec54ece440c6653 100644 (file)
@@ -34,6 +34,7 @@ snd-soc-lm4857-objs := lm4857.o
 snd-soc-lm49453-objs := lm49453.o
 snd-soc-max9768-objs := max9768.o
 snd-soc-max98088-objs := max98088.o
+snd-soc-max98090-objs := max98090.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
@@ -45,6 +46,7 @@ snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
 snd-soc-sigmadsp-objs := sigmadsp.o
+snd-soc-si476x-objs := si476x.o
 snd-soc-sn95031-objs := sn95031.o
 snd-soc-spdif-tx-objs := spdif_transciever.o
 snd-soc-spdif-rx-objs := spdif_receiver.o
@@ -62,6 +64,7 @@ snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
@@ -155,6 +158,7 @@ obj-$(CONFIG_SND_SOC_LM4857)        += snd-soc-lm4857.o
 obj-$(CONFIG_SND_SOC_LM49453)   += snd-soc-lm49453.o
 obj-$(CONFIG_SND_SOC_MAX9768)  += snd-soc-max9768.o
 obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
 obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
@@ -164,6 +168,7 @@ obj-$(CONFIG_SND_SOC_PCM3008)       += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
+obj-$(CONFIG_SND_SOC_SI476X)   += snd-soc-si476x.o
 obj-$(CONFIG_SND_SOC_SN95031)  +=snd-soc-sn95031.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
@@ -229,6 +234,7 @@ obj-$(CONFIG_SND_SOC_WM9090)        += snd-soc-wm9090.o
 obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
+obj-$(CONFIG_SND_SOC_WM_ADSP)  += snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)  += snd-soc-wm-hubs.o
 
 # Amp
index af547490b4f7f6e0b1dbada793259c64a513a203..4d96090db66297b44b10219f21f26e768c431935 100644 (file)
@@ -2356,7 +2356,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
        return 0;
 }
 
-struct snd_soc_dai_driver ab8500_codec_dai[] = {
+static struct snd_soc_dai_driver ab8500_codec_dai[] = {
        {
                .name = "ab8500-codec-dai.0",
                .id = 0,
index 31d4483245d0db951584a0e1619b91c8ac8fa726..4b11b82b227393c5d6a60311f417c7b846976bfa 100644 (file)
@@ -15,6 +15,8 @@
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <sound/asoundef.h>
 
 /* AK4104 registers addresses */
@@ -98,14 +100,32 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
        val = 0;
 
        switch (params_rate(params)) {
+       case 22050:
+               val |= IEC958_AES3_CON_FS_22050;
+               break;
+       case 24000:
+               val |= IEC958_AES3_CON_FS_24000;
+               break;
+       case 32000:
+               val |= IEC958_AES3_CON_FS_32000;
+               break;
        case 44100:
                val |= IEC958_AES3_CON_FS_44100;
                break;
        case 48000:
                val |= IEC958_AES3_CON_FS_48000;
                break;
-       case 32000:
-               val |= IEC958_AES3_CON_FS_32000;
+       case 88200:
+               val |= IEC958_AES3_CON_FS_88200;
+               break;
+       case 96000:
+               val |= IEC958_AES3_CON_FS_96000;
+               break;
+       case 176400:
+               val |= IEC958_AES3_CON_FS_176400;
+               break;
+       case 192000:
+               val |= IEC958_AES3_CON_FS_192000;
                break;
        default:
                dev_err(codec->dev, "unsupported sampling rate\n");
@@ -186,6 +206,7 @@ static const struct regmap_config ak4104_regmap = {
 
 static int ak4104_spi_probe(struct spi_device *spi)
 {
+       struct device_node *np = spi->dev.of_node;
        struct ak4104_private *ak4104;
        unsigned int val;
        int ret;
@@ -201,49 +222,59 @@ static int ak4104_spi_probe(struct spi_device *spi)
        if (ak4104 == NULL)
                return -ENOMEM;
 
-       ak4104->regmap = regmap_init_spi(spi, &ak4104_regmap);
+       ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
        if (IS_ERR(ak4104->regmap)) {
                ret = PTR_ERR(ak4104->regmap);
                return ret;
        }
 
+       if (np) {
+               enum of_gpio_flags flags;
+               int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
+
+               if (gpio_is_valid(gpio)) {
+                       ret = devm_gpio_request_one(&spi->dev, gpio,
+                                    flags & OF_GPIO_ACTIVE_LOW ?
+                                       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+                                    "ak4104 reset");
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        /* read the 'reserved' register - according to the datasheet, it
         * should contain 0x5b. Not a good way to verify the presence of
         * the device, but there is no hardware ID register. */
        ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val);
        if (ret != 0)
-               goto err;
-       if (val != AK4104_RESERVED_VAL) {
-               ret = -ENODEV;
-               goto err;
-       }
+               return ret;
+       if (val != AK4104_RESERVED_VAL)
+               return -ENODEV;
 
        spi_set_drvdata(spi, ak4104);
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_device_ak4104, &ak4104_dai, 1);
-       if (ret != 0)
-               goto err;
-
-       return 0;
-
-err:
-       regmap_exit(ak4104->regmap);
        return ret;
 }
 
 static int __devexit ak4104_spi_remove(struct spi_device *spi)
 {
-       struct ak4104_private *ak4101 = spi_get_drvdata(spi);
-       regmap_exit(ak4101->regmap);
        snd_soc_unregister_codec(&spi->dev);
        return 0;
 }
 
+static const struct of_device_id ak4104_of_match[] = {
+       { .compatible = "asahi-kasei,ak4104", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ak4104_of_match);
+
 static struct spi_driver ak4104_spi_driver = {
        .driver  = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = ak4104_of_match,
        },
        .probe  = ak4104_spi_probe,
        .remove = __devexit_p(ak4104_spi_remove),
index 618fdc30f73eb3889f2372e4bba9033d3675270d..fc5581063b2da414c789402648508cb5a1766796 100644 (file)
@@ -447,7 +447,7 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
        if (ak4535 == NULL)
                return -ENOMEM;
 
-       ak4535->regmap = regmap_init_i2c(i2c, &ak4535_regmap);
+       ak4535->regmap = devm_regmap_init_i2c(i2c, &ak4535_regmap);
        if (IS_ERR(ak4535->regmap)) {
                ret = PTR_ERR(ak4535->regmap);
                dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
@@ -458,18 +458,13 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_ak4535, &ak4535_dai, 1);
-       if (ret != 0)
-               regmap_exit(ak4535->regmap);
 
        return ret;
 }
 
 static __devexit int ak4535_i2c_remove(struct i2c_client *client)
 {
-       struct ak4535_priv *ak4535 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(ak4535->regmap);
        return 0;
 }
 
index b3e24f289421a7fda3dda11043039179c4777535..546466abb77f74b6be5cad2395bbc5049a8bfb45 100644 (file)
@@ -194,12 +194,6 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {
        {"LINEOUT Mixer", "DACL", "DAC"},
 };
 
-/* codec private data */
-struct ak4642_priv {
-       unsigned int sysclk;
-       enum snd_soc_control_type control_type;
-};
-
 /*
  * ak4642 register cache
  */
@@ -468,10 +462,9 @@ static int ak4642_resume(struct snd_soc_codec *codec)
 
 static int ak4642_probe(struct snd_soc_codec *codec)
 {
-       struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4642->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -523,21 +516,9 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = {
 static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
-       struct ak4642_priv *ak4642;
-       int ret;
-
-       ak4642 = devm_kzalloc(&i2c->dev, sizeof(struct ak4642_priv),
-                             GFP_KERNEL);
-       if (!ak4642)
-               return -ENOMEM;
-
-       i2c_set_clientdata(i2c, ak4642);
-       ak4642->control_type = SND_SOC_I2C;
-
-       ret =  snd_soc_register_codec(&i2c->dev,
+       return snd_soc_register_codec(&i2c->dev,
                                (struct snd_soc_codec_driver *)id->driver_data,
                                &ak4642_dai, 1);
-       return ret;
 }
 
 static __devexit int ak4642_i2c_remove(struct i2c_client *client)
index 054967d8bac2f6d089214e390b1bd6ce416f64b2..adf397b9d0e650eb19768e7bc6c592352014a595 100644 (file)
@@ -226,6 +226,31 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values);
 const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
 EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
 
+static const char *arizona_vol_ramp_text[] = {
+       "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
+       "15ms/6dB", "30ms/6dB",
+};
+
+const struct soc_enum arizona_in_vd_ramp =
+       SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
+                       ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
+
+const struct soc_enum arizona_in_vi_ramp =
+       SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
+                       ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
+
+const struct soc_enum arizona_out_vd_ramp =
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
+                       ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
+
+const struct soc_enum arizona_out_vi_ramp =
+       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
+                       ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
+
 static const char *arizona_lhpf_mode_text[] = {
        "Low-pass", "High-pass"
 };
@@ -380,6 +405,18 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
        case 49152000:
                val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
+       case 67737600:
+       case 73728000:
+               val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               break;
+       case 90316800:
+       case 98304000:
+               val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               break;
+       case 135475200:
+       case 147456000:
+               val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               break;
        default:
                return -EINVAL;
        }
@@ -737,6 +774,9 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
                return -EBUSY;
        }
 
+       dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
+               arizona_dai_clk_str(clk_id));
+
        memset(&routes, 0, sizeof(routes));
        routes[0].sink = dai->driver->capture.stream_name;
        routes[1].sink = dai->driver->playback.stream_name;
@@ -749,6 +789,8 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
        routes[1].source = arizona_dai_clk_str(clk_id);
        snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
 
+       dai_priv->clk = clk_id;
+
        return snd_soc_dapm_sync(&codec->dapm);
 }
 
@@ -925,6 +967,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
        bool ena;
        int ret;
 
+       if (fll->fref == Fref && fll->fout == Fout)
+               return 0;
+
        ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
        if (ret != 0) {
                arizona_fll_err(fll, "Failed to read current state: %d\n",
@@ -970,6 +1015,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
                if (ena)
                        pm_runtime_put_autosuspend(arizona->dev);
 
+               fll->fref = Fref;
+               fll->fout = Fout;
+
                return 0;
        }
 
@@ -998,10 +1046,13 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
                                   ARIZONA_FLL1_SYNC_ENA);
 
        ret = wait_for_completion_timeout(&fll->ok,
-                                         msecs_to_jiffies(25));
+                                         msecs_to_jiffies(250));
        if (ret == 0)
                arizona_fll_warn(fll, "Timed out waiting for lock\n");
 
+       fll->fref = Fref;
+       fll->fout = Fout;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_set_fll);
index 36ec64946120077455ab218c85aef34eaa29ef9a..41dae1ed3b714a4734448b1d3c99938af1fe9d9a 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <sound/soc.h>
 
+#include "wm_adsp.h"
+
 #define ARIZONA_CLK_SYSCLK         1
 #define ARIZONA_CLK_ASYNCCLK       2
 #define ARIZONA_CLK_OPCLK          3
 #define ARIZONA_MIXER_VOL_SHIFT                 1
 #define ARIZONA_MIXER_VOL_WIDTH                 7
 
-#define ARIZONA_MAX_DAI 3
+#define ARIZONA_MAX_DAI  4
+#define ARIZONA_MAX_ADSP 4
 
 struct arizona;
+struct wm_adsp;
 
 struct arizona_dai_priv {
        int clk;
 };
 
 struct arizona_priv {
+       struct wm_adsp adsp[ARIZONA_MAX_ADSP];
        struct arizona *arizona;
        int sysclk;
        int asyncclk;
@@ -89,19 +94,30 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        const struct snd_kcontrol_new name##_mux =      \
                SOC_DAPM_VALUE_ENUM("Route", name##_enum)
 
+#define ARIZONA_MUX_ENUMS(name, base_reg) \
+       static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg);      \
+       static ARIZONA_MUX_CTL_DECL(name)
+
 #define ARIZONA_MIXER_ENUMS(name, base_reg) \
-       static ARIZONA_MUX_ENUM_DECL(name##_in1_enum, base_reg);      \
-       static ARIZONA_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2);  \
-       static ARIZONA_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4);  \
-       static ARIZONA_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6);  \
-       static ARIZONA_MUX_CTL_DECL(name##_in1); \
-       static ARIZONA_MUX_CTL_DECL(name##_in2); \
-       static ARIZONA_MUX_CTL_DECL(name##_in3); \
-       static ARIZONA_MUX_CTL_DECL(name##_in4)
+       ARIZONA_MUX_ENUMS(name##_in1, base_reg);     \
+       ARIZONA_MUX_ENUMS(name##_in2, base_reg + 2); \
+       ARIZONA_MUX_ENUMS(name##_in3, base_reg + 4); \
+       ARIZONA_MUX_ENUMS(name##_in4, base_reg + 6)
+
+#define ARIZONA_DSP_AUX_ENUMS(name, base_reg) \
+       ARIZONA_MUX_ENUMS(name##_aux1, base_reg);       \
+       ARIZONA_MUX_ENUMS(name##_aux2, base_reg + 8);   \
+       ARIZONA_MUX_ENUMS(name##_aux3, base_reg + 16);  \
+       ARIZONA_MUX_ENUMS(name##_aux4, base_reg + 24);  \
+       ARIZONA_MUX_ENUMS(name##_aux5, base_reg + 32);  \
+       ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40)
 
 #define ARIZONA_MUX(name, ctrl) \
        SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
 
+#define ARIZONA_MUX_WIDGETS(name, name_str) \
+       ARIZONA_MUX(name_str " Input", &name##_mux)
+
 #define ARIZONA_MIXER_WIDGETS(name, name_str)  \
        ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \
        ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \
@@ -109,6 +125,19 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \
        SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
 
+#define ARIZONA_DSP_WIDGETS(name, name_str) \
+       ARIZONA_MIXER_WIDGETS(name##L, name_str "L"), \
+       ARIZONA_MIXER_WIDGETS(name##R, name_str "R"), \
+       ARIZONA_MUX(name_str " Aux 1", &name##_aux1_mux), \
+       ARIZONA_MUX(name_str " Aux 2", &name##_aux2_mux), \
+       ARIZONA_MUX(name_str " Aux 3", &name##_aux3_mux), \
+       ARIZONA_MUX(name_str " Aux 4", &name##_aux4_mux), \
+       ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \
+       ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux)
+
+#define ARIZONA_MUX_ROUTES(name) \
+       ARIZONA_MIXER_INPUT_ROUTES(name " Input")
+
 #define ARIZONA_MIXER_ROUTES(widget, name) \
        { widget, NULL, name " Mixer" },         \
        { name " Mixer", NULL, name " Input 1" }, \
@@ -120,6 +149,28 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \
        ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
 
+#define ARIZONA_DSP_ROUTES(name) \
+       { name, NULL, name " Aux 1" }, \
+       { name, NULL, name " Aux 2" }, \
+       { name, NULL, name " Aux 3" }, \
+       { name, NULL, name " Aux 4" }, \
+       { name, NULL, name " Aux 5" }, \
+       { name, NULL, name " Aux 6" }, \
+       ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
+       ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
+       ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
+       ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
+       ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
+       ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
+       ARIZONA_MIXER_ROUTES(name, name "L"), \
+       ARIZONA_MIXER_ROUTES(name, name "R")
+
+extern const struct soc_enum arizona_in_vi_ramp;
+extern const struct soc_enum arizona_in_vd_ramp;
+
+extern const struct soc_enum arizona_out_vi_ramp;
+extern const struct soc_enum arizona_out_vd_ramp;
+
 extern const struct soc_enum arizona_lhpf1_mode;
 extern const struct soc_enum arizona_lhpf2_mode;
 extern const struct soc_enum arizona_lhpf3_mode;
@@ -146,6 +197,8 @@ struct arizona_fll {
        unsigned int vco_mult;
        struct completion lock;
        struct completion ok;
+       unsigned int fref;
+       unsigned int fout;
 
        char lock_name[ARIZONA_FLL_NAME_LEN];
        char clock_ok_name[ARIZONA_FLL_NAME_LEN];
index e3f0a7f3131e14b7895aadf2daf8bf81f6058d8b..6ad3878db8fcf4663cf948812f6b063a5993acfb 100644 (file)
@@ -474,15 +474,25 @@ static int cs4271_probe(struct snd_soc_codec *codec)
        struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
        int ret;
        int gpio_nreset = -EINVAL;
+       int amutec_eq_bmutec = 0;
 
 #ifdef CONFIG_OF
-       if (of_match_device(cs4271_dt_ids, codec->dev))
+       if (of_match_device(cs4271_dt_ids, codec->dev)) {
                gpio_nreset = of_get_named_gpio(codec->dev->of_node,
                                                "reset-gpio", 0);
+
+               if (!of_get_property(codec->dev->of_node,
+                                    "cirrus,amutec-eq-bmutec", NULL))
+                       amutec_eq_bmutec = 1;
+       }
 #endif
 
-       if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))
-               gpio_nreset = cs4271plat->gpio_nreset;
+       if (cs4271plat) {
+               if (gpio_is_valid(cs4271plat->gpio_nreset))
+                       gpio_nreset = cs4271plat->gpio_nreset;
+
+               amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
+       }
 
        if (gpio_nreset >= 0)
                if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset"))
@@ -528,6 +538,11 @@ static int cs4271_probe(struct snd_soc_codec *codec)
        /* Power-up sequence requires 85 uS */
        udelay(85);
 
+       if (amutec_eq_bmutec)
+               snd_soc_update_bits(codec, CS4271_MODE2,
+                                   CS4271_MODE2_MUTECAEQUB,
+                                   CS4271_MODE2_MUTECAEQUB);
+
        return snd_soc_add_codec_controls(codec, cs4271_snd_controls,
                ARRAY_SIZE(cs4271_snd_controls));
 }
index af5db70805199e81b06e7d48a8e844ae504489b2..843c1eb72faf54aca00be107a74a5a47b2cbf991 100644 (file)
@@ -1231,7 +1231,7 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, da7210);
 
-       da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap_config_i2c);
+       da7210->regmap = devm_regmap_init_i2c(i2c, &da7210_regmap_config_i2c);
        if (IS_ERR(da7210->regmap)) {
                ret = PTR_ERR(da7210->regmap);
                dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
@@ -1245,24 +1245,15 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_da7210, &da7210_dai, 1);
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
-               goto err_regmap;
-       }
-       return ret;
-
-err_regmap:
-       regmap_exit(da7210->regmap);
 
        return ret;
 }
 
 static int __devexit da7210_i2c_remove(struct i2c_client *client)
 {
-       struct da7210_priv *da7210 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(da7210->regmap);
        return 0;
 }
 
@@ -1346,24 +1337,15 @@ static int __devinit da7210_spi_probe(struct spi_device *spi)
        if (ret != 0)
                dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret);
 
-       ret =  snd_soc_register_codec(&spi->dev,
+       ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_da7210, &da7210_dai, 1);
-       if (ret < 0)
-               goto err_regmap;
-
-       return ret;
-
-err_regmap:
-       regmap_exit(da7210->regmap);
 
        return ret;
 }
 
 static int __devexit da7210_spi_remove(struct spi_device *spi)
 {
-       struct da7210_priv *da7210 = spi_get_drvdata(spi);
        snd_soc_unregister_codec(&spi->dev);
-       regmap_exit(da7210->regmap);
        return 0;
 }
 
index f379b085c39204dfeb2a6fc34d7c07d9f15c9f0b..d3a6de2e757b9f8d0b96fd2ac0f3444f2d017dc5 100644 (file)
 #define DA9055_AIF_FORMAT_I2S_MODE     (0 << 0)
 #define DA9055_AIF_FORMAT_LEFT_J       (1 << 0)
 #define DA9055_AIF_FORMAT_RIGHT_J      (2 << 0)
+#define DA9055_AIF_FORMAT_DSP          (3 << 0)
 #define DA9055_AIF_WORD_S16_LE         (0 << 2)
 #define DA9055_AIF_WORD_S20_3LE                (1 << 2)
 #define DA9055_AIF_WORD_S24_LE         (2 << 2)
@@ -752,6 +753,17 @@ static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] = {
                        6, 1, 0),
 };
 
+/* Headphone Output Enable */
+static const struct snd_kcontrol_new da9055_dapm_hp_l_control =
+SOC_DAPM_SINGLE("Switch", DA9055_HP_L_CTRL, 3, 1, 0);
+
+static const struct snd_kcontrol_new da9055_dapm_hp_r_control =
+SOC_DAPM_SINGLE("Switch", DA9055_HP_R_CTRL, 3, 1, 0);
+
+/* Lineout Output Enable */
+static const struct snd_kcontrol_new da9055_dapm_lineout_control =
+SOC_DAPM_SINGLE("Switch", DA9055_LINE_CTRL, 3, 1, 0);
+
 /* DAPM widgets */
 static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = {
        /* Input Side */
@@ -816,6 +828,14 @@ static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = {
                           &da9055_dapm_mixoutr_controls[0],
                           ARRAY_SIZE(da9055_dapm_mixoutr_controls)),
 
+       /* Output Enable Switches */
+       SND_SOC_DAPM_SWITCH("Headphone Left Enable", SND_SOC_NOPM, 0, 0,
+                           &da9055_dapm_hp_l_control),
+       SND_SOC_DAPM_SWITCH("Headphone Right Enable", SND_SOC_NOPM, 0, 0,
+                           &da9055_dapm_hp_r_control),
+       SND_SOC_DAPM_SWITCH("Lineout Enable", SND_SOC_NOPM, 0, 0,
+                           &da9055_dapm_lineout_control),
+
        /* Output PGAs */
        SND_SOC_DAPM_PGA("MIXOUT Left", DA9055_MIXOUT_L_CTRL, 7, 0, NULL, 0),
        SND_SOC_DAPM_PGA("MIXOUT Right", DA9055_MIXOUT_R_CTRL, 7, 0, NULL, 0),
@@ -901,17 +921,20 @@ static const struct snd_soc_dapm_route da9055_audio_map[] = {
        {"Out Mixer Right", "DAC Right Switch", "DAC Right"},
 
        {"MIXOUT Left", NULL, "Out Mixer Left"},
-       {"Headphone Left", NULL, "MIXOUT Left"},
+       {"Headphone Left Enable", "Switch", "MIXOUT Left"},
+       {"Headphone Left", NULL, "Headphone Left Enable"},
        {"Headphone Left", NULL, "Charge Pump"},
        {"HPL", NULL, "Headphone Left"},
 
        {"MIXOUT Right", NULL, "Out Mixer Right"},
-       {"Headphone Right", NULL, "MIXOUT Right"},
+       {"Headphone Right Enable", "Switch", "MIXOUT Right"},
+       {"Headphone Right", NULL, "Headphone Right Enable"},
        {"Headphone Right", NULL, "Charge Pump"},
        {"HPR", NULL, "Headphone Right"},
 
        {"MIXOUT Right", NULL, "Out Mixer Right"},
-       {"Lineout", NULL, "MIXOUT Right"},
+       {"Lineout Enable", "Switch", "MIXOUT Right"},
+       {"Lineout", NULL, "Lineout Enable"},
        {"LINE", NULL, "Lineout"},
 };
 
@@ -1175,6 +1198,9 @@ static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        case SND_SOC_DAIFMT_RIGHT_J:
                aif_ctrl = DA9055_AIF_FORMAT_RIGHT_J;
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               aif_ctrl = DA9055_AIF_FORMAT_DSP;
+               break;
        default:
                return -EINVAL;
        }
@@ -1390,8 +1416,7 @@ static int da9055_probe(struct snd_soc_codec *codec)
                            DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
 
        /*
-        * There are two separate control bits for input and output mixers as
-        * well as headphone and line outs.
+        * There are two separate control bits for input and output mixers.
         * One to enable corresponding amplifier and other to enable its
         * output. As amplifier bits are related to power control, they are
         * being managed by DAPM while other (non power related) bits are
@@ -1407,14 +1432,6 @@ static int da9055_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, DA9055_MIXOUT_R_CTRL,
                            DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN);
 
-       snd_soc_update_bits(codec, DA9055_HP_L_CTRL,
-                           DA9055_HP_L_AMP_OE, DA9055_HP_L_AMP_OE);
-       snd_soc_update_bits(codec, DA9055_HP_R_CTRL,
-                           DA9055_HP_R_AMP_OE, DA9055_HP_R_AMP_OE);
-
-       snd_soc_update_bits(codec, DA9055_LINE_CTRL,
-                           DA9055_LINE_AMP_OE, DA9055_LINE_AMP_OE);
-
        /* Set this as per your system configuration */
        snd_soc_write(codec, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ);
 
index 85d9cabe6d555d9e28e3812f1d97f631434ff461..9ad1da36887e54316ed3568d556625f743c40363 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/regmap.h>
 
 #include <linux/delay.h>
 
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/tlv.h>
 
 #define JZ4740_REG_CODEC_1 0x0
-#define JZ4740_REG_CODEC_2 0x1
+#define JZ4740_REG_CODEC_2 0x4
 
 #define JZ4740_CODEC_1_LINE_ENABLE BIT(29)
 #define JZ4740_CODEC_1_MIC_ENABLE BIT(28)
 #define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET    4
 #define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET  0
 
-static const uint32_t jz4740_codec_regs[] = {
-       0x021b2302, 0x00170803,
+static const struct reg_default jz4740_codec_reg_defaults[] = {
+       { JZ4740_REG_CODEC_1, 0x021b2302 },
+       { JZ4740_REG_CODEC_2, 0x00170803 },
 };
 
 struct jz4740_codec {
-       void __iomem *base;
-       struct resource *mem;
+       struct regmap *regmap;
 };
 
-static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
-       unsigned int reg)
-{
-       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
-       return readl(jz4740_codec->base + (reg << 2));
-}
-
-static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
-       unsigned int val)
-{
-       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
-       u32 *cache = codec->reg_cache;
-
-       cache[reg] = val;
-       writel(val, jz4740_codec->base + (reg << 2));
+static const unsigned int jz4740_mic_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 2, TLV_DB_SCALE_ITEM(0, 600, 0),
+       3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0),
+};
 
-       return 0;
-}
+static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0);
+static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0);
 
 static const struct snd_kcontrol_new jz4740_codec_controls[] = {
-       SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2,
-                       JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0),
-       SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2,
-                       JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0),
+       SOC_SINGLE_TLV("Master Playback Volume", JZ4740_REG_CODEC_2,
+                       JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0,
+                       jz4740_out_tlv),
+       SOC_SINGLE_TLV("Master Capture Volume", JZ4740_REG_CODEC_2,
+                       JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0,
+                       jz4740_in_tlv),
        SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,
                        JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1),
-       SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2,
-                       JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0),
+       SOC_SINGLE_TLV("Mic Capture Volume", JZ4740_REG_CODEC_2,
+                       JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0,
+                       jz4740_mic_tlv),
 };
 
 static const struct snd_kcontrol_new jz4740_codec_output_controls[] = {
@@ -163,8 +158,8 @@ static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
 static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
+       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(dai->codec);
        uint32_t val;
-       struct snd_soc_codec *codec = dai->codec;
 
        switch (params_rate(params)) {
        case 8000:
@@ -200,7 +195,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
 
        val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET;
 
-       snd_soc_update_bits(codec, JZ4740_REG_CODEC_2,
+       regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_2,
                                JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);
 
        return 0;
@@ -230,25 +225,23 @@ static struct snd_soc_dai_driver jz4740_codec_dai = {
        .symmetric_rates = 1,
 };
 
-static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
+static void jz4740_codec_wakeup(struct regmap *regmap)
 {
-       int i;
-       uint32_t *cache = codec->reg_cache;
-
-       snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+       regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
                JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
        udelay(2);
 
-       snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+       regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
                JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
 
-       for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i)
-               jz4740_codec_write(codec, i, cache[i]);
+       regcache_sync(regmap);
 }
 
 static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
+       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+       struct regmap *regmap = jz4740_codec->regmap;
        unsigned int mask;
        unsigned int value;
 
@@ -261,12 +254,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
                                JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
                value = 0;
 
-               snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+               regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
                break;
        case SND_SOC_BIAS_STANDBY:
                /* The only way to clear the suspend flag is to reset the codec */
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
-                       jz4740_codec_wakeup(codec);
+                       jz4740_codec_wakeup(regmap);
 
                mask = JZ4740_CODEC_1_VREF_DISABLE |
                        JZ4740_CODEC_1_VREF_AMP_DISABLE |
@@ -275,13 +268,14 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
                        JZ4740_CODEC_1_VREF_AMP_DISABLE |
                        JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
 
-               snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+               regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
                break;
        case SND_SOC_BIAS_OFF:
                mask = JZ4740_CODEC_1_SUSPEND;
                value = JZ4740_CODEC_1_SUSPEND;
 
-               snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+               regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+               regcache_mark_dirty(regmap);
                break;
        default:
                break;
@@ -294,7 +288,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 
 static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 {
-       snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+
+       regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1,
                        JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
        jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -331,12 +327,7 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
        .remove = jz4740_codec_dev_remove,
        .suspend = jz4740_codec_suspend,
        .resume = jz4740_codec_resume,
-       .read = jz4740_codec_read,
-       .write = jz4740_codec_write,
        .set_bias_level = jz4740_codec_set_bias_level,
-       .reg_cache_default      = jz4740_codec_regs,
-       .reg_word_size = sizeof(u32),
-       .reg_cache_size = 2,
 
        .controls = jz4740_codec_controls,
        .num_controls = ARRAY_SIZE(jz4740_codec_controls),
@@ -346,11 +337,23 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
        .num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),
 };
 
+static const struct regmap_config jz4740_codec_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = JZ4740_REG_CODEC_2,
+
+       .reg_defaults = jz4740_codec_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int __devinit jz4740_codec_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz4740_codec *jz4740_codec;
        struct resource *mem;
+       void __iomem *base;
 
        jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec),
                                    GFP_KERNEL);
@@ -358,56 +361,29 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
-               ret = -ENOENT;
-               goto err_out;
-       }
-
-       mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
-       if (!mem) {
-               dev_err(&pdev->dev, "Failed to request mmio memory region\n");
-               ret = -EBUSY;
-               goto err_out;
-       }
+       base = devm_request_and_ioremap(&pdev->dev, mem);
+       if (!base)
+               return -EBUSY;
 
-       jz4740_codec->base = ioremap(mem->start, resource_size(mem));
-       if (!jz4740_codec->base) {
-               dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
-               ret = -EBUSY;
-               goto err_release_mem_region;
-       }
-       jz4740_codec->mem = mem;
+       jz4740_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                           &jz4740_codec_regmap_config);
+       if (IS_ERR(jz4740_codec->regmap))
+               return PTR_ERR(jz4740_codec->regmap);
 
        platform_set_drvdata(pdev, jz4740_codec);
 
        ret = snd_soc_register_codec(&pdev->dev,
                        &soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
-       if (ret) {
+       if (ret)
                dev_err(&pdev->dev, "Failed to register codec\n");
-               goto err_iounmap;
-       }
 
-       return 0;
-
-err_iounmap:
-       iounmap(jz4740_codec->base);
-err_release_mem_region:
-       release_mem_region(mem->start, resource_size(mem));
-err_out:
        return ret;
 }
 
 static int __devexit jz4740_codec_remove(struct platform_device *pdev)
 {
-       struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
-       struct resource *mem = jz4740_codec->mem;
-
        snd_soc_unregister_codec(&pdev->dev);
 
-       iounmap(jz4740_codec->base);
-       release_mem_region(mem->start, resource_size(mem));
-
        platform_set_drvdata(pdev, NULL);
 
        return 0;
index 99b0a9dcff346ac68b3915ae320b60645cb6a01f..096b6aa87f0f7fd508bb6c508cc8d821f7b1db27 100644 (file)
@@ -1497,7 +1497,7 @@ static __devinit int lm49453_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, lm49453);
 
-       lm49453->regmap = regmap_init_i2c(i2c, &lm49453_regmap_config);
+       lm49453->regmap = devm_regmap_init_i2c(i2c, &lm49453_regmap_config);
        if (IS_ERR(lm49453->regmap)) {
                ret = PTR_ERR(lm49453->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -1508,21 +1508,15 @@ static __devinit int lm49453_i2c_probe(struct i2c_client *i2c,
        ret =  snd_soc_register_codec(&i2c->dev,
                                      &soc_codec_dev_lm49453,
                                      lm49453_dai, ARRAY_SIZE(lm49453_dai));
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
-               regmap_exit(lm49453->regmap);
-               return ret;
-       }
 
        return ret;
 }
 
 static int __devexit lm49453_i2c_remove(struct i2c_client *client)
 {
-       struct lm49453_priv *lm49453 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(lm49453->regmap);
        return 0;
 }
 
index 17b3ec2d05cb1ebade50fe27eb95b4a62dfbfc20..a777de6a1b23c7d07ad77eeca73e73f894ec37eb 100644 (file)
@@ -187,7 +187,7 @@ static int __devinit max9768_i2c_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, max9768);
 
-       max9768->regmap = regmap_init_i2c(client, &max9768_i2c_regmap_config);
+       max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config);
        if (IS_ERR(max9768->regmap)) {
                err = PTR_ERR(max9768->regmap);
                goto err_gpio_free;
@@ -195,12 +195,10 @@ static int __devinit max9768_i2c_probe(struct i2c_client *client,
 
        err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0);
        if (err)
-               goto err_regmap_free;
+               goto err_gpio_free;
 
        return 0;
 
- err_regmap_free:
-       regmap_exit(max9768->regmap);
  err_gpio_free:
        if (gpio_is_valid(max9768->shdn_gpio))
                gpio_free(max9768->shdn_gpio);
@@ -215,7 +213,6 @@ static int __devexit max9768_i2c_remove(struct i2c_client *client)
        struct max9768 *max9768 = i2c_get_clientdata(client);
 
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(max9768->regmap);
 
        if (gpio_is_valid(max9768->shdn_gpio))
                gpio_free(max9768->shdn_gpio);
index 3264a5169306fc3f8d769912173f803fae3d17a4..b858264235c44e8f77f0adaef778b9f01d828a88 100644 (file)
@@ -2098,13 +2098,13 @@ static const struct i2c_device_id max98088_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
 
 static struct i2c_driver max98088_i2c_driver = {
-       .driver = {
-               .name = "max98088",
-               .owner = THIS_MODULE,
-       },
-       .probe  = max98088_i2c_probe,
-       .remove = __devexit_p(max98088_i2c_remove),
-       .id_table = max98088_i2c_id,
+       .driver = {
+               .name = "max98088",
+               .owner = THIS_MODULE,
+       },
+       .probe  = max98088_i2c_probe,
+       .remove = max98088_i2c_remove,
+       .id_table = max98088_i2c_id,
 };
 
 module_i2c_driver(max98088_i2c_driver);
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
new file mode 100644 (file)
index 0000000..c9772ca
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * max98090.c -- MAX98090 ALSA SoC Audio driver
+ * based on Rev0p8 datasheet
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on
+ *
+ * max98095.c
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * https://github.com/hardkernel/linux/commit/\
+ *     3417d7166b17113b3b33b0a337c74d1c7cc313df#sound/soc/codecs/max98090.c
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+/*
+ *
+ * MAX98090 Registers Definition
+ *
+ */
+
+/* RESET / STATUS / INTERRUPT REGISTERS */
+#define MAX98090_0x00_SW_RESET         0x00
+#define MAX98090_0x01_INT_STS          0x01
+#define MAX98090_0x02_JACK_STS         0x02
+#define MAX98090_0x03_INT_MASK         0x03
+
+/* QUICK SETUP REGISTERS */
+#define MAX98090_0x04_SYS_CLK          0x04
+#define MAX98090_0x05_SAMPLE_RATE      0x05
+#define MAX98090_0x06_DAI_IF           0x06
+#define MAX98090_0x07_DAC_PATH         0x07
+#define MAX98090_0x08_MIC_TO_ADC       0x08
+#define MAX98090_0x09_LINE_TO_ADC      0x09
+#define MAX98090_0x0A_ANALOG_MIC_LOOP  0x0A
+#define MAX98090_0x0B_ANALOG_LINE_LOOP 0x0B
+
+/* ANALOG INPUT CONFIGURATION REGISTERS */
+#define MAX98090_0x0D_INPUT_CONFIG     0x0D
+#define MAX98090_0x0E_LINE_IN_LVL      0x0E
+#define MAX98090_0x0F_LINI_IN_CFG      0x0F
+#define MAX98090_0x10_MIC1_IN_LVL      0x10
+#define MAX98090_0x11_MIC2_IN_LVL      0x11
+
+/* MICROPHONE CONFIGURATION REGISTERS  */
+#define MAX98090_0x12_MIC_BIAS_VOL     0x12
+#define MAX98090_0x13_DIGITAL_MIC_CFG  0x13
+#define MAX98090_0x14_DIGITAL_MIC_MODE 0x14
+
+/* ADC PATH AND CONFIGURATION REGISTERS */
+#define MAX98090_0x15_L_ADC_MIX                0x15
+#define MAX98090_0x16_R_ADC_MIX                0x16
+#define MAX98090_0x17_L_ADC_LVL                0x17
+#define MAX98090_0x18_R_ADC_LVL                0x18
+#define MAX98090_0x19_ADC_BIQUAD_LVL   0x19
+#define MAX98090_0x1A_ADC_SIDETONE     0x1A
+
+/* CLOCK CONFIGURATION REGISTERS */
+#define MAX98090_0x1B_SYS_CLK          0x1B
+#define MAX98090_0x1C_CLK_MODE         0x1C
+#define MAX98090_0x1D_ANY_CLK1         0x1D
+#define MAX98090_0x1E_ANY_CLK2         0x1E
+#define MAX98090_0x1F_ANY_CLK3         0x1F
+#define MAX98090_0x20_ANY_CLK4         0x20
+#define MAX98090_0x21_MASTER_MODE      0x21
+
+/* INTERFACE CONTROL REGISTERS */
+#define MAX98090_0x22_DAI_IF_FMT       0x22
+#define MAX98090_0x23_DAI_TDM_FMT1     0x23
+#define MAX98090_0x24_DAI_TDM_FMT2     0x24
+#define MAX98090_0x25_DAI_IO_CFG       0x25
+#define MAX98090_0x26_FILTER_CFG       0x26
+#define MAX98090_0x27_DAI_PLAYBACK_LVL 0x27
+#define MAX98090_0x28_EQ_PLAYBACK_LVL  0x28
+
+/* HEADPHONE CONTROL REGISTERS */
+#define MAX98090_0x29_L_HP_MIX         0x29
+#define MAX98090_0x2A_R_HP_MIX         0x2A
+#define MAX98090_0x2B_HP_CTR           0x2B
+#define MAX98090_0x2C_L_HP_VOL         0x2C
+#define MAX98090_0x2D_R_HP_VOL         0x2D
+
+/* SPEAKER CONFIGURATION REGISTERS */
+#define MAX98090_0x2E_L_SPK_MIX                0x2E
+#define MAX98090_0x2F_R_SPK_MIX                0x2F
+#define MAX98090_0x30_SPK_CTR          0x30
+#define MAX98090_0x31_L_SPK_VOL                0x31
+#define MAX98090_0x32_R_SPK_VOL                0x32
+
+/* ALC CONFIGURATION REGISTERS */
+#define MAX98090_0x33_ALC_TIMING       0x33
+#define MAX98090_0x34_ALC_COMPRESSOR   0x34
+#define MAX98090_0x35_ALC_EXPANDER     0x35
+#define MAX98090_0x36_ALC_GAIN         0x36
+
+/* RECEIVER AND LINE_OUTPUT REGISTERS */
+#define MAX98090_0x37_RCV_LOUT_L_MIX   0x37
+#define MAX98090_0x38_RCV_LOUT_L_CNTL  0x38
+#define MAX98090_0x39_RCV_LOUT_L_VOL   0x39
+#define MAX98090_0x3A_LOUT_R_MIX       0x3A
+#define MAX98090_0x3B_LOUT_R_CNTL      0x3B
+#define MAX98090_0x3C_LOUT_R_VOL       0x3C
+
+/* JACK DETECT AND ENABLE REGISTERS */
+#define MAX98090_0x3D_JACK_DETECT      0x3D
+#define MAX98090_0x3E_IN_ENABLE                0x3E
+#define MAX98090_0x3F_OUT_ENABLE       0x3F
+#define MAX98090_0x40_LVL_CTR          0x40
+#define MAX98090_0x41_DSP_FILTER_ENABLE        0x41
+
+/* BIAS AND POWER MODE CONFIGURATION REGISTERS */
+#define MAX98090_0x42_BIAS_CTR         0x42
+#define MAX98090_0x43_DAC_CTR          0x43
+#define MAX98090_0x44_ADC_CTR          0x44
+#define MAX98090_0x45_DEV_SHUTDOWN     0x45
+
+/* REVISION ID REGISTER */
+#define MAX98090_0xFF_REV_ID           0xFF
+
+#define MAX98090_REG_MAX_CACHED                0x45
+#define MAX98090_REG_END               0xFF
+
+/*
+ *
+ * MAX98090 Registers Bit Fields
+ *
+ */
+
+/* MAX98090_0x06_DAI_IF */
+#define MAX98090_DAI_IF_MASK           0x3F
+#define MAX98090_RJ_M                  (1 << 5)
+#define MAX98090_RJ_S                  (1 << 4)
+#define MAX98090_LJ_M                  (1 << 3)
+#define MAX98090_LJ_S                  (1 << 2)
+#define MAX98090_I2S_M                 (1 << 1)
+#define MAX98090_I2S_S                 (1 << 0)
+
+/* MAX98090_0x45_DEV_SHUTDOWN */
+#define MAX98090_SHDNRUN               (1 << 7)
+
+/* codec private data */
+struct max98090_priv {
+       struct regmap *regmap;
+};
+
+static const struct reg_default max98090_reg_defaults[] = {
+       /* RESET / STATUS / INTERRUPT REGISTERS */
+       {MAX98090_0x00_SW_RESET,                0x00},
+       {MAX98090_0x01_INT_STS,                 0x00},
+       {MAX98090_0x02_JACK_STS,                0x00},
+       {MAX98090_0x03_INT_MASK,                0x04},
+
+       /* QUICK SETUP REGISTERS */
+       {MAX98090_0x04_SYS_CLK,                 0x00},
+       {MAX98090_0x05_SAMPLE_RATE,             0x00},
+       {MAX98090_0x06_DAI_IF,                  0x00},
+       {MAX98090_0x07_DAC_PATH,                0x00},
+       {MAX98090_0x08_MIC_TO_ADC,              0x00},
+       {MAX98090_0x09_LINE_TO_ADC,             0x00},
+       {MAX98090_0x0A_ANALOG_MIC_LOOP,         0x00},
+       {MAX98090_0x0B_ANALOG_LINE_LOOP,        0x00},
+
+       /* ANALOG INPUT CONFIGURATION REGISTERS */
+       {MAX98090_0x0D_INPUT_CONFIG,            0x00},
+       {MAX98090_0x0E_LINE_IN_LVL,             0x1B},
+       {MAX98090_0x0F_LINI_IN_CFG,             0x00},
+       {MAX98090_0x10_MIC1_IN_LVL,             0x11},
+       {MAX98090_0x11_MIC2_IN_LVL,             0x11},
+
+       /* MICROPHONE CONFIGURATION REGISTERS  */
+       {MAX98090_0x12_MIC_BIAS_VOL,            0x00},
+       {MAX98090_0x13_DIGITAL_MIC_CFG,         0x00},
+       {MAX98090_0x14_DIGITAL_MIC_MODE,        0x00},
+
+       /* ADC PATH AND CONFIGURATION REGISTERS */
+       {MAX98090_0x15_L_ADC_MIX,               0x00},
+       {MAX98090_0x16_R_ADC_MIX,               0x00},
+       {MAX98090_0x17_L_ADC_LVL,               0x03},
+       {MAX98090_0x18_R_ADC_LVL,               0x03},
+       {MAX98090_0x19_ADC_BIQUAD_LVL,          0x00},
+       {MAX98090_0x1A_ADC_SIDETONE,            0x00},
+
+       /* CLOCK CONFIGURATION REGISTERS */
+       {MAX98090_0x1B_SYS_CLK,                 0x00},
+       {MAX98090_0x1C_CLK_MODE,                0x00},
+       {MAX98090_0x1D_ANY_CLK1,                0x00},
+       {MAX98090_0x1E_ANY_CLK2,                0x00},
+       {MAX98090_0x1F_ANY_CLK3,                0x00},
+       {MAX98090_0x20_ANY_CLK4,                0x00},
+       {MAX98090_0x21_MASTER_MODE,             0x00},
+
+       /* INTERFACE CONTROL REGISTERS */
+       {MAX98090_0x22_DAI_IF_FMT,              0x00},
+       {MAX98090_0x23_DAI_TDM_FMT1,            0x00},
+       {MAX98090_0x24_DAI_TDM_FMT2,            0x00},
+       {MAX98090_0x25_DAI_IO_CFG,              0x00},
+       {MAX98090_0x26_FILTER_CFG,              0x80},
+       {MAX98090_0x27_DAI_PLAYBACK_LVL,        0x00},
+       {MAX98090_0x28_EQ_PLAYBACK_LVL,         0x00},
+
+       /* HEADPHONE CONTROL REGISTERS */
+       {MAX98090_0x29_L_HP_MIX,                0x00},
+       {MAX98090_0x2A_R_HP_MIX,                0x00},
+       {MAX98090_0x2B_HP_CTR,                  0x00},
+       {MAX98090_0x2C_L_HP_VOL,                0x1A},
+       {MAX98090_0x2D_R_HP_VOL,                0x1A},
+
+       /* SPEAKER CONFIGURATION REGISTERS */
+       {MAX98090_0x2E_L_SPK_MIX,               0x00},
+       {MAX98090_0x2F_R_SPK_MIX,               0x00},
+       {MAX98090_0x30_SPK_CTR,                 0x00},
+       {MAX98090_0x31_L_SPK_VOL,               0x2C},
+       {MAX98090_0x32_R_SPK_VOL,               0x2C},
+
+       /* ALC CONFIGURATION REGISTERS */
+       {MAX98090_0x33_ALC_TIMING,              0x00},
+       {MAX98090_0x34_ALC_COMPRESSOR,          0x00},
+       {MAX98090_0x35_ALC_EXPANDER,            0x00},
+       {MAX98090_0x36_ALC_GAIN,                0x00},
+
+       /* RECEIVER AND LINE_OUTPUT REGISTERS */
+       {MAX98090_0x37_RCV_LOUT_L_MIX,          0x00},
+       {MAX98090_0x38_RCV_LOUT_L_CNTL,         0x00},
+       {MAX98090_0x39_RCV_LOUT_L_VOL,          0x15},
+       {MAX98090_0x3A_LOUT_R_MIX,              0x00},
+       {MAX98090_0x3B_LOUT_R_CNTL,             0x00},
+       {MAX98090_0x3C_LOUT_R_VOL,              0x15},
+
+       /* JACK DETECT AND ENABLE REGISTERS */
+       {MAX98090_0x3D_JACK_DETECT,             0x00},
+       {MAX98090_0x3E_IN_ENABLE,               0x00},
+       {MAX98090_0x3F_OUT_ENABLE,              0x00},
+       {MAX98090_0x40_LVL_CTR,                 0x00},
+       {MAX98090_0x41_DSP_FILTER_ENABLE,       0x00},
+
+       /* BIAS AND POWER MODE CONFIGURATION REGISTERS */
+       {MAX98090_0x42_BIAS_CTR,                0x00},
+       {MAX98090_0x43_DAC_CTR,                 0x00},
+       {MAX98090_0x44_ADC_CTR,                 0x06},
+       {MAX98090_0x45_DEV_SHUTDOWN,            0x00},
+};
+
+static const unsigned int max98090_hp_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0x0,    0x6,    TLV_DB_SCALE_ITEM(-6700, 400, 0),
+       0x7,    0xE,    TLV_DB_SCALE_ITEM(-4000, 300, 0),
+       0xF,    0x15,   TLV_DB_SCALE_ITEM(-1700, 200, 0),
+       0x16,   0x1B,   TLV_DB_SCALE_ITEM(-400, 100, 0),
+       0x1C,   0x1F,   TLV_DB_SCALE_ITEM(150, 50, 0),
+};
+
+static struct snd_kcontrol_new max98090_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("Headphone Volume", MAX98090_0x2C_L_HP_VOL,
+                        MAX98090_0x2D_R_HP_VOL, 0, 31, 0, max98090_hp_tlv),
+};
+
+/* Left HeadPhone Mixer Switch */
+static struct snd_kcontrol_new max98090_left_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACR Switch", MAX98090_0x29_L_HP_MIX, 1, 1, 0),
+       SOC_DAPM_SINGLE("DACL Switch", MAX98090_0x29_L_HP_MIX, 0, 1, 0),
+};
+
+/* Right HeadPhone Mixer Switch */
+static struct snd_kcontrol_new max98090_right_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACR Switch", MAX98090_0x2A_R_HP_MIX, 1, 1, 0),
+       SOC_DAPM_SINGLE("DACL Switch", MAX98090_0x2A_R_HP_MIX, 0, 1, 0),
+};
+
+static struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
+       /* Output */
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+
+       /* PGA */
+       SND_SOC_DAPM_PGA("HPL Out", MAX98090_0x3F_OUT_ENABLE, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPR Out", MAX98090_0x3F_OUT_ENABLE, 6, 0, NULL, 0),
+
+       /* Mixer */
+       SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0,
+                          max98090_left_hp_mixer_controls,
+                          ARRAY_SIZE(max98090_left_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0,
+                          max98090_right_hp_mixer_controls,
+                          ARRAY_SIZE(max98090_right_hp_mixer_controls)),
+
+       /* DAC */
+       SND_SOC_DAPM_DAC("DACL", "Hifi Playback", MAX98090_0x3F_OUT_ENABLE, 0, 0),
+       SND_SOC_DAPM_DAC("DACR", "Hifi Playback", MAX98090_0x3F_OUT_ENABLE, 1, 0),
+};
+
+static struct snd_soc_dapm_route max98090_audio_map[] = {
+       /* Output */
+       {"HPL", NULL, "HPL Out"},
+       {"HPR", NULL, "HPR Out"},
+
+       /* PGA */
+       {"HPL Out", NULL, "HPL Mixer"},
+       {"HPR Out", NULL, "HPR Mixer"},
+
+       /* Mixer*/
+       {"HPL Mixer", "DACR Switch", "DACR"},
+       {"HPL Mixer", "DACL Switch", "DACL"},
+
+       {"HPR Mixer", "DACR Switch", "DACR"},
+       {"HPR Mixer", "DACL Switch", "DACL"},
+};
+
+static bool max98090_volatile(struct device *dev, unsigned int reg)
+{
+       if ((reg == MAX98090_0x01_INT_STS)      ||
+           (reg == MAX98090_0x02_JACK_STS)     ||
+           (reg >  MAX98090_REG_MAX_CACHED))
+               return true;
+
+       return false;
+}
+
+static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params,
+               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int val;
+
+       switch (params_rate(params)) {
+       case 96000:
+               val = 1 << 5;
+               break;
+       case 32000:
+               val = 1 << 4;
+               break;
+       case 48000:
+               val = 1 << 3;
+               break;
+       case 44100:
+               val = 1 << 2;
+               break;
+       case 16000:
+               val = 1 << 1;
+               break;
+       case 8000:
+               val = 1 << 0;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported rate\n");
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, MAX98090_0x05_SAMPLE_RATE, 0x03F, val);
+
+       return 0;
+}
+
+static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int val;
+
+       snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN,
+                           MAX98090_SHDNRUN, 0);
+
+       switch (freq) {
+       case 26000000:
+               val = 1 << 7;
+               break;
+       case 19200000:
+               val = 1 << 6;
+               break;
+       case 13000000:
+               val = 1 << 5;
+               break;
+       case 12288000:
+               val = 1 << 4;
+               break;
+       case 12000000:
+               val = 1 << 3;
+               break;
+       case 11289600:
+               val = 1 << 2;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid master clock frequency\n");
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, MAX98090_0x04_SYS_CLK, 0xFD, val);
+
+       snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN,
+                           MAX98090_SHDNRUN, MAX98090_SHDNRUN);
+
+       dev_dbg(dai->dev, "sysclk is %uHz\n", freq);
+
+       return 0;
+}
+
+static int max98090_dai_set_fmt(struct snd_soc_dai *dai,
+                               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int is_master;
+       u8 val;
+
+       /* master/slave mode */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               is_master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               is_master = 0;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported clock\n");
+               return -EINVAL;
+       }
+
+       /* format */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               val = (is_master) ? MAX98090_I2S_M : MAX98090_I2S_S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               val = (is_master) ? MAX98090_RJ_M : MAX98090_RJ_S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = (is_master) ? MAX98090_LJ_M : MAX98090_LJ_S;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported format\n");
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, MAX98090_0x06_DAI_IF,
+                           MAX98090_DAI_IF_MASK, val);
+
+       return 0;
+}
+
+#define MAX98090_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98090_dai_ops = {
+       .set_sysclk     = max98090_dai_set_sysclk,
+       .set_fmt        = max98090_dai_set_fmt,
+       .hw_params      = max98090_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98090_dai = {
+       .name = "max98090-Hifi",
+       .playback = {
+               .stream_name    = "Playback",
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rates          = MAX98090_RATES,
+               .formats        = MAX98090_FORMATS,
+       },
+       .ops = &max98090_dai_ops,
+};
+
+static int max98090_probe(struct snd_soc_codec *codec)
+{
+       struct max98090_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct device *dev = codec->dev;
+       int ret;
+
+       codec->control_data = priv->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* Device active */
+       snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN,
+                           MAX98090_SHDNRUN, MAX98090_SHDNRUN);
+
+       return 0;
+}
+
+static int max98090_remove(struct snd_soc_codec *codec)
+{
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98090 = {
+       .probe                  = max98090_probe,
+       .remove                 = max98090_remove,
+       .controls               = max98090_snd_controls,
+       .num_controls           = ARRAY_SIZE(max98090_snd_controls),
+       .dapm_widgets           = max98090_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(max98090_dapm_widgets),
+       .dapm_routes            = max98090_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(max98090_audio_map),
+};
+
+static const struct regmap_config max98090_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = MAX98090_REG_END,
+       .volatile_reg           = max98090_volatile,
+       .cache_type             = REGCACHE_RBTREE,
+       .reg_defaults           = max98090_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(max98090_reg_defaults),
+};
+
+static int max98090_i2c_probe(struct i2c_client *i2c,
+                             const struct i2c_device_id *id)
+{
+       struct max98090_priv *priv;
+       struct device *dev = &i2c->dev;
+       unsigned int val;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(struct max98090_priv),
+                           GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(dev, "Failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, priv);
+
+       ret = regmap_read(priv->regmap, MAX98090_0xFF_REV_ID, &val);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device revision: %d\n", ret);
+               return ret;
+       }
+       dev_info(dev, "revision 0x%02x\n", val);
+
+       ret = snd_soc_register_codec(dev,
+                                    &soc_codec_dev_max98090,
+                                    &max98090_dai, 1);
+
+       return ret;
+}
+
+static int max98090_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id max98090_i2c_id[] = {
+       { "max98090", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
+
+static struct i2c_driver max98090_i2c_driver = {
+       .driver = {
+               .name = "max98090",
+               .owner = THIS_MODULE,
+       },
+       .probe          = max98090_i2c_probe,
+       .remove         = max98090_i2c_remove,
+       .id_table       = max98090_i2c_id,
+};
+module_i2c_driver(max98090_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98090 driver");
+MODULE_AUTHOR("Peter Hsiang, Kuninori Morimoto");
+MODULE_LICENSE("GPL");
index 960d0e93cce9463a3592c17d74de0f9d5ad4bf19..d6ca615489eecfb5eddf8c96342da7ab9f2b49d1 100644 (file)
@@ -1382,7 +1382,7 @@ static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
                                        timesofbclk);
        if (coeff < 0) {
                dev_err(codec->dev, "Fail to get coeff\n");
-               return -EINVAL;
+               return coeff;
        }
 
        switch (params_format(params)) {
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
new file mode 100644 (file)
index 0000000..38145ba
--- /dev/null
@@ -0,0 +1,255 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include <linux/i2c.h>
+
+#include <linux/mfd/si476x-core.h>
+
+enum si476x_audio_registers {
+       SI476X_DIGITAL_IO_OUTPUT_FORMAT         = 0x0203,
+       SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE    = 0x0202,
+};
+
+enum si476x_digital_io_output_format {
+       SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT       = 11,
+       SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT     = 8,
+};
+
+#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK    ((0b111 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \
+                                                 (0b111 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT))
+#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK   (0b1111110)
+
+enum si476x_daudio_formats {
+       SI476X_DAUDIO_MODE_I2S          = (0x0 << 1),
+       SI476X_DAUDIO_MODE_DSP_A        = (0x6 << 1),
+       SI476X_DAUDIO_MODE_DSP_B        = (0x7 << 1),
+       SI476X_DAUDIO_MODE_LEFT_J       = (0x8 << 1),
+       SI476X_DAUDIO_MODE_RIGHT_J      = (0x9 << 1),
+
+       SI476X_DAUDIO_MODE_IB           = (1 << 5),
+       SI476X_DAUDIO_MODE_IF           = (1 << 6),
+};
+
+enum si476x_pcm_format {
+       SI476X_PCM_FORMAT_S8            = 2,
+       SI476X_PCM_FORMAT_S16_LE        = 4,
+       SI476X_PCM_FORMAT_S20_3LE       = 5,
+       SI476X_PCM_FORMAT_S24_LE        = 6,
+};
+
+static unsigned int si476x_codec_read(struct snd_soc_codec *codec,
+                                     unsigned int reg)
+{
+       int err;
+       struct si476x_core *core = codec->control_data;
+
+       si476x_core_lock(core);
+       err = si476x_core_cmd_get_property(core, reg);
+       si476x_core_unlock(core);
+
+       return err;
+}
+
+static int si476x_codec_write(struct snd_soc_codec *codec,
+                             unsigned int reg, unsigned int val)
+{
+       int err;
+       struct si476x_core *core = codec->control_data;
+
+       si476x_core_lock(core);
+       err = si476x_core_cmd_set_property(core, reg, val);
+       si476x_core_unlock(core);
+
+       return err;
+}
+
+static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                   unsigned int fmt)
+{
+       int err;
+       u16 format = 0;
+
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+               return -EINVAL;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               format |= SI476X_DAUDIO_MODE_DSP_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               format |= SI476X_DAUDIO_MODE_DSP_B;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               format |= SI476X_DAUDIO_MODE_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               format |= SI476X_DAUDIO_MODE_RIGHT_J;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format |= SI476X_DAUDIO_MODE_LEFT_J;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       format |= SI476X_DAUDIO_MODE_IB;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       format |= SI476X_DAUDIO_MODE_IB |
+                               SI476X_DAUDIO_MODE_IF;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       format |= SI476X_DAUDIO_MODE_IB;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       format |= SI476X_DAUDIO_MODE_IF;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
+                                 SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK,
+                                 format);
+       if (err < 0) {
+               dev_err(codec_dai->codec->dev, "Failed to set output format\n");
+               return err;
+       }
+       
+       return 0;
+}
+
+static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       int rate, width, err;
+
+       rate = params_rate(params);
+       if (rate < 32000 || rate > 48000) {
+               dev_err(dai->codec->dev, "Rate: %d is not supported\n", rate);
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               width = SI476X_PCM_FORMAT_S8;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               width = SI476X_PCM_FORMAT_S16_LE;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               width = SI476X_PCM_FORMAT_S20_3LE;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               width = SI476X_PCM_FORMAT_S24_LE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE,
+                           rate);
+       if (err < 0) {
+               dev_err(dai->codec->dev, "Failed to set sample rate\n");
+               return err;
+       }
+
+       err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
+                                 SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK,
+                                 (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | 
+                                 (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
+       if (err < 0) {
+               dev_err(dai->codec->dev, "Failed to set output width\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int si476x_codec_probe(struct snd_soc_codec *codec)
+{
+       codec->control_data = i2c_mfd_cell_to_core(codec->dev);
+       return 0;
+}
+
+static struct snd_soc_dai_ops si476x_dai_ops = {
+       .hw_params      = si476x_codec_hw_params,
+       .set_fmt        = si476x_codec_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver si476x_dai = {
+       .name           = "si476x-codec",
+       .capture        = {
+               .stream_name    = "Capture",
+               .channels_min   = 2,
+               .channels_max   = 2,
+
+               .rates = SNDRV_PCM_RATE_32000 |
+               SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S8 |
+               SNDRV_PCM_FMTBIT_S16_LE |
+               SNDRV_PCM_FMTBIT_S20_3LE |
+               SNDRV_PCM_FMTBIT_S24_LE
+       },
+       .ops            = &si476x_dai_ops,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_si476x = {
+       .probe  = si476x_codec_probe,
+       .read   = si476x_codec_read,
+       .write  = si476x_codec_write,
+};
+
+static int __devinit si476x_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_si476x,
+                                     &si476x_dai, 1);
+}
+
+static int __devexit si476x_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+MODULE_ALIAS("platform:si476x-codec");
+
+static struct platform_driver si476x_platform_driver = {
+       .driver         = {
+               .name   = "si476x-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = si476x_platform_probe,
+       .remove         = __devexit_p(si476x_platform_remove),
+};
+module_platform_driver(si476x_platform_driver);
+
+MODULE_AUTHOR("Andrey Smirnov <andrey.smirnov@convergeddevices.net>");
+MODULE_DESCRIPTION("ASoC Si4761/64 codec driver");
+MODULE_LICENSE("GPL");
index f230292ba96bbfc0c5cf7c7264dd4435de3d7590..e39e08d5d8e42429b8b2cb27bf1b08104a65454f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/cdev.h>
 #include <linux/slab.h>
@@ -65,6 +66,7 @@ struct aic32x4_priv {
        u32 power_cfg;
        u32 micpga_routing;
        bool swapdacs;
+       int rstn_gpio;
 };
 
 /* 0dB min, 1dB steps */
@@ -627,10 +629,20 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
 {
        struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
        u32 tmp_reg;
+       int ret;
 
        codec->hw_write = (hw_write_t) i2c_master_send;
        codec->control_data = aic32x4->control_data;
 
+       if (aic32x4->rstn_gpio >= 0) {
+               ret = devm_gpio_request_one(codec->dev, aic32x4->rstn_gpio,
+                               GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
+               if (ret != 0)
+                       return ret;
+               ndelay(10);
+               gpio_set_value(aic32x4->rstn_gpio, 1);
+       }
+
        snd_soc_write(codec, AIC32X4_RESET, 0x01);
 
        /* Power platform configuration */
@@ -675,6 +687,16 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
                             ARRAY_SIZE(aic32x4_snd_controls));
        aic32x4_add_widgets(codec);
 
+       /*
+        * Workaround: for an unknown reason, the ADC needs to be powered up
+        * and down for the first capture to work properly. It seems related to
+        * a HW BUG or some kind of behavior not documented in the datasheet.
+        */
+       tmp_reg = snd_soc_read(codec, AIC32X4_ADCSETUP);
+       snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg |
+                               AIC32X4_LADC_EN | AIC32X4_RADC_EN);
+       snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg);
+
        return 0;
 }
 
@@ -713,10 +735,12 @@ static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c,
                aic32x4->power_cfg = pdata->power_cfg;
                aic32x4->swapdacs = pdata->swapdacs;
                aic32x4->micpga_routing = pdata->micpga_routing;
+               aic32x4->rstn_gpio = pdata->rstn_gpio;
        } else {
                aic32x4->power_cfg = 0;
                aic32x4->swapdacs = false;
                aic32x4->micpga_routing = 0;
+               aic32x4->rstn_gpio = -1;
        }
 
        ret = snd_soc_register_codec(&i2c->dev,
index aae2b2440398aaac19a62eac62b6e7788e41035c..35774223fd91f2a03c4ce4ed56c45df3f3ff2a3d 100644 (file)
@@ -94,6 +94,9 @@
 #define AIC32X4_WORD_LEN_24BITS                0x02
 #define AIC32X4_WORD_LEN_32BITS                0x03
 
+#define AIC32X4_LADC_EN                        (1 << 7)
+#define AIC32X4_RADC_EN                        (1 << 6)
+
 #define AIC32X4_I2S_MODE               0x00
 #define AIC32X4_DSP_MODE               0x01
 #define AIC32X4_RIGHT_JUSTIFIED_MODE   0x02
index 99afc003a084cabfc47511047247c0416da8931f..40256b52625977893bc19d280827c27f81337101 100644 (file)
@@ -31,6 +31,9 @@
 
 #define DEVICE_ID_WM0010       10
 
+/* We only support v1 of the .dfw INFO record */
+#define INFO_VERSION           1
+
 enum dfw_cmd {
        DFW_CMD_FUSE = 0x01,
        DFW_CMD_CODE_HDR,
@@ -46,6 +49,13 @@ struct dfw_binrec {
        uint8_t data[0];
 } __packed;
 
+struct dfw_inforec {
+       u8 info_version;
+       u8 tool_major_version;
+       u8 tool_minor_version;
+       u8 dsp_target;
+};
+
 struct dfw_pllrec {
        u8 command;
        u32 length:24;
@@ -97,7 +107,6 @@ struct wm0010_priv {
 
        enum wm0010_state state;
        bool boot_failed;
-       int boot_done;
        bool ready;
        bool pll_running;
        int max_spi_freq;
@@ -234,7 +243,7 @@ static void wm0010_boot_xfer_complete(void *data)
                        break;
 
                case 0x55555555:
-                       if (wm0010->boot_done == 0)
+                       if (wm0010->state < WM0010_STAGE2)
                                break;
                        dev_err(codec->dev,
                                "%d: ROM bootloader running in stage 2\n", i);
@@ -321,7 +330,6 @@ static void wm0010_boot_xfer_complete(void *data)
                        break;
        }
 
-       wm0010->boot_done++;
        if (xfer->done)
                complete(xfer->done);
 }
@@ -334,94 +342,198 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
                data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
 }
 
-static int wm0010_boot(struct snd_soc_codec *codec)
+static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
 {
        struct spi_device *spi = to_spi_device(codec->dev);
        struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
-       unsigned long flags;
        struct list_head xfer_list;
        struct wm0010_boot_xfer *xfer;
        int ret;
        struct completion done;
        const struct firmware *fw;
        const struct dfw_binrec *rec;
-       struct spi_message m;
-       struct spi_transfer t;
-       struct dfw_pllrec pll_rec;
-       u32 *img, *p;
-       u64 *img_swap;
-       u8 *out;
+       const struct dfw_inforec *inforec;
+       u64 *img;
+       u8 *out, dsp;
        u32 len, offset;
-       int i;
 
-       spin_lock_irqsave(&wm0010->irq_lock, flags);
-       if (wm0010->state != WM0010_POWER_OFF)
-               dev_warn(wm0010->dev, "DSP already powered up!\n");
-       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+       INIT_LIST_HEAD(&xfer_list);
 
-       if (wm0010->sysclk > 26000000) {
-               dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n");
-               ret = -ECANCELED;
-               goto err;
+       ret = request_firmware(&fw, name, codec->dev);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request application: %d\n",
+                       ret);
+               return ret;
        }
 
-       INIT_LIST_HEAD(&xfer_list);
+       rec = (const struct dfw_binrec *)fw->data;
+       inforec = (const struct dfw_inforec *)rec->data;
+       offset = 0;
+       dsp = inforec->dsp_target;
+       wm0010->boot_failed = false;
+       BUG_ON(!list_empty(&xfer_list));
+       init_completion(&done);
 
-       mutex_lock(&wm0010->lock);
-       wm0010->pll_running = false;
+       /* First record should be INFO */
+       if (rec->command != DFW_CMD_INFO) {
+               dev_err(codec->dev, "First record not INFO\r\n");
+               ret = -EINVAL;
+               goto abort;
+       }
 
-       dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
+       if (inforec->info_version != INFO_VERSION) {
+               dev_err(codec->dev,
+                       "Unsupported version (%02d) of INFO record\r\n",
+                       inforec->info_version);
+               ret = -EINVAL;
+               goto abort;
+       }
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies),
-                                   wm0010->core_supplies);
-       if (ret != 0) {
-               dev_err(&spi->dev, "Failed to enable core supplies: %d\n",
-                       ret);
-               mutex_unlock(&wm0010->lock);
-               goto err;
+       dev_dbg(codec->dev, "Version v%02d INFO record found\r\n",
+               inforec->info_version);
+
+       /* Check it's a DSP file */
+       if (dsp != DEVICE_ID_WM0010) {
+               dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
+               ret = -EINVAL;
+               goto abort;
        }
 
-       ret = regulator_enable(wm0010->dbvdd);
-       if (ret != 0) {
-               dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret);
-               goto err_core;
+       /* Skip the info record as we don't need to send it */
+       offset += ((rec->length) + 8);
+       rec = (void *)&rec->data[rec->length];
+
+       while (offset < fw->size) {
+               dev_dbg(codec->dev,
+                       "Packet: command %d, data length = 0x%x\r\n",
+                       rec->command, rec->length);
+               len = rec->length + 8;
+
+               out = kzalloc(len, GFP_KERNEL);
+               if (!out) {
+                       dev_err(codec->dev,
+                               "Failed to allocate RX buffer\n");
+                       ret = -ENOMEM;
+                       goto abort1;
+               }
+
+               img = kzalloc(len, GFP_KERNEL);
+               if (!img) {
+                       dev_err(codec->dev,
+                               "Failed to allocate image buffer\n");
+                       ret = -ENOMEM;
+                       goto abort1;
+               }
+
+               byte_swap_64((u64 *)&rec->command, img, len);
+
+               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+               if (!xfer) {
+                       dev_err(codec->dev, "Failed to allocate xfer\n");
+                       ret = -ENOMEM;
+                       goto abort1;
+               }
+
+               xfer->codec = codec;
+               list_add_tail(&xfer->list, &xfer_list);
+
+               spi_message_init(&xfer->m);
+               xfer->m.complete = wm0010_boot_xfer_complete;
+               xfer->m.context = xfer;
+               xfer->t.tx_buf = img;
+               xfer->t.rx_buf = out;
+               xfer->t.len = len;
+               xfer->t.bits_per_word = 8;
+
+               if (!wm0010->pll_running) {
+                       xfer->t.speed_hz = wm0010->sysclk / 6;
+               } else {
+                       xfer->t.speed_hz = wm0010->max_spi_freq;
+
+                       if (wm0010->board_max_spi_speed &&
+                          (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
+                                       xfer->t.speed_hz = wm0010->board_max_spi_speed;
+               }
+
+               /* Store max usable spi frequency for later use */
+               wm0010->max_spi_freq = xfer->t.speed_hz;
+
+               spi_message_add_tail(&xfer->t, &xfer->m);
+
+               offset += ((rec->length) + 8);
+               rec = (void *)&rec->data[rec->length];
+
+               if (offset >= fw->size) {
+                       dev_dbg(codec->dev, "All transfers scheduled\n");
+                       xfer->done = &done;
+               }
+
+               ret = spi_async(spi, &xfer->m);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Write failed: %d\n", ret);
+                       goto abort1;
+               }
+
+               if (wm0010->boot_failed) {
+                       dev_dbg(codec->dev, "Boot fail!\n");
+                       ret = -EINVAL;
+                       goto abort1;
+               }
        }
 
-       /* Release reset */
-       gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
-       spin_lock_irqsave(&wm0010->irq_lock, flags);
-       wm0010->state = WM0010_OUT_OF_RESET;
-       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+       wait_for_completion(&done);
+
+       ret = 0;
+
+abort1:
+       while (!list_empty(&xfer_list)) {
+               xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
+                                       list);
+               kfree(xfer->t.rx_buf);
+               kfree(xfer->t.tx_buf);
+               list_del(&xfer->list);
+               kfree(xfer);
+       }
+
+abort:
+       release_firmware(fw);
+       return ret;
+}
+
+static int wm0010_stage2_load(struct snd_soc_codec *codec)
+{
+       struct spi_device *spi = to_spi_device(codec->dev);
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+       const struct firmware *fw;
+       struct spi_message m;
+       struct spi_transfer t;
+       u32 *img;
+       u8 *out;
+       int i;
+       int ret = 0;
 
-       /* First the bootloader */
        ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request stage2 loader: %d\n",
                        ret);
-               goto abort;
+               return ret;
        }
 
-       if (!wait_for_completion_timeout(&wm0010->boot_completion,
-                                        msecs_to_jiffies(10)))
-               dev_err(codec->dev, "Failed to get interrupt from DSP\n");
-
-       spin_lock_irqsave(&wm0010->irq_lock, flags);
-       wm0010->state = WM0010_BOOTROM;
-       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
-
        dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
 
        /* Copy to local buffer first as vmalloc causes problems for dma */
        img = kzalloc(fw->size, GFP_KERNEL);
        if (!img) {
                dev_err(codec->dev, "Failed to allocate image buffer\n");
-               goto abort;
+               ret = -ENOMEM;
+               goto abort2;
        }
 
        out = kzalloc(fw->size, GFP_KERNEL);
        if (!out) {
                dev_err(codec->dev, "Failed to allocate output buffer\n");
-               goto abort;
+               ret = -ENOMEM;
+               goto abort1;
        }
 
        memcpy(img, &fw->data[0], fw->size);
@@ -447,20 +559,97 @@ static int wm0010_boot(struct snd_soc_codec *codec)
        /* Look for errors from the boot ROM */
        for (i = 0; i < fw->size; i++) {
                if (out[i] != 0x55) {
-                       ret = -EBUSY;
                        dev_err(codec->dev, "Boot ROM error: %x in %d\n",
                                out[i], i);
                        wm0010_mark_boot_failure(wm0010);
+                       ret = -EBUSY;
                        goto abort;
                }
        }
-
-       release_firmware(fw);
-       kfree(img);
+abort:
        kfree(out);
+abort1:
+       kfree(img);
+abort2:
+       release_firmware(fw);
+
+       return ret;
+}
+
+static int wm0010_boot(struct snd_soc_codec *codec)
+{
+       struct spi_device *spi = to_spi_device(codec->dev);
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+       unsigned long flags;
+       int ret;
+       const struct firmware *fw;
+       struct spi_message m;
+       struct spi_transfer t;
+       struct dfw_pllrec pll_rec;
+       u32 *p, len;
+       u64 *img_swap;
+       u8 *out;
+       int i;
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       if (wm0010->state != WM0010_POWER_OFF)
+               dev_warn(wm0010->dev, "DSP already powered up!\n");
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       if (wm0010->sysclk > 26000000) {
+               dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n");
+               ret = -ECANCELED;
+               goto err;
+       }
+
+       mutex_lock(&wm0010->lock);
+       wm0010->pll_running = false;
+
+       dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies),
+                                   wm0010->core_supplies);
+       if (ret != 0) {
+               dev_err(&spi->dev, "Failed to enable core supplies: %d\n",
+                       ret);
+               mutex_unlock(&wm0010->lock);
+               goto err;
+       }
+
+       ret = regulator_enable(wm0010->dbvdd);
+       if (ret != 0) {
+               dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret);
+               goto err_core;
+       }
+
+       /* Release reset */
+       gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       wm0010->state = WM0010_OUT_OF_RESET;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       /* First the bootloader */
+       ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request stage2 loader: %d\n",
+                       ret);
+               goto abort;
+       }
+
+       if (!wait_for_completion_timeout(&wm0010->boot_completion,
+                                        msecs_to_jiffies(20)))
+               dev_err(codec->dev, "Failed to get interrupt from DSP\n");
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       wm0010->state = WM0010_BOOTROM;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       ret = wm0010_stage2_load(codec);
+       if (ret)
+               goto abort;
 
        if (!wait_for_completion_timeout(&wm0010->boot_completion,
-                                        msecs_to_jiffies(10)))
+                                        msecs_to_jiffies(20)))
                dev_err(codec->dev, "Failed to get interrupt from DSP loader.\n");
 
        spin_lock_irqsave(&wm0010->irq_lock, flags);
@@ -535,110 +724,10 @@ static int wm0010_boot(struct snd_soc_codec *codec)
        } else
                dev_dbg(codec->dev, "Not enabling DSP PLL.");
 
-       ret = request_firmware(&fw, "wm0010.dfw", codec->dev);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request application: %d\n",
-                       ret);
-               goto abort;
-       }
-
-       rec = (const struct dfw_binrec *)fw->data;
-       offset = 0;
-       wm0010->boot_done = 0;
-       wm0010->boot_failed = false;
-       BUG_ON(!list_empty(&xfer_list));
-       init_completion(&done);
+       ret = wm0010_firmware_load("wm0010.dfw", codec);
 
-       /* First record should be INFO */
-       if (rec->command != DFW_CMD_INFO) {
-               dev_err(codec->dev, "First record not INFO\r\n");
-               goto abort;
-       }
-
-       /* Check it's a 0010 file */
-       if (rec->data[0] != DEVICE_ID_WM0010) {
-               dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
+       if (ret != 0)
                goto abort;
-       }
-
-       /* Skip the info record as we don't need to send it */
-       offset += ((rec->length) + 8);
-       rec = (void *)&rec->data[rec->length];
-
-       while (offset < fw->size) {
-               dev_dbg(codec->dev,
-                       "Packet: command %d, data length = 0x%x\r\n",
-                       rec->command, rec->length);
-               len = rec->length + 8;
-
-               out = kzalloc(len, GFP_KERNEL);
-               if (!out) {
-                       dev_err(codec->dev,
-                               "Failed to allocate RX buffer\n");
-                       goto abort;
-               }
-
-               img_swap = kzalloc(len, GFP_KERNEL);
-               if (!img_swap) {
-                       dev_err(codec->dev,
-                               "Failed to allocate image buffer\n");
-                       goto abort;
-               }
-
-               /* We need to re-order for 0010 */
-               byte_swap_64((u64 *)&rec->command, img_swap, len);
-
-               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
-               if (!xfer) {
-                       dev_err(codec->dev, "Failed to allocate xfer\n");
-                       goto abort;
-               }
-
-               xfer->codec = codec;
-               list_add_tail(&xfer->list, &xfer_list);
-
-               spi_message_init(&xfer->m);
-               xfer->m.complete = wm0010_boot_xfer_complete;
-               xfer->m.context = xfer;
-               xfer->t.tx_buf = img_swap;
-               xfer->t.rx_buf = out;
-               xfer->t.len = len;
-               xfer->t.bits_per_word = 8;
-
-               if (!wm0010->pll_running) {
-                       xfer->t.speed_hz = wm0010->sysclk / 6;
-               } else {
-                       xfer->t.speed_hz = wm0010->max_spi_freq;
-
-                       if (wm0010->board_max_spi_speed &&
-                          (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
-                                       xfer->t.speed_hz = wm0010->board_max_spi_speed;
-               }
-
-               /* Store max usable spi frequency for later use */
-               wm0010->max_spi_freq = xfer->t.speed_hz;
-
-               spi_message_add_tail(&xfer->t, &xfer->m);
-
-               offset += ((rec->length) + 8);
-               rec = (void *)&rec->data[rec->length];
-
-               if (offset >= fw->size) {
-                       dev_dbg(codec->dev, "All transfers scheduled\n");
-                       xfer->done = &done;
-               }
-
-               ret = spi_async(spi, &xfer->m);
-               if (ret != 0) {
-                       dev_err(codec->dev, "Write failed: %d\n", ret);
-                       goto abort;
-               }
-
-               if (wm0010->boot_failed)
-                       goto abort;
-       }
-
-       wait_for_completion(&done);
 
        spin_lock_irqsave(&wm0010->irq_lock, flags);
        wm0010->state = WM0010_FIRMWARE;
@@ -646,17 +735,6 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 
        mutex_unlock(&wm0010->lock);
 
-       release_firmware(fw);
-
-       while (!list_empty(&xfer_list)) {
-               xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
-                                       list);
-               kfree(xfer->t.rx_buf);
-               kfree(xfer->t.tx_buf);
-               list_del(&xfer->list);
-               kfree(xfer);
-       }
-
        return 0;