From d65ab0b04d7ebe58af82bfa65deb9e971f8357fe Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2013 12:02:51 +0000 Subject: [PATCH] --- yaml --- r: 353494 b: refs/heads/master c: ef5c2eba2412596f1a022c11caf74428bffd9abe h: refs/heads/master v: v3 --- [refs] | 2 +- .../devicetree/bindings/sound/ak4642.txt | 17 - .../devicetree/bindings/sound/cs4271.txt | 12 - .../sound/nvidia,tegra-audio-wm9712.txt | 51 - .../bindings/sound/nvidia,tegra20-ac97.txt | 22 - .../bindings/sound/omap-twl4030.txt | 46 - .../devicetree/bindings/sound/renesas,fsi.txt | 26 - .../bindings/sound/samsung,smdk-wm8994.txt | 14 - .../devicetree/bindings/sound/samsung-i2s.txt | 63 - .../devicetree/bindings/sound/tlv320aic3x.txt | 6 - .../devicetree/bindings/sound/wm8962.txt | 16 - .../arch/arm/boot/dts/exynos5250-smdk5250.dts | 26 - trunk/arch/arm/boot/dts/exynos5250.dtsi | 44 +- trunk/arch/arm/mach-exynos/mach-exynos5-dt.c | 6 - trunk/arch/arm/mach-pxa/pxa27x.c | 20 +- trunk/arch/arm/mach-shmobile/board-ap4evb.c | 42 +- .../arm/mach-shmobile/board-armadillo800eva.c | 34 +- trunk/arch/arm/mach-shmobile/board-kzm9g.c | 20 +- trunk/arch/arm/mach-shmobile/board-mackerel.c | 42 +- trunk/arch/arm/plat-samsung/dma-ops.c | 10 +- .../arm/plat-samsung/include/plat/dma-ops.h | 3 +- trunk/arch/arm/plat-samsung/s3c-dma-ops.c | 3 +- trunk/arch/sh/boards/mach-ecovec24/setup.c | 27 +- trunk/arch/sh/boards/mach-se/7724/setup.c | 29 +- trunk/drivers/base/regmap/internal.h | 18 - trunk/drivers/base/regmap/regmap-spi.c | 52 - trunk/drivers/base/regmap/regmap.c | 301 +- trunk/drivers/misc/Kconfig | 2 +- trunk/drivers/misc/atmel-ssc.c | 2 +- trunk/drivers/spi/spi-s3c64xx.c | 77 +- trunk/include/linux/mfd/arizona/pdata.h | 9 - trunk/include/linux/regmap.h | 28 - trunk/include/sound/cs4271.h | 15 - trunk/include/sound/da7213.h | 52 + trunk/include/sound/max98090.h | 29 - trunk/include/sound/saif.h | 16 + trunk/include/sound/sh_fsi.h | 70 +- trunk/include/sound/simple_card.h | 12 +- trunk/include/sound/soc-dai.h | 8 +- trunk/include/sound/soc.h | 6 +- trunk/include/sound/tlv320aic3x.h | 10 - trunk/include/sound/wm2000.h | 3 + trunk/include/sound/wm2200.h | 22 +- trunk/sound/arm/pxa2xx-ac97-lib.c | 8 +- trunk/sound/soc/atmel/Kconfig | 6 +- trunk/sound/soc/atmel/atmel-pcm-pdc.c | 4 +- trunk/sound/soc/atmel/atmel-pcm.c | 2 +- trunk/sound/soc/atmel/atmel-pcm.h | 6 +- trunk/sound/soc/atmel/atmel_ssc_dai.c | 14 +- trunk/sound/soc/atmel/sam9g20_wm8731.c | 6 +- trunk/sound/soc/codecs/Kconfig | 4 + trunk/sound/soc/codecs/Makefile | 2 + trunk/sound/soc/codecs/ak4642.c | 33 +- trunk/sound/soc/codecs/arizona.c | 264 +- trunk/sound/soc/codecs/arizona.h | 8 +- trunk/sound/soc/codecs/cs4271.c | 34 - trunk/sound/soc/codecs/cs42l52.c | 4 +- trunk/sound/soc/codecs/da7213.c | 1599 ++++++++++ trunk/sound/soc/codecs/da7213.h | 523 ++++ trunk/sound/soc/codecs/max98090.c | 2685 +++-------------- trunk/sound/soc/codecs/max98090.h | 1549 ---------- trunk/sound/soc/codecs/tlv320aic3x.c | 87 +- trunk/sound/soc/codecs/tlv320aic3x.h | 4 - trunk/sound/soc/codecs/tlv320dac33.c | 16 + trunk/sound/soc/codecs/twl4030.c | 85 +- trunk/sound/soc/codecs/twl6040.c | 62 +- trunk/sound/soc/codecs/wm2000.c | 66 +- trunk/sound/soc/codecs/wm2000.h | 3 - trunk/sound/soc/codecs/wm2200.c | 62 +- trunk/sound/soc/codecs/wm5100.c | 13 - trunk/sound/soc/codecs/wm5102.c | 159 +- trunk/sound/soc/codecs/wm5110.c | 94 +- trunk/sound/soc/codecs/wm8350.c | 10 +- trunk/sound/soc/codecs/wm8804.c | 3 + trunk/sound/soc/codecs/wm8962.c | 37 +- trunk/sound/soc/codecs/wm8983.c | 41 +- trunk/sound/soc/codecs/wm8985.c | 43 +- trunk/sound/soc/codecs/wm8994.c | 10 +- trunk/sound/soc/codecs/wm_adsp.c | 525 +--- trunk/sound/soc/codecs/wm_adsp.h | 18 - trunk/sound/soc/codecs/wmfw.h | 15 +- trunk/sound/soc/davinci/davinci-evm.c | 6 +- trunk/sound/soc/davinci/davinci-mcasp.c | 2 +- trunk/sound/soc/dwc/designware_i2s.c | 4 - trunk/sound/soc/fsl/imx-audmux.c | 2 +- trunk/sound/soc/generic/simple-card.c | 63 +- trunk/sound/soc/mxs/mxs-saif.c | 49 +- trunk/sound/soc/omap/Kconfig | 19 +- trunk/sound/soc/omap/Makefile | 4 + trunk/sound/soc/omap/n810.c | 4 +- trunk/sound/soc/omap/omap-hdmi.c | 2 - trunk/sound/soc/omap/omap-mcpdm.c | 4 + trunk/sound/soc/omap/omap-pcm.c | 14 +- trunk/sound/soc/omap/omap-twl4030.c | 204 +- trunk/sound/soc/omap/omap3pandora.c | 8 +- trunk/sound/soc/omap/rx51.c | 8 +- trunk/sound/soc/omap/sdp3430.c | 278 ++ trunk/sound/soc/omap/zoom2.c | 207 ++ trunk/sound/soc/pxa/palm27x.c | 38 +- trunk/sound/soc/samsung/Kconfig | 6 +- trunk/sound/soc/samsung/dma.c | 3 +- trunk/sound/soc/samsung/dma.h | 1 - trunk/sound/soc/samsung/i2s.c | 267 +- trunk/sound/soc/samsung/i2s.h | 7 + trunk/sound/soc/samsung/s3c24xx-i2s.c | 2 +- trunk/sound/soc/samsung/smdk_wm8580.c | 7 +- trunk/sound/soc/samsung/smdk_wm8994.c | 30 +- trunk/sound/soc/sh/fsi.c | 242 +- trunk/sound/soc/soc-compress.c | 123 +- trunk/sound/soc/soc-core.c | 135 +- trunk/sound/soc/soc-dapm.c | 6 +- trunk/sound/soc/soc-pcm.c | 19 +- trunk/sound/soc/tegra/Kconfig | 19 - trunk/sound/soc/tegra/Makefile | 4 - trunk/sound/soc/tegra/tegra20_ac97.c | 480 --- trunk/sound/soc/tegra/tegra20_ac97.h | 95 - trunk/sound/soc/tegra/tegra20_das.c | 13 - trunk/sound/soc/tegra/tegra30_ahub.c | 4 +- trunk/sound/soc/tegra/tegra30_i2s.c | 4 +- trunk/sound/soc/tegra/tegra_asoc_utils.c | 53 - trunk/sound/soc/tegra/tegra_asoc_utils.h | 1 - trunk/sound/soc/tegra/tegra_wm9712.c | 176 -- trunk/sound/soc/ux500/mop500.c | 2 +- 123 files changed, 4214 insertions(+), 7818 deletions(-) delete mode 100644 trunk/Documentation/devicetree/bindings/sound/ak4642.txt delete mode 100644 trunk/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt delete mode 100644 trunk/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt delete mode 100644 trunk/Documentation/devicetree/bindings/sound/renesas,fsi.txt delete mode 100644 trunk/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt delete mode 100644 trunk/Documentation/devicetree/bindings/sound/samsung-i2s.txt delete mode 100644 trunk/Documentation/devicetree/bindings/sound/wm8962.txt create mode 100644 trunk/include/sound/da7213.h delete mode 100755 trunk/include/sound/max98090.h create mode 100644 trunk/include/sound/saif.h create mode 100644 trunk/sound/soc/codecs/da7213.c create mode 100644 trunk/sound/soc/codecs/da7213.h mode change 100755 => 100644 trunk/sound/soc/codecs/max98090.c delete mode 100755 trunk/sound/soc/codecs/max98090.h create mode 100644 trunk/sound/soc/omap/sdp3430.c create mode 100644 trunk/sound/soc/omap/zoom2.c delete mode 100644 trunk/sound/soc/tegra/tegra20_ac97.c delete mode 100644 trunk/sound/soc/tegra/tegra20_ac97.h delete mode 100644 trunk/sound/soc/tegra/tegra_wm9712.c diff --git a/[refs] b/[refs] index 649ecadd245f..000c2322081f 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e951f7e85de428bcbbe8034cd353e17799baa35b +refs/heads/master: ef5c2eba2412596f1a022c11caf74428bffd9abe diff --git a/trunk/Documentation/devicetree/bindings/sound/ak4642.txt b/trunk/Documentation/devicetree/bindings/sound/ak4642.txt deleted file mode 100644 index 623d4e70ae11..000000000000 --- a/trunk/Documentation/devicetree/bindings/sound/ak4642.txt +++ /dev/null @@ -1,17 +0,0 @@ -AK4642 I2C transmitter - -This device supports I2C mode only. - -Required properties: - - - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648" - - reg : The chip select number on the I2C bus - -Example: - -&i2c { - ak4648: ak4648@0x12 { - compatible = "asahi-kasei,ak4642"; - reg = <0x12>; - }; -}; diff --git a/trunk/Documentation/devicetree/bindings/sound/cs4271.txt b/trunk/Documentation/devicetree/bindings/sound/cs4271.txt index e2cd1d7539e5..a850fb9c88ea 100644 --- a/trunk/Documentation/devicetree/bindings/sound/cs4271.txt +++ b/trunk/Documentation/devicetree/bindings/sound/cs4271.txt @@ -20,18 +20,6 @@ Optional properties: !RESET pin - cirrus,amuteb-eq-bmutec: When given, the Codec's AMUTEB=BMUTEC flag is enabled. - - cirrus,enable-soft-reset: - The CS4271 requires its LRCLK and MCLK to be stable before its RESET - line is de-asserted. That also means that clocks cannot be changed - without putting the chip back into hardware reset, which also requires - a complete re-initialization of all registers. - - One (undocumented) workaround is to assert and de-assert the PDN bit - in the MODE2 register. This workaround can be enabled with this DT - property. - - Note that this is not needed in case the clocks are stable - throughout the entire runtime of the codec. Examples: diff --git a/trunk/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt b/trunk/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt deleted file mode 100644 index be35d34e8b26..000000000000 --- a/trunk/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt +++ /dev/null @@ -1,51 +0,0 @@ -NVIDIA Tegra audio complex - -Required properties: -- compatible : "nvidia,tegra-audio-wm9712" -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the WM9712's pins, and the jacks on the board: - - WM9712 pins: - - * MONOOUT - * HPOUTL - * HPOUTR - * LOUT2 - * ROUT2 - * OUT3 - * LINEINL - * LINEINR - * PHONE - * PCBEEP - * MIC1 - * MIC2 - * Mic Bias - - Board connectors: - - * Headphone - * LineIn - * Mic - -- nvidia,ac97-controller : The phandle of the Tegra AC97 controller - - -Example: - -sound { - compatible = "nvidia,tegra-audio-wm9712-colibri_t20", - "nvidia,tegra-audio-wm9712"; - nvidia,model = "Toradex Colibri T20"; - - nvidia,audio-routing = - "Headphone", "HPOUTL", - "Headphone", "HPOUTR", - "LineIn", "LINEINL", - "LineIn", "LINEINR", - "Mic", "MIC1"; - - nvidia,ac97-controller = <&ac97>; -}; diff --git a/trunk/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt b/trunk/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt deleted file mode 100644 index c1454979c1ef..000000000000 --- a/trunk/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt +++ /dev/null @@ -1,22 +0,0 @@ -NVIDIA Tegra 20 AC97 controller - -Required properties: -- compatible : "nvidia,tegra20-ac97" -- reg : Should contain AC97 controller registers location and length -- interrupts : Should contain AC97 interrupt -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for the AC97 controller -- nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number - of the GPIO used to reset the external AC97 codec -- nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number - of the GPIO corresponding with the AC97 DAP _FS line -Example: - -ac97@70002000 { - compatible = "nvidia,tegra20-ac97"; - reg = <0x70002000 0x200>; - interrupts = <0 81 0x04>; - nvidia,dma-request-selector = <&apbdma 12>; - nvidia,codec-reset-gpio = <&gpio 170 0>; - nvidia,codec-sync-gpio = <&gpio 120 0>; -}; diff --git a/trunk/Documentation/devicetree/bindings/sound/omap-twl4030.txt b/trunk/Documentation/devicetree/bindings/sound/omap-twl4030.txt index 1ab6bc8404d5..6fae51c7f766 100644 --- a/trunk/Documentation/devicetree/bindings/sound/omap-twl4030.txt +++ b/trunk/Documentation/devicetree/bindings/sound/omap-twl4030.txt @@ -6,52 +6,6 @@ Required properties: - ti,mcbsp: phandle for the McBSP node - ti,codec: phandle for the twl4030 audio node -Optional properties: -- ti,mcbsp-voice: phandle for the McBSP node connected to the voice port of twl -- ti, jack-det-gpio: Jack detect GPIO -- ti,audio-routing: List of connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. - If the routing is not provided all possible connection will be available - -Available audio endpoints for the audio-routing table: - -Board connectors: - * Headset Stereophone - * Earpiece Spk - * Handsfree Spk - * Ext Spk - * Main Mic - * Sub Mic - * Headset Mic - * Carkit Mic - * Digital0 Mic - * Digital1 Mic - * Line In - -twl4030 pins: - * HSOL - * HSOR - * EARPIECE - * HFL - * HFR - * PREDRIVEL - * PREDRIVER - * CARKITL - * CARKITR - * MAINMIC - * SUBMIC - * HSMIC - * DIGIMIC0 - * DIGIMIC1 - * CARKITMIC - * AUXL - * AUXR - - * Headset Mic Bias - * Mic Bias 1 /* Used for Main Mic or Digimic0 */ - * Mic Bias 2 /* Used for Sub Mic or Digimic1 */ - Example: sound { diff --git a/trunk/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/trunk/Documentation/devicetree/bindings/sound/renesas,fsi.txt deleted file mode 100644 index c5be003f413e..000000000000 --- a/trunk/Documentation/devicetree/bindings/sound/renesas,fsi.txt +++ /dev/null @@ -1,26 +0,0 @@ -Renesas FSI - -Required properties: -- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi" -- reg : Should contain the register physical address and length -- interrupts : Should contain FSI interrupt - -- fsia,spdif-connection : FSI is connected by S/PDFI -- fsia,stream-mode-support : FSI supports 16bit stream mode. -- fsia,use-internal-clock : FSI uses internal clock when master mode. - -- fsib,spdif-connection : same as fsia -- fsib,stream-mode-support : same as fsia -- fsib,use-internal-clock : same as fsia - -Example: - -sh_fsi2: sh_fsi2@0xec230000 { - compatible = "renesas,sh_fsi2"; - reg = <0xec230000 0x400>; - interrupts = <0 146 0x4>; - - fsia,spdif-connection; - fsia,stream-mode-support; - fsia,use-internal-clock; -}; diff --git a/trunk/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt b/trunk/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt deleted file mode 100644 index 4686646fb122..000000000000 --- a/trunk/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt +++ /dev/null @@ -1,14 +0,0 @@ -Samsung SMDK audio complex - -Required properties: -- compatible : "samsung,smdk-wm8994" -- samsung,i2s-controller: The phandle of the Samsung I2S0 controller -- samsung,audio-codec: The phandle of the WM8994 audio codec -Example: - -sound { - compatible = "samsung,smdk-wm8994"; - - samsung,i2s-controller = <&i2s0>; - samsung,audio-codec = <&wm8994>; -}; diff --git a/trunk/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/trunk/Documentation/devicetree/bindings/sound/samsung-i2s.txt deleted file mode 100644 index 3070046da2e5..000000000000 --- a/trunk/Documentation/devicetree/bindings/sound/samsung-i2s.txt +++ /dev/null @@ -1,63 +0,0 @@ -* Samsung I2S controller - -Required SoC Specific Properties: - -- compatible : "samsung,i2s-v5" -- reg: physical base address of the controller and length of memory mapped - region. -- dmas: list of DMA controller phandle and DMA request line ordered pairs. -- dma-names: identifier string for each DMA request line in the dmas property. - These strings correspond 1:1 with the ordered pairs in dmas. - -Optional SoC Specific Properties: - -- samsung,supports-6ch: If the I2S Primary sound source has 5.1 Channel - support, this flag is enabled. -- samsung,supports-rstclr: This flag should be set if I2S software reset bit - control is required. When this flag is set I2S software reset bit will be - enabled or disabled based on need. -- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA, - then this flag is enabled. -- samsung,idma-addr: Internal DMA register base address of the audio - sub system(used in secondary sound source). - -Required Board Specific Properties: - -- gpios: The gpio specifier for data out,data in, LRCLK, CDCLK and SCLK - interface lines. The format of the gpio specifier depends on the gpio - controller. - The syntax of samsung gpio specifier is - <[phandle of the gpio controller node] - [pin number within the gpio controller] - [mux function] - [flags and pull up/down] - [drive strength]> - -Example: - -- SoC Specific Portion: - -i2s@03830000 { - compatible = "samsung,i2s-v5"; - reg = <0x03830000 0x100>; - dmas = <&pdma0 10 - &pdma0 9 - &pdma0 8>; - dma-names = "tx", "rx", "tx-sec"; - samsung,supports-6ch; - samsung,supports-rstclr; - samsung,supports-secdai; - samsung,idma-addr = <0x03000000>; -}; - -- Board Specific Portion: - -i2s@03830000 { - gpios = <&gpz 0 2 0 0>, /* I2S_0_SCLK */ - <&gpz 1 2 0 0>, /* I2S_0_CDCLK */ - <&gpz 2 2 0 0>, /* I2S_0_LRCK */ - <&gpz 3 2 0 0>, /* I2S_0_SDI */ - <&gpz 4 2 0 0>, /* I2S_0_SDO[1] */ - <&gpz 5 2 0 0>, /* I2S_0_SDO[2] */ - <&gpz 6 2 0 0>; /* I2S_0_SDO[3] */ -}; diff --git a/trunk/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/trunk/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index f47c3f589fd0..e7b98f41fa5f 100644 --- a/trunk/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/trunk/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -11,12 +11,6 @@ Optional properties: - gpio-reset - gpio pin number used for codec reset - ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality -- ai3x-micbias-vg - MicBias Voltage required. - 1 - MICBIAS output is powered to 2.0V, - 2 - MICBIAS output is powered to 2.5V, - 3 - MICBIAS output is connected to AVDD, - If this node is not mentioned or if the value is incorrect, then MicBias - is powered down. Example: diff --git a/trunk/Documentation/devicetree/bindings/sound/wm8962.txt b/trunk/Documentation/devicetree/bindings/sound/wm8962.txt deleted file mode 100644 index dceb3b1c2bb7..000000000000 --- a/trunk/Documentation/devicetree/bindings/sound/wm8962.txt +++ /dev/null @@ -1,16 +0,0 @@ -WM8962 audio CODEC - -This device supports I2C only. - -Required properties: - - - compatible : "wlf,wm8962" - - - reg : the I2C address of the device. - -Example: - -codec: wm8962@1a { - compatible = "wlf,wm8962"; - reg = <0x1a>; -}; diff --git a/trunk/arch/arm/boot/dts/exynos5250-smdk5250.dts b/trunk/arch/arm/boot/dts/exynos5250-smdk5250.dts index 4db9db0a8443..e05b18f3c33d 100644 --- a/trunk/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/trunk/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -49,11 +49,6 @@ compatible = "samsung,s524ad0xd1"; reg = <0x51>; }; - - wm8994: wm8994@1a { - compatible = "wlf,wm8994"; - reg = <0x1a>; - }; }; i2c@121D0000 { @@ -209,25 +204,4 @@ samsung,mfc-r = <0x43000000 0x800000>; samsung,mfc-l = <0x51000000 0x800000>; }; - - i2s0: i2s@03830000 { - gpios = <&gpz 0 2 0 0>, <&gpz 1 2 0 0>, <&gpz 2 2 0 0>, - <&gpz 3 2 0 0>, <&gpz 4 2 0 0>, <&gpz 5 2 0 0>, - <&gpz 6 2 0 0>; - }; - - i2s1: i2s@12D60000 { - status = "disabled"; - }; - - i2s2: i2s@12D70000 { - status = "disabled"; - }; - - sound { - compatible = "samsung,smdk-wm8994"; - - samsung,i2s-controller = <&i2s0>; - samsung,audio-codec = <&wm8994>; - }; }; diff --git a/trunk/arch/arm/boot/dts/exynos5250.dtsi b/trunk/arch/arm/boot/dts/exynos5250.dtsi index f50b4e854355..3acf594ea60b 100644 --- a/trunk/arch/arm/boot/dts/exynos5250.dtsi +++ b/trunk/arch/arm/boot/dts/exynos5250.dtsi @@ -211,9 +211,8 @@ compatible = "samsung,exynos4210-spi"; reg = <0x12d20000 0x100>; interrupts = <0 66 0>; - dmas = <&pdma0 5 - &pdma0 4>; - dma-names = "tx", "rx"; + tx-dma-channel = <&pdma0 5>; /* preliminary */ + rx-dma-channel = <&pdma0 4>; /* preliminary */ #address-cells = <1>; #size-cells = <0>; }; @@ -222,9 +221,8 @@ compatible = "samsung,exynos4210-spi"; reg = <0x12d30000 0x100>; interrupts = <0 67 0>; - dmas = <&pdma1 5 - &pdma1 4>; - dma-names = "tx", "rx"; + tx-dma-channel = <&pdma1 5>; /* preliminary */ + rx-dma-channel = <&pdma1 4>; /* preliminary */ #address-cells = <1>; #size-cells = <0>; }; @@ -233,9 +231,8 @@ compatible = "samsung,exynos4210-spi"; reg = <0x12d40000 0x100>; interrupts = <0 68 0>; - dmas = <&pdma0 7 - &pdma0 6>; - dma-names = "tx", "rx"; + tx-dma-channel = <&pdma0 7>; /* preliminary */ + rx-dma-channel = <&pdma0 6>; /* preliminary */ #address-cells = <1>; #size-cells = <0>; }; @@ -272,35 +269,6 @@ #size-cells = <0>; }; - i2s0: i2s@03830000 { - compatible = "samsung,i2s-v5"; - reg = <0x03830000 0x100>; - dmas = <&pdma0 10 - &pdma0 9 - &pdma0 8>; - dma-names = "tx", "rx", "tx-sec"; - samsung,supports-6ch; - samsung,supports-rstclr; - samsung,supports-secdai; - samsung,idma-addr = <0x03000000>; - }; - - i2s1: i2s@12D60000 { - compatible = "samsung,i2s-v5"; - reg = <0x12D60000 0x100>; - dmas = <&pdma1 12 - &pdma1 11>; - dma-names = "tx", "rx"; - }; - - i2s2: i2s@12D70000 { - compatible = "samsung,i2s-v5"; - reg = <0x12D70000 0x100>; - dmas = <&pdma0 12 - &pdma0 11>; - dma-names = "tx", "rx"; - }; - amba { #address-cells = <1>; #size-cells = <1>; diff --git a/trunk/arch/arm/mach-exynos/mach-exynos5-dt.c b/trunk/arch/arm/mach-exynos/mach-exynos5-dt.c index ea9e3020972d..e99d3d8f2bcf 100644 --- a/trunk/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/trunk/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -104,12 +104,6 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL), OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000, "exynos-tmu", NULL), - OF_DEV_AUXDATA("samsung,i2s-v5", 0x03830000, - "samsung-i2s.0", NULL), - OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D60000, - "samsung-i2s.1", NULL), - OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D70000, - "samsung-i2s.2", NULL), {}, }; diff --git a/trunk/arch/arm/mach-pxa/pxa27x.c b/trunk/arch/arm/mach-pxa/pxa27x.c index 69985b06c0da..616cb87b6179 100644 --- a/trunk/arch/arm/mach-pxa/pxa27x.c +++ b/trunk/arch/arm/mach-pxa/pxa27x.c @@ -53,25 +53,17 @@ static unsigned long ac97_reset_config[] = { GPIO95_AC97_nRESET, }; -void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio) +void pxa27x_assert_ac97reset(int reset_gpio, int on) { - /* - * This helper function is used to work around a bug in the pxa27x's - * ac97 controller during a warm reset. The configuration of the - * reset_gpio is changed as follows: - * to_gpio == true: configured to generic output gpio and driven high - * to_gpio == false: configured to ac97 controller alt fn AC97_nRESET - */ - if (reset_gpio == 113) - pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[0] : - &ac97_reset_config[1], 1); + pxa2xx_mfp_config(on ? &ac97_reset_config[0] : + &ac97_reset_config[1], 1); if (reset_gpio == 95) - pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[2] : - &ac97_reset_config[3], 1); + pxa2xx_mfp_config(on ? &ac97_reset_config[2] : + &ac97_reset_config[3], 1); } -EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset); +EXPORT_SYMBOL_GPL(pxa27x_assert_ac97reset); /* Crystal clock: 13MHz */ #define BASE_CLK 13000000 diff --git a/trunk/arch/arm/mach-shmobile/board-ap4evb.c b/trunk/arch/arm/mach-shmobile/board-ap4evb.c index 08294fa9e0d4..99ef190d0909 100644 --- a/trunk/arch/arm/mach-shmobile/board-ap4evb.c +++ b/trunk/arch/arm/mach-shmobile/board-ap4evb.c @@ -657,8 +657,14 @@ static struct platform_device lcdc_device = { /* FSI */ #define IRQ_FSI evt2irq(0x1840) static struct sh_fsi_platform_info fsi_info = { + .port_a = { + .flags = SH_FSI_BRS_INV, + }, .port_b = { - .flags = SH_FSI_CLK_CPG | + .flags = SH_FSI_BRS_INV | + SH_FSI_BRM_INV | + SH_FSI_LRS_INV | + SH_FSI_CLK_CPG | SH_FSI_FMT_SPDIF, }, }; @@ -686,21 +692,21 @@ static struct platform_device fsi_device = { }, }; +static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = { + .fmt = SND_SOC_DAIFMT_LEFT_J, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 11289600, +}; + static struct asoc_simple_card_info fsi2_ak4643_info = { .name = "AK4643", .card = "FSI2A-AK4643", + .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_dai = { - .name = "fsia-dai", - .fmt = SND_SOC_DAIFMT_CBS_CFS, - }, - .codec_dai = { - .name = "ak4642-hifi", - .fmt = SND_SOC_DAIFMT_CBM_CFM, - .sysclk = 11289600, - }, + .codec_dai = "ak4642-hifi", + .init = &fsi2_ak4643_init_info, }; static struct platform_device fsi_ak4643_device = { @@ -809,18 +815,18 @@ static struct platform_device lcdc1_device = { }, }; +static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { + .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM, +}; + static struct asoc_simple_card_info fsi2_hdmi_info = { .name = "HDMI", .card = "FSI2B-HDMI", + .cpu_dai = "fsib-dai", .codec = "sh-mobile-hdmi", .platform = "sh_fsi2", - .cpu_dai = { - .name = "fsib-dai", - .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, - }, - .codec_dai = { - .name = "sh_mobile_hdmi-hifi", - }, + .codec_dai = "sh_mobile_hdmi-hifi", + .init = &fsi2_hdmi_init_info, }; static struct platform_device fsi_hdmi_device = { diff --git a/trunk/arch/arm/mach-shmobile/board-armadillo800eva.c b/trunk/arch/arm/mach-shmobile/board-armadillo800eva.c index 0679ca6bf1f6..5353adf6b828 100644 --- a/trunk/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/trunk/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -806,21 +806,21 @@ static struct platform_device fsi_device = { }; /* FSI-WM8978 */ +static struct asoc_simple_dai_init_info fsi_wm8978_init_info = { + .fmt = SND_SOC_DAIFMT_I2S, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 12288000, +}; + static struct asoc_simple_card_info fsi_wm8978_info = { .name = "wm8978", .card = "FSI2A-WM8978", + .cpu_dai = "fsia-dai", .codec = "wm8978.0-001a", .platform = "sh_fsi2", - .daifmt = SND_SOC_DAIFMT_I2S, - .cpu_dai = { - .name = "fsia-dai", - .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, - }, - .codec_dai = { - .name = "wm8978-hifi", - .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF, - .sysclk = 12288000, - }, + .codec_dai = "wm8978-hifi", + .init = &fsi_wm8978_init_info, }; static struct platform_device fsi_wm8978_device = { @@ -832,18 +832,18 @@ static struct platform_device fsi_wm8978_device = { }; /* FSI-HDMI */ +static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { + .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM, +}; + static struct asoc_simple_card_info fsi2_hdmi_info = { .name = "HDMI", .card = "FSI2B-HDMI", + .cpu_dai = "fsib-dai", .codec = "sh-mobile-hdmi", .platform = "sh_fsi2", - .cpu_dai = { - .name = "fsib-dai", - .fmt = SND_SOC_DAIFMT_CBM_CFM, - }, - .codec_dai = { - .name = "sh_mobile_hdmi-hifi", - }, + .codec_dai = "sh_mobile_hdmi-hifi", + .init = &fsi2_hdmi_init_info, }; static struct platform_device fsi_hdmi_device = { diff --git a/trunk/arch/arm/mach-shmobile/board-kzm9g.c b/trunk/arch/arm/mach-shmobile/board-kzm9g.c index f41b71e8df3e..c02448d6847f 100644 --- a/trunk/arch/arm/mach-shmobile/board-kzm9g.c +++ b/trunk/arch/arm/mach-shmobile/board-kzm9g.c @@ -525,21 +525,21 @@ static struct platform_device fsi_device = { }, }; +static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = { + .fmt = SND_SOC_DAIFMT_LEFT_J, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 11289600, +}; + static struct asoc_simple_card_info fsi2_ak4648_info = { .name = "AK4648", .card = "FSI2A-AK4648", + .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi2", - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_dai = { - .name = "fsia-dai", - .fmt = SND_SOC_DAIFMT_CBS_CFS, - }, - .codec_dai = { - .name = "ak4642-hifi", - .fmt = SND_SOC_DAIFMT_CBM_CFM, - .sysclk = 11289600, - }, + .codec_dai = "ak4642-hifi", + .init = &fsi2_ak4648_init_info, }; static struct platform_device fsi_ak4648_device = { diff --git a/trunk/arch/arm/mach-shmobile/board-mackerel.c b/trunk/arch/arm/mach-shmobile/board-mackerel.c index 3fd716dae405..2fed62f66045 100644 --- a/trunk/arch/arm/mach-shmobile/board-mackerel.c +++ b/trunk/arch/arm/mach-shmobile/board-mackerel.c @@ -502,18 +502,18 @@ static struct platform_device hdmi_lcdc_device = { }, }; +static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = { + .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM, +}; + static struct asoc_simple_card_info fsi2_hdmi_info = { .name = "HDMI", .card = "FSI2B-HDMI", + .cpu_dai = "fsib-dai", .codec = "sh-mobile-hdmi", .platform = "sh_fsi2", - .cpu_dai = { - .name = "fsib-dai", - .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF, - }, - .codec_dai = { - .name = "sh_mobile_hdmi-hifi", - }, + .codec_dai = "sh_mobile_hdmi-hifi", + .init = &fsi2_hdmi_init_info, }; static struct platform_device fsi_hdmi_device = { @@ -858,12 +858,16 @@ static struct platform_device leds_device = { #define IRQ_FSI evt2irq(0x1840) static struct sh_fsi_platform_info fsi_info = { .port_a = { + .flags = SH_FSI_BRS_INV, .tx_id = SHDMA_SLAVE_FSIA_TX, .rx_id = SHDMA_SLAVE_FSIA_RX, }, .port_b = { - .flags = SH_FSI_CLK_CPG | - SH_FSI_FMT_SPDIF, + .flags = SH_FSI_BRS_INV | + SH_FSI_BRM_INV | + SH_FSI_LRS_INV | + SH_FSI_CLK_CPG | + SH_FSI_FMT_SPDIF, } }; @@ -892,21 +896,21 @@ static struct platform_device fsi_device = { }, }; +static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = { + .fmt = SND_SOC_DAIFMT_LEFT_J, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 11289600, +}; + static struct asoc_simple_card_info fsi2_ak4643_info = { .name = "AK4643", .card = "FSI2A-AK4643", + .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_dai = { - .name = "fsia-dai", - .fmt = SND_SOC_DAIFMT_CBS_CFS, - }, - .codec_dai = { - .name = "ak4642-hifi", - .fmt = SND_SOC_DAIFMT_CBM_CFM, - .sysclk = 11289600, - }, + .codec_dai = "ak4642-hifi", + .init = &fsi2_ak4643_init_info, }; static struct platform_device fsi_ak4643_device = { diff --git a/trunk/arch/arm/plat-samsung/dma-ops.c b/trunk/arch/arm/plat-samsung/dma-ops.c index 71d58ddea9c1..d088afa034e8 100644 --- a/trunk/arch/arm/plat-samsung/dma-ops.c +++ b/trunk/arch/arm/plat-samsung/dma-ops.c @@ -19,8 +19,7 @@ #include static unsigned samsung_dmadev_request(enum dma_ch dma_ch, - struct samsung_dma_req *param, - struct device *dev, char *ch_name) + struct samsung_dma_req *param) { dma_cap_mask_t mask; void *filter_param; @@ -34,12 +33,7 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch, */ filter_param = (dma_ch == DMACH_DT_PROP) ? (void *)param->dt_dmach_prop : (void *)dma_ch; - - if (dev->of_node) - return (unsigned)dma_request_slave_channel(dev, ch_name); - else - return (unsigned)dma_request_channel(mask, pl330_filter, - filter_param); + return (unsigned)dma_request_channel(mask, pl330_filter, filter_param); } static int samsung_dmadev_release(unsigned ch, void *param) diff --git a/trunk/arch/arm/plat-samsung/include/plat/dma-ops.h b/trunk/arch/arm/plat-samsung/include/plat/dma-ops.h index 114178268b75..f5144cdd3001 100644 --- a/trunk/arch/arm/plat-samsung/include/plat/dma-ops.h +++ b/trunk/arch/arm/plat-samsung/include/plat/dma-ops.h @@ -39,8 +39,7 @@ struct samsung_dma_config { }; struct samsung_dma_ops { - unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param, - struct device *dev, char *ch_name); + unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param); int (*release)(unsigned ch, void *param); int (*config)(unsigned ch, struct samsung_dma_config *param); int (*prepare)(unsigned ch, struct samsung_dma_prep *param); diff --git a/trunk/arch/arm/plat-samsung/s3c-dma-ops.c b/trunk/arch/arm/plat-samsung/s3c-dma-ops.c index 0cc40aea3f5a..f99448c48d30 100644 --- a/trunk/arch/arm/plat-samsung/s3c-dma-ops.c +++ b/trunk/arch/arm/plat-samsung/s3c-dma-ops.c @@ -36,8 +36,7 @@ static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param, } static unsigned s3c_dma_request(enum dma_ch dma_ch, - struct samsung_dma_req *param, - struct device *dev, char *ch_name) + struct samsung_dma_req *param) { struct cb_data *data; diff --git a/trunk/arch/sh/boards/mach-ecovec24/setup.c b/trunk/arch/sh/boards/mach-ecovec24/setup.c index aaff7671101b..a0fa5791cd44 100644 --- a/trunk/arch/sh/boards/mach-ecovec24/setup.c +++ b/trunk/arch/sh/boards/mach-ecovec24/setup.c @@ -887,6 +887,12 @@ static struct platform_device camera_devices[] = { }; /* FSI */ +static struct sh_fsi_platform_info fsi_info = { + .port_b = { + .flags = SH_FSI_BRS_INV, + }, +}; + static struct resource fsi_resources[] = { [0] = { .name = "FSI", @@ -905,22 +911,25 @@ static struct platform_device fsi_device = { .id = 0, .num_resources = ARRAY_SIZE(fsi_resources), .resource = fsi_resources, + .dev = { + .platform_data = &fsi_info, + }, +}; + +static struct asoc_simple_dai_init_info fsi_da7210_init_info = { + .fmt = SND_SOC_DAIFMT_I2S, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, }; static struct asoc_simple_card_info fsi_da7210_info = { .name = "DA7210", .card = "FSIB-DA7210", + .cpu_dai = "fsib-dai", .codec = "da7210.0-001a", .platform = "sh_fsi.0", - .daifmt = SND_SOC_DAIFMT_I2S, - .cpu_dai = { - .name = "fsib-dai", - .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, - }, - .codec_dai = { - .name = "da7210-hifi", - .fmt = SND_SOC_DAIFMT_CBM_CFM, - }, + .codec_dai = "da7210-hifi", + .init = &fsi_da7210_init_info, }; static struct platform_device fsi_da7210_device = { diff --git a/trunk/arch/sh/boards/mach-se/7724/setup.c b/trunk/arch/sh/boards/mach-se/7724/setup.c index 4010e63e82d8..35f6efa3ac0e 100644 --- a/trunk/arch/sh/boards/mach-se/7724/setup.c +++ b/trunk/arch/sh/boards/mach-se/7724/setup.c @@ -279,6 +279,12 @@ static struct platform_device ceu1_device = { /* FSI */ /* change J20, J21, J22 pin to 1-2 connection to use slave mode */ +static struct sh_fsi_platform_info fsi_info = { + .port_a = { + .flags = SH_FSI_BRS_INV, + }, +}; + static struct resource fsi_resources[] = { [0] = { .name = "FSI", @@ -297,23 +303,26 @@ static struct platform_device fsi_device = { .id = 0, .num_resources = ARRAY_SIZE(fsi_resources), .resource = fsi_resources, + .dev = { + .platform_data = &fsi_info, + }, +}; + +static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = { + .fmt = SND_SOC_DAIFMT_LEFT_J, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 11289600, }; static struct asoc_simple_card_info fsi_ak4642_info = { .name = "AK4642", .card = "FSIA-AK4642", + .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi.0", - .daifmt = SND_SOC_DAIFMT_LEFT_J, - .cpu_dai = { - .name = "fsia-dai", - .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF, - }, - .codec_dai = { - .name = "ak4642-hifi", - .fmt = SND_SOC_DAIFMT_CBM_CFM, - .sysclk = 11289600, - }, + .codec_dai = "ak4642-hifi", + .init = &fsi2_ak4642_init_info, }; static struct platform_device fsi_ak4642_device = { diff --git a/trunk/drivers/base/regmap/internal.h b/trunk/drivers/base/regmap/internal.h index 202518641779..401d1919635a 100644 --- a/trunk/drivers/base/regmap/internal.h +++ b/trunk/drivers/base/regmap/internal.h @@ -16,7 +16,6 @@ #include #include #include -#include struct regmap; struct regcache_ops; @@ -40,13 +39,6 @@ struct regmap_format { unsigned int (*parse_val)(void *buf); }; -struct regmap_async { - struct list_head list; - struct work_struct cleanup; - struct regmap *map; - void *work_buf; -}; - struct regmap { struct mutex mutex; spinlock_t spinlock; @@ -61,11 +53,6 @@ struct regmap { void *bus_context; const char *name; - spinlock_t async_lock; - wait_queue_head_t async_waitq; - struct list_head async_list; - int async_ret; - #ifdef CONFIG_DEBUG_FS struct dentry *debugfs; const char *debugfs_name; @@ -87,9 +74,6 @@ struct regmap { const struct regmap_access_table *volatile_table; const struct regmap_access_table *precious_table; - int (*reg_read)(void *context, unsigned int reg, unsigned int *val); - int (*reg_write)(void *context, unsigned int reg, unsigned int val); - u8 read_flag_mask; u8 write_flag_mask; @@ -191,8 +175,6 @@ bool regcache_set_val(void *base, unsigned int idx, unsigned int val, unsigned int word_size); int regcache_lookup_reg(struct regmap *map, unsigned int reg); -void regmap_async_complete_cb(struct regmap_async *async, int ret); - extern struct regcache_ops regcache_rbtree_ops; extern struct regcache_ops regcache_lzo_ops; diff --git a/trunk/drivers/base/regmap/regmap-spi.c b/trunk/drivers/base/regmap/regmap-spi.c index 913274b5f00a..ffa46a92ad33 100644 --- a/trunk/drivers/base/regmap/regmap-spi.c +++ b/trunk/drivers/base/regmap/regmap-spi.c @@ -15,21 +15,6 @@ #include #include -#include "internal.h" - -struct regmap_async_spi { - struct regmap_async core; - struct spi_message m; - struct spi_transfer t[2]; -}; - -static void regmap_spi_complete(void *data) -{ - struct regmap_async_spi *async = data; - - regmap_async_complete_cb(&async->core, async->m.status); -} - static int regmap_spi_write(void *context, const void *data, size_t count) { struct device *dev = context; @@ -55,41 +40,6 @@ static int regmap_spi_gather_write(void *context, return spi_sync(spi, &m); } -static int regmap_spi_async_write(void *context, - const void *reg, size_t reg_len, - const void *val, size_t val_len, - struct regmap_async *a) -{ - struct regmap_async_spi *async = container_of(a, - struct regmap_async_spi, - core); - struct device *dev = context; - struct spi_device *spi = to_spi_device(dev); - - async->t[0].tx_buf = reg; - async->t[0].len = reg_len; - async->t[1].tx_buf = val; - async->t[1].len = val_len; - - spi_message_init(&async->m); - spi_message_add_tail(&async->t[0], &async->m); - spi_message_add_tail(&async->t[1], &async->m); - - async->m.complete = regmap_spi_complete; - async->m.context = async; - - return spi_async(spi, &async->m); -} - -static struct regmap_async *regmap_spi_async_alloc(void) -{ - struct regmap_async_spi *async_spi; - - async_spi = kzalloc(sizeof(*async_spi), GFP_KERNEL); - - return &async_spi->core; -} - static int regmap_spi_read(void *context, const void *reg, size_t reg_size, void *val, size_t val_size) @@ -103,8 +53,6 @@ static int regmap_spi_read(void *context, static struct regmap_bus regmap_spi = { .write = regmap_spi_write, .gather_write = regmap_spi_gather_write, - .async_write = regmap_spi_async_write, - .async_alloc = regmap_spi_async_alloc, .read = regmap_spi_read, .read_flag_mask = 0x80, }; diff --git a/trunk/drivers/base/regmap/regmap.c b/trunk/drivers/base/regmap/regmap.c index 47825095ebfd..f00b059c057a 100644 --- a/trunk/drivers/base/regmap/regmap.c +++ b/trunk/drivers/base/regmap/regmap.c @@ -16,7 +16,6 @@ #include #include #include -#include #define CREATE_TRACE_POINTS #include @@ -35,22 +34,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change); -static int _regmap_bus_read(void *context, unsigned int reg, - unsigned int *val); -static int _regmap_bus_formatted_write(void *context, unsigned int reg, - unsigned int val); -static int _regmap_bus_raw_write(void *context, unsigned int reg, - unsigned int val); - -static void async_cleanup(struct work_struct *work) -{ - struct regmap_async *async = container_of(work, struct regmap_async, - cleanup); - - kfree(async->work_buf); - kfree(async); -} - bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges) @@ -440,10 +423,6 @@ struct regmap *regmap_init(struct device *dev, map->cache_type = config->cache_type; map->name = config->name; - spin_lock_init(&map->async_lock); - INIT_LIST_HEAD(&map->async_list); - init_waitqueue_head(&map->async_waitq); - if (config->read_flag_mask || config->write_flag_mask) { map->read_flag_mask = config->read_flag_mask; map->write_flag_mask = config->write_flag_mask; @@ -451,8 +430,6 @@ struct regmap *regmap_init(struct device *dev, map->read_flag_mask = bus->read_flag_mask; } - map->reg_read = _regmap_bus_read; - reg_endian = config->reg_format_endian; if (reg_endian == REGMAP_ENDIAN_DEFAULT) reg_endian = bus->reg_format_endian_default; @@ -598,11 +575,6 @@ struct regmap *regmap_init(struct device *dev, goto err_map; } - if (map->format.format_write) - map->reg_write = _regmap_bus_formatted_write; - else if (map->format.format_val) - map->reg_write = _regmap_bus_raw_write; - map->range_tree = RB_ROOT; for (i = 0; i < config->num_ranges; i++) { const struct regmap_range_cfg *range_cfg = &config->ranges[i]; @@ -898,13 +870,10 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, } static int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len, bool async) + const void *val, size_t val_len) { struct regmap_range_node *range; - unsigned long flags; u8 *u8 = map->work_buf; - void *work_val = map->work_buf + map->format.reg_bytes + - map->format.pad_bytes; void *buf; int ret = -ENOTSUPP; size_t len; @@ -949,7 +918,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, dev_dbg(map->dev, "Writing window %d/%zu\n", win_residue, val_len / map->format.val_bytes); ret = _regmap_raw_write(map, reg, val, win_residue * - map->format.val_bytes, async); + map->format.val_bytes); if (ret != 0) return ret; @@ -972,50 +941,6 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, u8[0] |= map->write_flag_mask; - if (async && map->bus->async_write) { - struct regmap_async *async = map->bus->async_alloc(); - if (!async) - return -ENOMEM; - - async->work_buf = kzalloc(map->format.buf_size, - GFP_KERNEL | GFP_DMA); - if (!async->work_buf) { - kfree(async); - return -ENOMEM; - } - - INIT_WORK(&async->cleanup, async_cleanup); - async->map = map; - - /* If the caller supplied the value we can use it safely. */ - memcpy(async->work_buf, map->work_buf, map->format.pad_bytes + - map->format.reg_bytes + map->format.val_bytes); - if (val == work_val) - val = async->work_buf + map->format.pad_bytes + - map->format.reg_bytes; - - spin_lock_irqsave(&map->async_lock, flags); - list_add_tail(&async->list, &map->async_list); - spin_unlock_irqrestore(&map->async_lock, flags); - - ret = map->bus->async_write(map->bus_context, async->work_buf, - map->format.reg_bytes + - map->format.pad_bytes, - val, val_len, async); - - if (ret != 0) { - dev_err(map->dev, "Failed to schedule write: %d\n", - ret); - - spin_lock_irqsave(&map->async_lock, flags); - list_del(&async->list); - spin_unlock_irqrestore(&map->async_lock, flags); - - kfree(async->work_buf); - kfree(async); - } - } - trace_regmap_hw_write_start(map->dev, reg, val_len / map->format.val_bytes); @@ -1023,7 +948,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, * send the work_buf directly, otherwise try to do a gather * write. */ - if (val == work_val) + if (val == (map->work_buf + map->format.pad_bytes + + map->format.reg_bytes)) ret = map->bus->write(map->bus_context, map->work_buf, map->format.reg_bytes + map->format.pad_bytes + @@ -1055,54 +981,12 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, return ret; } -static int _regmap_bus_formatted_write(void *context, unsigned int reg, - unsigned int val) -{ - int ret; - struct regmap_range_node *range; - struct regmap *map = context; - - BUG_ON(!map->format.format_write); - - range = _regmap_range_lookup(map, reg); - if (range) { - ret = _regmap_select_page(map, ®, range, 1); - if (ret != 0) - return ret; - } - - map->format.format_write(map, reg, val); - - trace_regmap_hw_write_start(map->dev, reg, 1); - - ret = map->bus->write(map->bus_context, map->work_buf, - map->format.buf_size); - - trace_regmap_hw_write_done(map->dev, reg, 1); - - return ret; -} - -static int _regmap_bus_raw_write(void *context, unsigned int reg, - unsigned int val) -{ - struct regmap *map = context; - - BUG_ON(!map->format.format_val); - - map->format.format_val(map->work_buf + map->format.reg_bytes - + map->format.pad_bytes, val, 0); - return _regmap_raw_write(map, reg, - map->work_buf + - map->format.reg_bytes + - map->format.pad_bytes, - map->format.val_bytes, false); -} - 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); if (!map->cache_bypass && map->format.format_write) { ret = regcache_write(map, reg, val); @@ -1121,7 +1005,33 @@ int _regmap_write(struct regmap *map, unsigned int reg, trace_regmap_reg_write(map->dev, reg, val); - return map->reg_write(map, reg, val); + if (map->format.format_write) { + range = _regmap_range_lookup(map, reg); + if (range) { + ret = _regmap_select_page(map, ®, range, 1); + if (ret != 0) + return ret; + } + + map->format.format_write(map, reg, val); + + trace_regmap_hw_write_start(map->dev, reg, 1); + + ret = map->bus->write(map->bus_context, map->work_buf, + map->format.buf_size); + + trace_regmap_hw_write_done(map->dev, reg, 1); + + return ret; + } else { + map->format.format_val(map->work_buf + map->format.reg_bytes + + map->format.pad_bytes, val, 0); + return _regmap_raw_write(map, reg, + map->work_buf + + map->format.reg_bytes + + map->format.pad_bytes, + map->format.val_bytes); + } } /** @@ -1179,7 +1089,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, map->lock(map->lock_arg); - ret = _regmap_raw_write(map, reg, val, val_len, false); + ret = _regmap_raw_write(map, reg, val, val_len); map->unlock(map->lock_arg); @@ -1235,15 +1145,14 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, if (map->use_single_rw) { for (i = 0; i < val_count; i++) { ret = regmap_raw_write(map, - reg + (i * map->reg_stride), - val + (i * val_bytes), - val_bytes); + reg + (i * map->reg_stride), + val + (i * val_bytes), + val_bytes); if (ret != 0) return ret; } } else { - ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count, - false); + ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); } if (val_bytes != 1) @@ -1255,48 +1164,6 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, } EXPORT_SYMBOL_GPL(regmap_bulk_write); -/** - * regmap_raw_write_async(): Write raw values to one or more registers - * asynchronously - * - * @map: Register map to write to - * @reg: Initial register to write to - * @val: Block of data to be written, laid out for direct transmission to the - * device. Must be valid until regmap_async_complete() is called. - * @val_len: Length of data pointed to by val. - * - * This function is intended to be used for things like firmware - * download where a large block of data needs to be transferred to the - * device. No formatting will be done on the data provided. - * - * If supported by the underlying bus the write will be scheduled - * asynchronously, helping maximise I/O speed on higher speed buses - * like SPI. regmap_async_complete() can be called to ensure that all - * asynchrnous writes have been completed. - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_raw_write_async(struct regmap *map, unsigned int reg, - const void *val, size_t val_len) -{ - int ret; - - if (val_len % map->format.val_bytes) - return -EINVAL; - if (reg % map->reg_stride) - return -EINVAL; - - map->lock(map->lock_arg); - - ret = _regmap_raw_write(map, reg, val, val_len, true); - - map->unlock(map->lock_arg); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_raw_write_async); - static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, unsigned int val_len) { @@ -1335,27 +1202,10 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, return ret; } -static int _regmap_bus_read(void *context, unsigned int reg, - unsigned int *val) -{ - int ret; - struct regmap *map = context; - - if (!map->format.parse_val) - return -EINVAL; - - ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); - if (ret == 0) - *val = map->format.parse_val(map->work_buf); - - return ret; -} - static int _regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) { int ret; - BUG_ON(!map->reg_read); if (!map->cache_bypass) { ret = regcache_read(map, reg, val); @@ -1363,22 +1213,27 @@ static int _regmap_read(struct regmap *map, unsigned int reg, return 0; } + if (!map->format.parse_val) + return -EINVAL; + if (map->cache_only) return -EBUSY; - ret = map->reg_read(map, reg, val); + ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); if (ret == 0) { + *val = map->format.parse_val(map->work_buf); + #ifdef LOG_DEVICE if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) dev_info(map->dev, "%x => %x\n", reg, *val); #endif trace_regmap_reg_read(map->dev, reg, *val); - - if (!map->cache_bypass) - regcache_write(map, reg, *val); } + if (ret == 0 && !map->cache_bypass) + regcache_write(map, reg, *val); + return ret; } @@ -1595,68 +1450,6 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_update_bits_check); -void regmap_async_complete_cb(struct regmap_async *async, int ret) -{ - struct regmap *map = async->map; - bool wake; - - spin_lock(&map->async_lock); - - list_del(&async->list); - wake = list_empty(&map->async_list); - - if (ret != 0) - map->async_ret = ret; - - spin_unlock(&map->async_lock); - - schedule_work(&async->cleanup); - - if (wake) - wake_up(&map->async_waitq); -} -EXPORT_SYMBOL_GPL(regmap_async_complete_cb); - -static int regmap_async_is_done(struct regmap *map) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&map->async_lock, flags); - ret = list_empty(&map->async_list); - spin_unlock_irqrestore(&map->async_lock, flags); - - return ret; -} - -/** - * regmap_async_complete: Ensure all asynchronous I/O has completed. - * - * @map: Map to operate on. - * - * Blocks until any pending asynchronous I/O has completed. Returns - * an error code for any failed I/O operations. - */ -int regmap_async_complete(struct regmap *map) -{ - unsigned long flags; - int ret; - - /* Nothing to do with no async support */ - if (!map->bus->async_write) - return 0; - - wait_event(map->async_waitq, regmap_async_is_done(map)); - - spin_lock_irqsave(&map->async_lock, flags); - ret = map->async_ret; - map->async_ret = 0; - spin_unlock_irqrestore(&map->async_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_async_complete); - /** * regmap_register_patch: Register and apply register updates to be applied * on device initialistion diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index 8f59d88897e7..b151b7c1bd59 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -192,7 +192,7 @@ config ICS932S401 config ATMEL_SSC tristate "Device driver for Atmel SSC peripheral" - depends on HAS_IOMEM + depends on AVR32 || ARCH_AT91 ---help--- This option enables device driver support for Atmel Synchronized Serial Communication peripheral (SSC). diff --git a/trunk/drivers/misc/atmel-ssc.c b/trunk/drivers/misc/atmel-ssc.c index bd90dd23242e..3c09cbb70b1d 100644 --- a/trunk/drivers/misc/atmel-ssc.c +++ b/trunk/drivers/misc/atmel-ssc.c @@ -175,7 +175,7 @@ static int ssc_probe(struct platform_device *pdev) /* disable all interrupts */ clk_enable(ssc->clk); - ssc_writel(ssc->regs, IDR, -1); + ssc_writel(ssc->regs, IDR, ~0UL); ssc_readl(ssc->regs, SR); clk_disable(ssc->clk); diff --git a/trunk/drivers/spi/spi-s3c64xx.c b/trunk/drivers/spi/spi-s3c64xx.c index 51a8c4216ebb..ad93231a8038 100644 --- a/trunk/drivers/spi/spi-s3c64xx.c +++ b/trunk/drivers/spi/spi-s3c64xx.c @@ -134,6 +134,7 @@ struct s3c64xx_spi_dma_data { unsigned ch; enum dma_transfer_direction direction; enum dma_ch dmach; + struct property *dma_prop; }; /** @@ -318,15 +319,16 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma, static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) { struct samsung_dma_req req; - struct device *dev = &sdd->pdev->dev; sdd->ops = samsung_dma_get_ops(); req.cap = DMA_SLAVE; req.client = &s3c64xx_spi_dma_client; - sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx"); - sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx"); + req.dt_dmach_prop = sdd->rx_dma.dma_prop; + sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req); + req.dt_dmach_prop = sdd->tx_dma.dma_prop; + sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req); return 1; } @@ -1052,6 +1054,49 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) flush_fifo(sdd); } +static int s3c64xx_spi_get_dmares( + struct s3c64xx_spi_driver_data *sdd, bool tx) +{ + struct platform_device *pdev = sdd->pdev; + struct s3c64xx_spi_dma_data *dma_data; + struct property *prop; + struct resource *res; + char prop_name[15], *chan_str; + + if (tx) { + dma_data = &sdd->tx_dma; + dma_data->direction = DMA_MEM_TO_DEV; + chan_str = "tx"; + } else { + dma_data = &sdd->rx_dma; + dma_data->direction = DMA_DEV_TO_MEM; + chan_str = "rx"; + } + + if (!sdd->pdev->dev.of_node) { + res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1); + if (!res) { + dev_err(&pdev->dev, "Unable to get SPI-%s dma " + "resource\n", chan_str); + return -ENXIO; + } + dma_data->dmach = res->start; + return 0; + } + + sprintf(prop_name, "%s-dma-channel", chan_str); + prop = of_find_property(pdev->dev.of_node, prop_name, NULL); + if (!prop) { + dev_err(&pdev->dev, "%s dma channel property not specified\n", + chan_str); + return -ENXIO; + } + + dma_data->dmach = DMACH_DT_PROP; + dma_data->dma_prop = prop; + return 0; +} + #ifdef CONFIG_OF static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd) { @@ -1153,7 +1198,6 @@ static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config( static int __init s3c64xx_spi_probe(struct platform_device *pdev) { struct resource *mem_res; - struct resource *res; struct s3c64xx_spi_driver_data *sdd; struct s3c64xx_spi_info *sci = pdev->dev.platform_data; struct spi_master *master; @@ -1212,26 +1256,13 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) sdd->cur_bpw = 8; - if (!sdd->pdev->dev.of_node) { - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, "Unable to get SPI tx dma " - "resource\n"); - return -ENXIO; - } - sdd->tx_dma.dmach = res->start; - - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(&pdev->dev, "Unable to get SPI rx dma " - "resource\n"); - return -ENXIO; - } - sdd->rx_dma.dmach = res->start; - } + ret = s3c64xx_spi_get_dmares(sdd, true); + if (ret) + goto err0; - sdd->tx_dma.direction = DMA_MEM_TO_DEV; - sdd->rx_dma.direction = DMA_DEV_TO_MEM; + ret = s3c64xx_spi_get_dmares(sdd, false); + if (ret) + goto err0; master->dev.of_node = pdev->dev.of_node; master->bus_num = sdd->port_id; diff --git a/trunk/include/linux/mfd/arizona/pdata.h b/trunk/include/linux/mfd/arizona/pdata.h index ec3e2a2a6d77..8b1d1daaae16 100644 --- a/trunk/include/linux/mfd/arizona/pdata.h +++ b/trunk/include/linux/mfd/arizona/pdata.h @@ -62,8 +62,6 @@ #define ARIZONA_MAX_OUTPUT 6 -#define ARIZONA_MAX_AIF 3 - #define ARIZONA_HAP_ACT_ERM 0 #define ARIZONA_HAP_ACT_LRA 2 @@ -98,13 +96,6 @@ struct arizona_pdata { /** Pin state for GPIO pins */ int gpio_defaults[ARIZONA_MAX_GPIO]; - /** - * Maximum number of channels clocks will be generated for, - * useful for systems where and I2S bus with multiple data - * lines is mastered. - */ - int max_channels_clocked[ARIZONA_MAX_AIF]; - /** GPIO for mic detection polarity */ int micd_pol_gpio; diff --git a/trunk/include/linux/regmap.h b/trunk/include/linux/regmap.h index f9b7fbe35ab1..b7e95bf942c9 100644 --- a/trunk/include/linux/regmap.h +++ b/trunk/include/linux/regmap.h @@ -235,21 +235,14 @@ struct regmap_range_cfg { unsigned int window_len; }; -struct regmap_async; - typedef int (*regmap_hw_write)(void *context, const void *data, size_t count); typedef int (*regmap_hw_gather_write)(void *context, const void *reg, size_t reg_len, const void *val, size_t val_len); -typedef int (*regmap_hw_async_write)(void *context, - const void *reg, size_t reg_len, - const void *val, size_t val_len, - struct regmap_async *async); typedef int (*regmap_hw_read)(void *context, const void *reg_buf, size_t reg_size, void *val_buf, size_t val_size); -typedef struct regmap_async *(*regmap_hw_async_alloc)(void); typedef void (*regmap_hw_free_context)(void *context); /** @@ -262,11 +255,8 @@ typedef void (*regmap_hw_free_context)(void *context); * @write: Write operation. * @gather_write: Write operation with split register/value, return -ENOTSUPP * if not implemented on a given device. - * @async_write: Write operation which completes asynchronously, optional and - * must serialise with respect to non-async I/O. * @read: Read operation. Data is returned in the buffer used to transmit * data. - * @async_alloc: Allocate a regmap_async() structure. * @read_flag_mask: Mask to be set in the top byte of the register when doing * a read. * @reg_format_endian_default: Default endianness for formatted register @@ -275,16 +265,13 @@ typedef void (*regmap_hw_free_context)(void *context); * @val_format_endian_default: Default endianness for formatted register * values. Used when the regmap_config specifies DEFAULT. If this is * DEFAULT, BIG is assumed. - * @async_size: Size of struct used for async work. */ struct regmap_bus { bool fast_io; regmap_hw_write write; regmap_hw_gather_write gather_write; - regmap_hw_async_write async_write; regmap_hw_read read; regmap_hw_free_context free_context; - regmap_hw_async_alloc async_alloc; u8 read_flag_mask; enum regmap_endian reg_format_endian_default; enum regmap_endian val_format_endian_default; @@ -323,8 +310,6 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count); -int regmap_raw_write_async(struct regmap *map, unsigned int reg, - const void *val, size_t val_len); int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, size_t val_len); @@ -336,7 +321,6 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change); int regmap_get_val_bytes(struct regmap *map); -int regmap_async_complete(struct regmap *map); int regcache_sync(struct regmap *map); int regcache_sync_region(struct regmap *map, unsigned int min, @@ -438,13 +422,6 @@ static inline int regmap_raw_write(struct regmap *map, unsigned int reg, return -EINVAL; } -static inline int regmap_raw_write_async(struct regmap *map, unsigned int reg, - const void *val, size_t val_len) -{ - WARN_ONCE(1, "regmap API is disabled"); - return -EINVAL; -} - static inline int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count) { @@ -523,11 +500,6 @@ static inline void regcache_mark_dirty(struct regmap *map) WARN_ONCE(1, "regmap API is disabled"); } -static inline void regmap_async_complete(struct regmap *map) -{ - WARN_ONCE(1, "regmap API is disabled"); -} - static inline int regmap_register_patch(struct regmap *map, const struct reg_default *regs, int num_regs) diff --git a/trunk/include/sound/cs4271.h b/trunk/include/sound/cs4271.h index 70f45355acaa..dd8c48d14ed9 100644 --- a/trunk/include/sound/cs4271.h +++ b/trunk/include/sound/cs4271.h @@ -20,21 +20,6 @@ struct cs4271_platform_data { int gpio_nreset; /* GPIO driving Reset pin, if any */ bool amutec_eq_bmutec; /* flag to enable AMUTEC=BMUTEC */ - - /* - * The CS4271 requires its LRCLK and MCLK to be stable before its RESET - * line is de-asserted. That also means that clocks cannot be changed - * without putting the chip back into hardware reset, which also requires - * a complete re-initialization of all registers. - * - * One (undocumented) workaround is to assert and de-assert the PDN bit - * in the MODE2 register. This workaround can be enabled with the - * following flag. - * - * Note that this is not needed in case the clocks are stable - * throughout the entire runtime of the codec. - */ - bool enable_soft_reset; }; #endif /* __CS4271_H */ diff --git a/trunk/include/sound/da7213.h b/trunk/include/sound/da7213.h new file mode 100644 index 000000000000..673f5c39cbf2 --- /dev/null +++ b/trunk/include/sound/da7213.h @@ -0,0 +1,52 @@ +/* + * da7213.h - DA7213 ASoC Codec Driver Platform Data + * + * Copyright (c) 2013 Dialog Semiconductor + * + * Author: Adam Thomson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DA7213_PDATA_H +#define _DA7213_PDATA_H + +enum da7213_micbias_voltage { + DA7213_MICBIAS_1_6V = 0, + DA7213_MICBIAS_2_2V = 1, + DA7213_MICBIAS_2_5V = 2, + DA7213_MICBIAS_3_0V = 3, +}; + +enum da7213_dmic_data_sel { + DA7213_DMIC_DATA_LRISE_RFALL = 0, + DA7213_DMIC_DATA_LFALL_RRISE = 1, +}; + +enum da7213_dmic_samplephase { + DA7213_DMIC_SAMPLE_ON_CLKEDGE = 0, + DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE = 1, +}; + +enum da7213_dmic_clk_rate { + DA7213_DMIC_CLK_3_0MHZ = 0, + DA7213_DMIC_CLK_1_5MHZ = 1, +}; + +struct da7213_platform_data { + /* Mic Bias voltage */ + enum da7213_micbias_voltage micbias1_lvl; + enum da7213_micbias_voltage micbias2_lvl; + + /* DMIC config */ + enum da7213_dmic_data_sel dmic_data_sel; + enum da7213_dmic_samplephase dmic_samplephase; + enum da7213_dmic_clk_rate dmic_clk_rate; + + /* MCLK squaring config */ + bool mclk_squaring; +}; + +#endif /* _DA7213_PDATA_H */ diff --git a/trunk/include/sound/max98090.h b/trunk/include/sound/max98090.h deleted file mode 100755 index 95efb13f8478..000000000000 --- a/trunk/include/sound/max98090.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Platform data for MAX98090 - * - * Copyright 2011-2012 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 as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __SOUND_MAX98090_PDATA_H__ -#define __SOUND_MAX98090_PDATA_H__ - -/* codec platform data */ -struct max98090_pdata { - - /* Analog/digital microphone configuration: - * 0 = analog microphone input (normal setting) - * 1 = digital microphone input - */ - unsigned int digmic_left_mode:1; - unsigned int digmic_right_mode:1; - unsigned int digmic_3_mode:1; - unsigned int digmic_4_mode:1; -}; - -#endif diff --git a/trunk/include/sound/saif.h b/trunk/include/sound/saif.h new file mode 100644 index 000000000000..f22f3e16edf4 --- /dev/null +++ b/trunk/include/sound/saif.h @@ -0,0 +1,16 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SOUND_SAIF_H__ +#define __SOUND_SAIF_H__ + +struct mxs_saif_platform_data { + bool master_mode; /* if true use master mode */ + int master_id; /* id of the master if in slave mode */ +}; +#endif diff --git a/trunk/include/sound/sh_fsi.h b/trunk/include/sound/sh_fsi.h index 7a9710b4b799..cc1c919c6436 100644 --- a/trunk/include/sound/sh_fsi.h +++ b/trunk/include/sound/sh_fsi.h @@ -11,20 +11,82 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#define FSI_PORT_A 0 +#define FSI_PORT_B 1 + #include #include /* - * flags + * flags format + * + * 0x00000CBA + * + * A: inversion + * B: format mode + * C: chip specific + * D: clock selecter if master mode */ -#define SH_FSI_FMT_SPDIF (1 << 0) /* spdif for HDMI */ -#define SH_FSI_ENABLE_STREAM_MODE (1 << 1) /* for 16bit data */ -#define SH_FSI_CLK_CPG (1 << 2) /* FSIxCK + FSI-DIV */ + +/* A: clock inversion */ +#define SH_FSI_INVERSION_MASK 0x0000000F +#define SH_FSI_LRM_INV (1 << 0) +#define SH_FSI_BRM_INV (1 << 1) +#define SH_FSI_LRS_INV (1 << 2) +#define SH_FSI_BRS_INV (1 << 3) + +/* B: format mode */ +#define SH_FSI_FMT_MASK 0x000000F0 +#define SH_FSI_FMT_DAI (0 << 4) +#define SH_FSI_FMT_SPDIF (1 << 4) + +/* C: chip specific */ +#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 + * + * see ACKMD/BPFMD on + * ACK_MD (FSI2) + * CKG1 (FSI) + * + * err : return value < 0 + * no change : return value == 0 + * change xMD : return value > 0 + * + * 0x-00000AB + * + * A: ACKMD value + * B: BPFMD value + */ + +#define SH_FSI_ACKMD_MASK (0xF << 0) +#define SH_FSI_ACKMD_512 (1 << 0) +#define SH_FSI_ACKMD_256 (2 << 0) +#define SH_FSI_ACKMD_128 (3 << 0) +#define SH_FSI_ACKMD_64 (4 << 0) +#define SH_FSI_ACKMD_32 (5 << 0) + +#define SH_FSI_BPFMD_MASK (0xF << 4) +#define SH_FSI_BPFMD_512 (1 << 4) +#define SH_FSI_BPFMD_256 (2 << 4) +#define SH_FSI_BPFMD_128 (3 << 4) +#define SH_FSI_BPFMD_64 (4 << 4) +#define SH_FSI_BPFMD_32 (5 << 4) +#define SH_FSI_BPFMD_16 (6 << 4) struct sh_fsi_port_info { unsigned long flags; int tx_id; int rx_id; + int (*set_rate)(struct device *dev, int rate, int enable); }; struct sh_fsi_platform_info { diff --git a/trunk/include/sound/simple_card.h b/trunk/include/sound/simple_card.h index 6c74527d4926..4b62b8dc6a4f 100644 --- a/trunk/include/sound/simple_card.h +++ b/trunk/include/sound/simple_card.h @@ -14,21 +14,21 @@ #include -struct asoc_simple_dai { - const char *name; +struct asoc_simple_dai_init_info { unsigned int fmt; + unsigned int cpu_daifmt; + unsigned int codec_daifmt; unsigned int sysclk; }; struct asoc_simple_card_info { const char *name; const char *card; + const char *cpu_dai; const char *codec; const char *platform; - - unsigned int daifmt; - struct asoc_simple_dai cpu_dai; - struct asoc_simple_dai codec_dai; + const char *codec_dai; + struct asoc_simple_dai_init_info *init; /* for snd_link.init */ /* used in simple-card.c */ struct snd_soc_dai_link snd_link; diff --git a/trunk/include/sound/soc-dai.h b/trunk/include/sound/soc-dai.h index 3d84808952b9..3953cea0ecfb 100644 --- a/trunk/include/sound/soc-dai.h +++ b/trunk/include/sound/soc-dai.h @@ -45,7 +45,7 @@ struct snd_compr_stream; * sending or receiving PCM data in a frame. This can be used to save power. */ #define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */ -#define SND_SOC_DAIFMT_GATED (0 << 4) /* clock is gated */ +#define SND_SOC_DAIFMT_GATED (2 << 4) /* clock is gated */ /* * DAI hardware signal inversions. @@ -53,7 +53,7 @@ struct snd_compr_stream; * Specifies whether the DAI can also support inverted clocks for the specified * format. */ -#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ +#define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */ #define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */ #define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */ #define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */ @@ -126,8 +126,7 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); /* Digital Audio Interface mute */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, - int direction); +int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); struct snd_soc_dai_ops { /* @@ -158,7 +157,6 @@ struct snd_soc_dai_ops { * Called by soc-core to minimise any pops. */ int (*digital_mute)(struct snd_soc_dai *dai, int mute); - int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream); /* * ALSA PCM audio operations - all optional. diff --git a/trunk/include/sound/soc.h b/trunk/include/sound/soc.h index a6a059ca3874..bc56738cb109 100644 --- a/trunk/include/sound/soc.h +++ b/trunk/include/sound/soc.h @@ -906,8 +906,8 @@ struct snd_soc_dai_link { struct snd_pcm_hw_params *params); /* machine stream operations */ - const struct snd_soc_ops *ops; - const struct snd_soc_compr_ops *compr_ops; + struct snd_soc_ops *ops; + struct snd_soc_compr_ops *compr_ops; }; struct snd_soc_codec_conf { @@ -1171,8 +1171,6 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname); int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); -unsigned int snd_soc_of_parse_daifmt(struct device_node *np, - const char *prefix); #include diff --git a/trunk/include/sound/tlv320aic3x.h b/trunk/include/sound/tlv320aic3x.h index 9407fd00363b..ffd9bc793105 100644 --- a/trunk/include/sound/tlv320aic3x.h +++ b/trunk/include/sound/tlv320aic3x.h @@ -46,13 +46,6 @@ enum { AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 }; -enum aic3x_micbias_voltage { - AIC3X_MICBIAS_OFF = 0, - AIC3X_MICBIAS_2_0V = 1, - AIC3X_MICBIAS_2_5V = 2, - AIC3X_MICBIAS_AVDDV = 3, -}; - struct aic3x_setup_data { unsigned int gpio_func[2]; }; @@ -60,9 +53,6 @@ struct aic3x_setup_data { struct aic3x_pdata { int gpio_reset; /* < 0 if not used */ struct aic3x_setup_data *setup; - - /* Selects the micbias voltage */ - enum aic3x_micbias_voltage micbias_vg; }; #endif diff --git a/trunk/include/sound/wm2000.h b/trunk/include/sound/wm2000.h index 4de81f41c90f..aa388ca9ec64 100644 --- a/trunk/include/sound/wm2000.h +++ b/trunk/include/sound/wm2000.h @@ -15,6 +15,9 @@ struct wm2000_platform_data { /** Filename for system-specific image to download to device. */ const char *download_file; + /** Divide MCLK by 2 for system clock? */ + unsigned int mclkdiv2:1; + /** Disable speech clarity enhancement, for use when an * external algorithm is used. */ unsigned int speech_enh_disable:1; diff --git a/trunk/include/sound/wm2200.h b/trunk/include/sound/wm2200.h index bc7ab1a4b480..79bf55be7ffa 100644 --- a/trunk/include/sound/wm2200.h +++ b/trunk/include/sound/wm2200.h @@ -12,7 +12,6 @@ #define __LINUX_SND_WM2200_H #define WM2200_GPIO_SET 0x10000 -#define WM2200_MAX_MICBIAS 2 enum wm2200_in_mode { WM2200_IN_SE = 0, @@ -26,24 +25,6 @@ enum wm2200_dmic_sup { WM2200_DMIC_SUP_MICBIAS2 = 2, }; -enum wm2200_mbias_lvl { - WM2200_MBIAS_LVL_1V5 = 1, - WM2200_MBIAS_LVL_1V8 = 2, - WM2200_MBIAS_LVL_1V9 = 3, - WM2200_MBIAS_LVL_2V0 = 4, - WM2200_MBIAS_LVL_2V2 = 5, - WM2200_MBIAS_LVL_2V4 = 6, - WM2200_MBIAS_LVL_2V5 = 7, - WM2200_MBIAS_LVL_2V6 = 8, -}; - -struct wm2200_micbias { - enum wm2200_mbias_lvl mb_lvl; /** Regulated voltage */ - unsigned int discharge:1; /** Actively discharge */ - unsigned int fast_start:1; /** Enable aggressive startup ramp rate */ - unsigned int bypass:1; /** Use bypass mode */ -}; - struct wm2200_pdata { int reset; /** GPIO controlling /RESET, if any */ int ldo_ena; /** GPIO controlling LODENA, if any */ @@ -54,8 +35,7 @@ struct wm2200_pdata { enum wm2200_in_mode in_mode[3]; enum wm2200_dmic_sup dmic_sup[3]; - /** MICBIAS configurations */ - struct wm2200_micbias micbias[WM2200_MAX_MICBIAS]; + int micbias_cfg[2]; /** Register value to configure MICBIAS */ }; #endif diff --git a/trunk/sound/arm/pxa2xx-ac97-lib.c b/trunk/sound/arm/pxa2xx-ac97-lib.c index e6f4633b8dd5..fff7753e35c1 100644 --- a/trunk/sound/arm/pxa2xx-ac97-lib.c +++ b/trunk/sound/arm/pxa2xx-ac97-lib.c @@ -34,7 +34,7 @@ static struct clk *ac97_clk; static struct clk *ac97conf_clk; static int reset_gpio; -extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio); +extern void pxa27x_assert_ac97reset(int reset_gpio, int on); /* * Beware PXA27x bugs: @@ -140,10 +140,10 @@ static inline void pxa_ac97_warm_pxa27x(void) gsr_bits = 0; /* warm reset broken on Bulverde, so manually keep AC97 reset high */ - pxa27x_configure_ac97reset(reset_gpio, true); + pxa27x_assert_ac97reset(reset_gpio, 1); udelay(10); GCR |= GCR_WARM_RST; - pxa27x_configure_ac97reset(reset_gpio, false); + pxa27x_assert_ac97reset(reset_gpio, 0); udelay(500); } @@ -358,7 +358,7 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev) __func__, ret); goto err_conf; } - pxa27x_configure_ac97reset(reset_gpio, false); + pxa27x_assert_ac97reset(reset_gpio, 0); ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); if (IS_ERR(ac97conf_clk)) { diff --git a/trunk/sound/soc/atmel/Kconfig b/trunk/sound/soc/atmel/Kconfig index 3fdd87fa18a9..d1b691bf8e2d 100644 --- a/trunk/sound/soc/atmel/Kconfig +++ b/trunk/sound/soc/atmel/Kconfig @@ -1,6 +1,6 @@ config SND_ATMEL_SOC tristate "SoC Audio for the Atmel System-on-Chip" - depends on HAS_IOMEM + depends on ARCH_AT91 help Say Y or M if you want to add support for codecs attached to the ATMEL SSC interface. You will also need @@ -24,7 +24,7 @@ config SND_ATMEL_SOC_SSC config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ARCH_AT91 && ATMEL_SSC && 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 @@ -34,7 +34,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 config SND_AT91_SOC_AFEB9260 tristate "SoC Audio support for AFEB9260 board" - depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC + 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 diff --git a/trunk/sound/soc/atmel/atmel-pcm-pdc.c b/trunk/sound/soc/atmel/atmel-pcm-pdc.c index 054ea4d9326a..6a293c713a38 100644 --- a/trunk/sound/soc/atmel/atmel-pcm-pdc.c +++ b/trunk/sound/soc/atmel/atmel-pcm-pdc.c @@ -159,7 +159,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, pr_debug("atmel-pcm: " "hw_params: DMA for %s initialized " - "(dma_bytes=%zu, period_size=%zu)\n", + "(dma_bytes=%u, period_size=%u)\n", prtd->params->name, runtime->dma_bytes, prtd->period_size); @@ -201,7 +201,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream, int ret = 0; pr_debug("atmel-pcm:buffer_size = %ld," - "dma_area = %p, dma_bytes = %zu\n", + "dma_area = %p, dma_bytes = %u\n", rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); switch (cmd) { diff --git a/trunk/sound/soc/atmel/atmel-pcm.c b/trunk/sound/soc/atmel/atmel-pcm.c index 3109db7b9017..e99f1811300a 100644 --- a/trunk/sound/soc/atmel/atmel-pcm.c +++ b/trunk/sound/soc/atmel/atmel-pcm.c @@ -49,7 +49,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, buf->private_data = NULL; buf->area = dma_alloc_coherent(pcm->card->dev, size, &buf->addr, GFP_KERNEL); - pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n", + pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n", (void *)buf->area, (void *)buf->addr, size); if (!buf->area) diff --git a/trunk/sound/soc/atmel/atmel-pcm.h b/trunk/sound/soc/atmel/atmel-pcm.h index 12ae814eff21..bb45d20e7250 100644 --- a/trunk/sound/soc/atmel/atmel-pcm.h +++ b/trunk/sound/soc/atmel/atmel-pcm.h @@ -88,8 +88,7 @@ void atmel_pcm_free(struct snd_pcm *pcm); int atmel_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -#if defined(CONFIG_SND_ATMEL_SOC_PDC) || \ - defined(CONFIG_SND_ATMEL_SOC_PDC_MODULE) +#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 @@ -102,8 +101,7 @@ static inline void atmel_pcm_pdc_platform_unregister(struct device *dev) } #endif -#if defined(CONFIG_SND_ATMEL_SOC_DMA) || \ - defined(CONFIG_SND_ATMEL_SOC_DMA_MODULE) +#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 diff --git a/trunk/sound/soc/atmel/atmel_ssc_dai.c b/trunk/sound/soc/atmel/atmel_ssc_dai.c index e13580d6c476..1c7663422054 100644 --- a/trunk/sound/soc/atmel/atmel_ssc_dai.c +++ b/trunk/sound/soc/atmel/atmel_ssc_dai.c @@ -42,6 +42,8 @@ #include #include +#include + #include "atmel-pcm.h" #include "atmel_ssc_dai.h" @@ -677,6 +679,15 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) # define atmel_ssc_resume NULL #endif /* CONFIG_PM */ +static int atmel_ssc_probe(struct snd_soc_dai *dai) +{ + struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + + snd_soc_dai_set_drvdata(dai, ssc_p); + + return 0; +} + #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ @@ -692,6 +703,7 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { }; static struct snd_soc_dai_driver atmel_ssc_dai = { + .probe = atmel_ssc_probe, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -778,8 +790,8 @@ void atmel_ssc_put_audio(int ssc_id) { struct ssc_device *ssc = ssc_info[ssc_id].ssc; - asoc_ssc_exit(&ssc->pdev->dev); ssc_free(ssc); + asoc_ssc_exit(&ssc->pdev->dev); } EXPORT_SYMBOL_GPL(atmel_ssc_put_audio); diff --git a/trunk/sound/soc/atmel/sam9g20_wm8731.c b/trunk/sound/soc/atmel/sam9g20_wm8731.c index 2d6fbd0125b9..da976291da9e 100644 --- a/trunk/sound/soc/atmel/sam9g20_wm8731.c +++ b/trunk/sound/soc/atmel/sam9g20_wm8731.c @@ -305,10 +305,10 @@ static int at91sam9g20ek_audio_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - clk_disable(mclk); - mclk = NULL; - snd_soc_unregister_card(card); atmel_ssc_put_audio(0); + snd_soc_unregister_card(card); + clk_put(mclk); + mclk = NULL; return 0; } diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index 3a847828932a..751476aa7814 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI select SND_SOC_CX20442 select SND_SOC_DA7210 if I2C + select SND_SOC_DA7213 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C select SND_SOC_DFBMCS320 @@ -247,6 +248,9 @@ config SND_SOC_L3 config SND_SOC_DA7210 tristate +config SND_SOC_DA7213 + tristate + config SND_SOC_DA732X tristate diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index f6e8e36cceb7..6a3b3c3b8b41 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -23,6 +23,7 @@ snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o +snd-soc-da7213-objs := da7213.o snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o snd-soc-dfbmcs320-objs := dfbmcs320.o @@ -147,6 +148,7 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o +obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o diff --git a/trunk/sound/soc/codecs/ak4642.c b/trunk/sound/soc/codecs/ak4642.c index 2d0378709702..1f0cdab03294 100644 --- a/trunk/sound/soc/codecs/ak4642.c +++ b/trunk/sound/soc/codecs/ak4642.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -514,31 +513,12 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static struct of_device_id ak4642_of_match[]; static int ak4642_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct device_node *np = i2c->dev.of_node; - const struct snd_soc_codec_driver *driver; - - driver = NULL; - if (np) { - const struct of_device_id *of_id; - - of_id = of_match_device(ak4642_of_match, &i2c->dev); - if (of_id) - driver = of_id->data; - } else { - driver = (struct snd_soc_codec_driver *)id->driver_data; - } - - if (!driver) { - dev_err(&i2c->dev, "no driver\n"); - return -EINVAL; - } - return snd_soc_register_codec(&i2c->dev, - driver, &ak4642_dai, 1); + (struct snd_soc_codec_driver *)id->driver_data, + &ak4642_dai, 1); } static int ak4642_i2c_remove(struct i2c_client *client) @@ -547,14 +527,6 @@ static int ak4642_i2c_remove(struct i2c_client *client) return 0; } -static struct of_device_id ak4642_of_match[] = { - { .compatible = "asahi-kasei,ak4642", .data = &soc_codec_dev_ak4642}, - { .compatible = "asahi-kasei,ak4643", .data = &soc_codec_dev_ak4642}, - { .compatible = "asahi-kasei,ak4648", .data = &soc_codec_dev_ak4648}, - {}, -}; -MODULE_DEVICE_TABLE(of, ak4642_of_match); - static const struct i2c_device_id ak4642_i2c_id[] = { { "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 }, { "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 }, @@ -567,7 +539,6 @@ static struct i2c_driver ak4642_i2c_driver = { .driver = { .name = "ak4642-codec", .owner = THIS_MODULE, - .of_match_table = ak4642_of_match, }, .probe = ak4642_i2c_probe, .remove = ak4642_i2c_remove, diff --git a/trunk/sound/soc/codecs/arizona.c b/trunk/sound/soc/codecs/arizona.c index ac948a671ea6..ef62c435848e 100644 --- a/trunk/sound/soc/codecs/arizona.c +++ b/trunk/sound/soc/codecs/arizona.c @@ -56,14 +56,14 @@ #define arizona_fll_warn(_fll, fmt, ...) \ dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) #define arizona_fll_dbg(_fll, fmt, ...) \ - dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) + dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) #define arizona_aif_err(_dai, fmt, ...) \ dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) #define arizona_aif_warn(_dai, fmt, ...) \ dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) #define arizona_aif_dbg(_dai, fmt, ...) \ - dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) + dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", @@ -141,30 +141,6 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "ASRC1R", "ASRC2L", "ASRC2R", - "ISRC1INT1", - "ISRC1INT2", - "ISRC1INT3", - "ISRC1INT4", - "ISRC1DEC1", - "ISRC1DEC2", - "ISRC1DEC3", - "ISRC1DEC4", - "ISRC2INT1", - "ISRC2INT2", - "ISRC2INT3", - "ISRC2INT4", - "ISRC2DEC1", - "ISRC2DEC2", - "ISRC2DEC3", - "ISRC2DEC4", - "ISRC3INT1", - "ISRC3INT2", - "ISRC3INT3", - "ISRC3INT4", - "ISRC3DEC1", - "ISRC3DEC2", - "ISRC3DEC3", - "ISRC3DEC4", }; EXPORT_SYMBOL_GPL(arizona_mixer_texts); @@ -244,30 +220,6 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { 0x91, 0x92, 0x93, - 0xa0, /* ISRC1INT1 */ - 0xa1, - 0xa2, - 0xa3, - 0xa4, /* ISRC1DEC1 */ - 0xa5, - 0xa6, - 0xa7, - 0xa8, /* ISRC2DEC1 */ - 0xa9, - 0xaa, - 0xab, - 0xac, /* ISRC2INT1 */ - 0xad, - 0xae, - 0xaf, - 0xb0, /* ISRC3DEC1 */ - 0xb1, - 0xb2, - 0xb3, - 0xb4, /* ISRC3INT1 */ - 0xb5, - 0xb6, - 0xb7, }; EXPORT_SYMBOL_GPL(arizona_mixer_values); @@ -323,35 +275,9 @@ const struct soc_enum arizona_lhpf4_mode = arizona_lhpf_mode_text); EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); -static const char *arizona_ng_hold_text[] = { - "30ms", "120ms", "250ms", "500ms", -}; - -const struct soc_enum arizona_ng_hold = - SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT, - 4, arizona_ng_hold_text); -EXPORT_SYMBOL_GPL(arizona_ng_hold); - int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - unsigned int reg; - - if (w->shift % 2) - reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8); - else - reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8); - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0); - break; - case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, - ARIZONA_IN1L_MUTE); - break; - } - return 0; } EXPORT_SYMBOL_GPL(arizona_in_ev); @@ -491,10 +417,6 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, case 147456000: val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; break; - case 0: - dev_dbg(arizona->dev, "%s cleared\n", name); - *clk = freq; - return 0; default: return -EINVAL; } @@ -713,9 +635,6 @@ static int arizona_startup(struct snd_pcm_substream *substream, return 0; } - if (base_rate == 0) - return 0; - if (base_rate % 8000) constraint = &arizona_44k1_constraint; else @@ -726,81 +645,25 @@ static int arizona_startup(struct snd_pcm_substream *substream, constraint); } -static int arizona_hw_params_rate(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; - int base = dai->driver->base; - int i, sr_val; - - /* - * We will need to be more flexible than this in future, - * currently we use a single sample rate for SYSCLK. - */ - for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++) - if (arizona_sr_vals[i] == params_rate(params)) - break; - if (i == ARRAY_SIZE(arizona_sr_vals)) { - arizona_aif_err(dai, "Unsupported sample rate %dHz\n", - params_rate(params)); - return -EINVAL; - } - sr_val = i; - - switch (dai_priv->clk) { - case ARIZONA_CLK_SYSCLK: - snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, - ARIZONA_SAMPLE_RATE_1_MASK, sr_val); - if (base) - snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, - ARIZONA_AIF1_RATE_MASK, 0); - break; - case ARIZONA_CLK_ASYNCCLK: - snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, - ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); - if (base) - snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, - ARIZONA_AIF1_RATE_MASK, - 8 << ARIZONA_AIF1_RATE_SHIFT); - break; - default: - arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); - return -EINVAL; - } - - return 0; -} - static int arizona_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; + struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; int base = dai->driver->base; const int *rates; - int i, ret; - int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; - int bclk, lrclk, wl, frame, bclk_target; + int i; + int bclk, lrclk, wl, frame, sr_val; if (params_rate(params) % 8000) rates = &arizona_44k1_bclk_rates[0]; else rates = &arizona_48k_bclk_rates[0]; - bclk_target = snd_soc_params_to_bclk(params); - if (chan_limit && chan_limit < params_channels(params)) { - arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit); - bclk_target /= params_channels(params); - bclk_target *= chan_limit; - } - for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { - if (rates[i] >= bclk_target && + if (rates[i] >= snd_soc_params_to_bclk(params) && rates[i] % params_rate(params) == 0) { bclk = i; break; @@ -812,6 +675,16 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++) + if (arizona_sr_vals[i] == params_rate(params)) + break; + if (i == ARRAY_SIZE(arizona_sr_vals)) { + arizona_aif_err(dai, "Unsupported sample rate %dHz\n", + params_rate(params)); + return -EINVAL; + } + sr_val = i; + lrclk = rates[bclk] / params_rate(params); arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", @@ -820,9 +693,28 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, wl = snd_pcm_format_width(params_format(params)); frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; - ret = arizona_hw_params_rate(substream, params, dai); - if (ret != 0) - return ret; + /* + * We will need to be more flexible than this in future, + * currently we use a single sample rate for SYSCLK. + */ + switch (dai_priv->clk) { + case ARIZONA_CLK_SYSCLK: + snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, + ARIZONA_SAMPLE_RATE_1_MASK, sr_val); + snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, + ARIZONA_AIF1_RATE_MASK, 0); + break; + case ARIZONA_CLK_ASYNCCLK: + snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, + ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); + snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, + ARIZONA_AIF1_RATE_MASK, + 8 << ARIZONA_AIF1_RATE_SHIFT); + break; + default: + arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); + return -EINVAL; + } snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); @@ -897,27 +789,11 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, return snd_soc_dapm_sync(&codec->dapm); } -static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate) -{ - struct snd_soc_codec *codec = dai->codec; - int base = dai->driver->base; - unsigned int reg; - - if (tristate) - reg = ARIZONA_AIF1_TRI; - else - reg = 0; - - return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, - ARIZONA_AIF1_TRI, reg); -} - const struct snd_soc_dai_ops arizona_dai_ops = { .startup = arizona_startup, .set_fmt = arizona_set_fmt, .hw_params = arizona_hw_params, .set_sysclk = arizona_dai_set_sysclk, - .set_tristate = arizona_set_tristate, }; EXPORT_SYMBOL_GPL(arizona_dai_ops); @@ -931,6 +807,17 @@ int arizona_init_dai(struct arizona_priv *priv, int id) } EXPORT_SYMBOL_GPL(arizona_init_dai); +static irqreturn_t arizona_fll_lock(int irq, void *data) +{ + struct arizona_fll *fll = data; + + arizona_fll_dbg(fll, "Lock status changed\n"); + + complete(&fll->lock); + + return IRQ_HANDLED; +} + static irqreturn_t arizona_fll_clock_ok(int irq, void *data) { struct arizona_fll *fll = data; @@ -1023,7 +910,7 @@ static int arizona_calc_fll(struct arizona_fll *fll, cfg->n = target / (ratio * Fref); - if (target % (ratio * Fref)) { + if (target % Fref) { gcd_fll = gcd(target, ratio * Fref); arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll); @@ -1035,15 +922,6 @@ static int arizona_calc_fll(struct arizona_fll *fll, cfg->lambda = 0; } - /* Round down to 16bit range with cost of accuracy lost. - * Denominator must be bigger than numerator so we only - * take care of it. - */ - while (cfg->lambda >= (1 << 16)) { - cfg->theta >>= 1; - cfg->lambda >>= 1; - } - arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", cfg->n, cfg->theta, cfg->lambda); arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", @@ -1179,6 +1057,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, { int ret; + init_completion(&fll->lock); init_completion(&fll->ok); fll->id = id; @@ -1189,6 +1068,13 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), "FLL%d clock OK", id); + ret = arizona_request_irq(arizona, lock_irq, fll->lock_name, + arizona_fll_lock, fll); + if (ret != 0) { + dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n", + id, ret); + } + ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, arizona_fll_clock_ok, fll); if (ret != 0) { @@ -1203,40 +1089,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, } EXPORT_SYMBOL_GPL(arizona_init_fll); -/** - * arizona_set_output_mode - Set the mode of the specified output - * - * @codec: Device to configure - * @output: Output number - * @diff: True to set the output to differential mode - * - * Some systems use external analogue switches to connect more - * analogue devices to the CODEC than are supported by the device. In - * some systems this requires changing the switched output from single - * ended to differential mode dynamically at runtime, an operation - * supported using this function. - * - * Most systems have a single static configuration and should use - * platform data instead. - */ -int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff) -{ - unsigned int reg, val; - - if (output < 1 || output > 6) - return -EINVAL; - - reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8; - - if (diff) - val = ARIZONA_OUT1_MONO; - else - val = 0; - - return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val); -} -EXPORT_SYMBOL_GPL(arizona_set_output_mode); - MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/arizona.h b/trunk/sound/soc/codecs/arizona.h index 116372c91f5d..4deebeb07177 100644 --- a/trunk/sound/soc/codecs/arizona.h +++ b/trunk/sound/soc/codecs/arizona.h @@ -66,7 +66,7 @@ struct arizona_priv { struct arizona_dai_priv dai[ARIZONA_MAX_DAI]; }; -#define ARIZONA_NUM_MIXER_INPUTS 99 +#define ARIZONA_NUM_MIXER_INPUTS 75 extern const unsigned int arizona_mixer_tlv[]; extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; @@ -176,8 +176,6 @@ extern const struct soc_enum arizona_lhpf2_mode; extern const struct soc_enum arizona_lhpf3_mode; extern const struct soc_enum arizona_lhpf4_mode; -extern const struct soc_enum arizona_ng_hold; - extern int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); @@ -197,6 +195,7 @@ struct arizona_fll { int id; unsigned int base; unsigned int vco_mult; + struct completion lock; struct completion ok; unsigned int fref; unsigned int fout; @@ -212,7 +211,4 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, extern int arizona_init_dai(struct arizona_priv *priv, int dai); -int arizona_set_output_mode(struct snd_soc_codec *codec, int output, - bool diff); - #endif diff --git a/trunk/sound/soc/codecs/cs4271.c b/trunk/sound/soc/codecs/cs4271.c index 2415a4118dbd..ac8742a1f25a 100644 --- a/trunk/sound/soc/codecs/cs4271.c +++ b/trunk/sound/soc/codecs/cs4271.c @@ -167,8 +167,6 @@ struct cs4271_private { int gpio_nreset; /* GPIO that disable serial bus, if any */ int gpio_disable; - /* enable soft reset workaround */ - bool enable_soft_reset; }; /* @@ -327,33 +325,6 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, int i, ret; unsigned int ratio, val; - if (cs4271->enable_soft_reset) { - /* - * Put the codec in soft reset and back again in case it's not - * currently streaming data. This way of bringing the codec in - * sync to the current clocks is not explicitly documented in - * the data sheet, but it seems to work fine, and in contrast - * to a read hardware reset, we don't have to sync back all - * registers every time. - */ - - if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - !dai->capture_active) || - (substream->stream == SNDRV_PCM_STREAM_CAPTURE && - !dai->playback_active)) { - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN, - CS4271_MODE2_PDN); - if (ret < 0) - return ret; - - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN, 0); - if (ret < 0) - return ret; - } - } - cs4271->rate = params_rate(params); /* Configure DAC */ @@ -513,10 +484,6 @@ static int cs4271_probe(struct snd_soc_codec *codec) if (of_get_property(codec->dev->of_node, "cirrus,amutec-eq-bmutec", NULL)) amutec_eq_bmutec = true; - - if (of_get_property(codec->dev->of_node, - "cirrus,enable-soft-reset", NULL)) - cs4271->enable_soft_reset = true; } #endif @@ -525,7 +492,6 @@ static int cs4271_probe(struct snd_soc_codec *codec) gpio_nreset = cs4271plat->gpio_nreset; amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; - cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; } if (gpio_nreset >= 0) diff --git a/trunk/sound/soc/codecs/cs42l52.c b/trunk/sound/soc/codecs/cs42l52.c index 0f6f481cec09..9811a5478c87 100644 --- a/trunk/sound/soc/codecs/cs42l52.c +++ b/trunk/sound/soc/codecs/cs42l52.c @@ -1038,7 +1038,7 @@ static void cs42l52_init_beep(struct snd_soc_codec *codec) struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec); int ret; - cs42l52->beep = devm_input_allocate_device(codec->dev); + cs42l52->beep = input_allocate_device(); if (!cs42l52->beep) { dev_err(codec->dev, "Failed to allocate beep device\n"); return; @@ -1059,6 +1059,7 @@ static void cs42l52_init_beep(struct snd_soc_codec *codec) ret = input_register_device(cs42l52->beep); if (ret != 0) { + input_free_device(cs42l52->beep); cs42l52->beep = NULL; dev_err(codec->dev, "Failed to register beep device\n"); } @@ -1075,6 +1076,7 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec) struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec); device_remove_file(codec->dev, &dev_attr_beep); + input_unregister_device(cs42l52->beep); cancel_work_sync(&cs42l52->beep_work); cs42l52->beep = NULL; diff --git a/trunk/sound/soc/codecs/da7213.c b/trunk/sound/soc/codecs/da7213.c new file mode 100644 index 000000000000..41230ad1c3e0 --- /dev/null +++ b/trunk/sound/soc/codecs/da7213.c @@ -0,0 +1,1599 @@ +/* + * DA7213 ALSA SoC Codec Driver + * + * Copyright (c) 2013 Dialog Semiconductor + * + * Author: Adam Thomson + * Based on DA9055 ALSA SoC codec driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "da7213.h" + + +/* Gain and Volume */ +static const unsigned int aux_vol_tlv[] = { + TLV_DB_RANGE_HEAD(2), + /* -54dB */ + 0x0, 0x11, TLV_DB_SCALE_ITEM(-5400, 0, 0), + /* -52.5dB to 15dB */ + 0x12, 0x3f, TLV_DB_SCALE_ITEM(-5250, 150, 0) +}; + +static const unsigned int digital_gain_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + /* -78dB to 12dB */ + 0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0) +}; + +static const unsigned int alc_analog_gain_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + /* 0dB to 36dB */ + 0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0) +}; + +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0); +static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0); +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0); +static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0); + +/* ADC and DAC voice mode (8kHz) high pass cutoff value */ +static const char * const da7213_voice_hpf_corner_txt[] = { + "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" +}; + +static const struct soc_enum da7213_dac_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, + DA7213_VOICE_HPF_CORNER_MAX, + da7213_voice_hpf_corner_txt); + +static const struct soc_enum da7213_adc_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, + DA7213_VOICE_HPF_CORNER_MAX, + da7213_voice_hpf_corner_txt); + +/* ADC and DAC high pass filter cutoff value */ +static const char * const da7213_audio_hpf_corner_txt[] = { + "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" +}; + +static const struct soc_enum da7213_dac_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, + DA7213_AUDIO_HPF_CORNER_MAX, + da7213_audio_hpf_corner_txt); + +static const struct soc_enum da7213_adc_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, + DA7213_AUDIO_HPF_CORNER_MAX, + da7213_audio_hpf_corner_txt); + +/* Gain ramping rate value */ +static const char * const da7213_gain_ramp_rate_txt[] = { + "nominal rate * 8", "nominal rate * 16", "nominal rate / 16", + "nominal rate / 32" +}; + +static const struct soc_enum da7213_gain_ramp_rate = + SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT, + DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt); + +/* DAC noise gate setup time value */ +static const char * const da7213_dac_ng_setup_time_txt[] = { + "256 samples", "512 samples", "1024 samples", "2048 samples" +}; + +static const struct soc_enum da7213_dac_ng_setup_time = + SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_SETUP_TIME_SHIFT, + DA7213_DAC_NG_SETUP_TIME_MAX, + da7213_dac_ng_setup_time_txt); + +/* DAC noise gate rampup rate value */ +static const char * const da7213_dac_ng_rampup_txt[] = { + "0.02 ms/dB", "0.16 ms/dB" +}; + +static const struct soc_enum da7213_dac_ng_rampup_rate = + SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_RAMPUP_RATE_SHIFT, + DA7213_DAC_NG_RAMP_RATE_MAX, + da7213_dac_ng_rampup_txt); + +/* DAC noise gate rampdown rate value */ +static const char * const da7213_dac_ng_rampdown_txt[] = { + "0.64 ms/dB", "20.48 ms/dB" +}; + +static const struct soc_enum da7213_dac_ng_rampdown_rate = + SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_RAMPDN_RATE_SHIFT, + DA7213_DAC_NG_RAMP_RATE_MAX, + da7213_dac_ng_rampdown_txt); + +/* DAC soft mute rate value */ +static const char * const da7213_dac_soft_mute_rate_txt[] = { + "1", "2", "4", "8", "16", "32", "64" +}; + +static const struct soc_enum da7213_dac_soft_mute_rate = + SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT, + DA7213_DAC_SOFTMUTE_RATE_MAX, + da7213_dac_soft_mute_rate_txt); + +/* ALC Attack Rate select */ +static const char * const da7213_alc_attack_rate_txt[] = { + "44/fs", "88/fs", "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", + "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" +}; + +static const struct soc_enum da7213_alc_attack_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT, + DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt); + +/* ALC Release Rate select */ +static const char * const da7213_alc_release_rate_txt[] = { + "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", "5632/fs", + "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" +}; + +static const struct soc_enum da7213_alc_release_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT, + DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt); + +/* ALC Hold Time select */ +static const char * const da7213_alc_hold_time_txt[] = { + "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs", + "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs", + "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" +}; + +static const struct soc_enum da7213_alc_hold_time = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT, + DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt); + +/* ALC Input Signal Tracking rate select */ +static const char * const da7213_alc_integ_rate_txt[] = { + "1/4", "1/16", "1/256", "1/65536" +}; + +static const struct soc_enum da7213_alc_integ_attack_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT, + DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); + +static const struct soc_enum da7213_alc_integ_release_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT, + DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); + + +/* + * Control Functions + */ + +static int da7213_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) +{ + int mid_data, top_data; + int sum = 0; + u8 iteration; + + for (iteration = 0; iteration < DA7213_ALC_AVG_ITERATIONS; + iteration++) { + /* Select the left or right channel and capture data */ + snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL, reg_val); + + /* Select middle 8 bits for read back from data register */ + snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL, + reg_val | DA7213_ALC_DATA_MIDDLE); + mid_data = snd_soc_read(codec, DA7213_ALC_CIC_OP_LVL_DATA); + + /* Select top 8 bits for read back from data register */ + snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL, + reg_val | DA7213_ALC_DATA_TOP); + top_data = snd_soc_read(codec, DA7213_ALC_CIC_OP_LVL_DATA); + + sum += ((mid_data << 8) | (top_data << 16)); + } + + return sum / DA7213_ALC_AVG_ITERATIONS; +} + +static void da7213_alc_calib_man(struct snd_soc_codec *codec) +{ + u8 reg_val; + int avg_left_data, avg_right_data, offset_l, offset_r; + + /* Calculate average for Left and Right data */ + /* Left Data */ + avg_left_data = da7213_get_alc_data(codec, + DA7213_ALC_CIC_OP_CHANNEL_LEFT); + /* Right Data */ + avg_right_data = da7213_get_alc_data(codec, + DA7213_ALC_CIC_OP_CHANNEL_RIGHT); + + /* Calculate DC offset */ + offset_l = -avg_left_data; + offset_r = -avg_right_data; + + reg_val = (offset_l & DA7213_ALC_OFFSET_15_8) >> 8; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_M_L, reg_val); + reg_val = (offset_l & DA7213_ALC_OFFSET_19_16) >> 16; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_U_L, reg_val); + + reg_val = (offset_r & DA7213_ALC_OFFSET_15_8) >> 8; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_M_R, reg_val); + reg_val = (offset_r & DA7213_ALC_OFFSET_19_16) >> 16; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_U_R, reg_val); + + /* Enable analog/digital gain mode & offset cancellation */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE); +} + +static void da7213_alc_calib_auto(struct snd_soc_codec *codec) +{ + u8 alc_ctrl1; + + /* Begin auto calibration and wait for completion */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, DA7213_ALC_AUTO_CALIB_EN, + DA7213_ALC_AUTO_CALIB_EN); + do { + alc_ctrl1 = snd_soc_read(codec, DA7213_ALC_CTRL1); + } while (alc_ctrl1 & DA7213_ALC_AUTO_CALIB_EN); + + /* If auto calibration fails, fall back to digital gain only mode */ + if (alc_ctrl1 & DA7213_ALC_CALIB_OVERFLOW) { + dev_warn(codec->dev, + "ALC auto calibration failed with overflow\n"); + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE, + 0); + } else { + /* Enable analog/digital gain mode & offset cancellation */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE); + } + +} + +static void da7213_alc_calib(struct snd_soc_codec *codec) +{ + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + u8 adc_l_ctrl, adc_r_ctrl; + u8 mixin_l_sel, mixin_r_sel; + u8 mic_1_ctrl, mic_2_ctrl; + + /* Save current values from ADC control registers */ + adc_l_ctrl = snd_soc_read(codec, DA7213_ADC_L_CTRL); + adc_r_ctrl = snd_soc_read(codec, DA7213_ADC_R_CTRL); + + /* Save current values from MIXIN_L/R_SELECT registers */ + mixin_l_sel = snd_soc_read(codec, DA7213_MIXIN_L_SELECT); + mixin_r_sel = snd_soc_read(codec, DA7213_MIXIN_R_SELECT); + + /* Save current values from MIC control registers */ + mic_1_ctrl = snd_soc_read(codec, DA7213_MIC_1_CTRL); + mic_2_ctrl = snd_soc_read(codec, DA7213_MIC_2_CTRL); + + /* Enable ADC Left and Right */ + snd_soc_update_bits(codec, DA7213_ADC_L_CTRL, DA7213_ADC_EN, + DA7213_ADC_EN); + snd_soc_update_bits(codec, DA7213_ADC_R_CTRL, DA7213_ADC_EN, + DA7213_ADC_EN); + + /* Enable MIC paths */ + snd_soc_update_bits(codec, DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIC_1 | + DA7213_MIXIN_L_MIX_SELECT_MIC_2, + DA7213_MIXIN_L_MIX_SELECT_MIC_1 | + DA7213_MIXIN_L_MIX_SELECT_MIC_2); + snd_soc_update_bits(codec, DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIC_2 | + DA7213_MIXIN_R_MIX_SELECT_MIC_1, + DA7213_MIXIN_R_MIX_SELECT_MIC_2 | + DA7213_MIXIN_R_MIX_SELECT_MIC_1); + + /* Mute MIC PGAs */ + snd_soc_update_bits(codec, DA7213_MIC_1_CTRL, DA7213_MUTE_EN, + DA7213_MUTE_EN); + snd_soc_update_bits(codec, DA7213_MIC_2_CTRL, DA7213_MUTE_EN, + DA7213_MUTE_EN); + + /* Perform calibration */ + if (da7213->alc_calib_auto) + da7213_alc_calib_auto(codec); + else + da7213_alc_calib_man(codec); + + /* Restore MIXIN_L/R_SELECT registers to their original states */ + snd_soc_write(codec, DA7213_MIXIN_L_SELECT, mixin_l_sel); + snd_soc_write(codec, DA7213_MIXIN_R_SELECT, mixin_r_sel); + + /* Restore ADC control registers to their original states */ + snd_soc_write(codec, DA7213_ADC_L_CTRL, adc_l_ctrl); + snd_soc_write(codec, DA7213_ADC_R_CTRL, adc_r_ctrl); + + /* Restore original values of MIC control registers */ + snd_soc_write(codec, DA7213_MIC_1_CTRL, mic_1_ctrl); + snd_soc_write(codec, DA7213_MIC_2_CTRL, mic_2_ctrl); +} + +static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); + + /* If ALC in operation, make sure calibrated offsets are updated */ + if ((!ret) && (da7213->alc_en)) + da7213_alc_calib(codec); + + return ret; +} + +static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + + /* Force ALC offset calibration if enabling ALC */ + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) { + if (!da7213->alc_en) { + da7213_alc_calib(codec); + da7213->alc_en = true; + } + } else { + da7213->alc_en = false; + } + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + + +/* + * KControls + */ + +static const struct snd_kcontrol_new da7213_snd_controls[] = { + + /* Volume controls */ + SOC_SINGLE_TLV("Mic 1 Volume", DA7213_MIC_1_GAIN, + DA7213_MIC_AMP_GAIN_SHIFT, DA7213_MIC_AMP_GAIN_MAX, + DA7213_NO_INVERT, mic_vol_tlv), + SOC_SINGLE_TLV("Mic 2 Volume", DA7213_MIC_2_GAIN, + DA7213_MIC_AMP_GAIN_SHIFT, DA7213_MIC_AMP_GAIN_MAX, + DA7213_NO_INVERT, mic_vol_tlv), + SOC_DOUBLE_R_TLV("Aux Volume", DA7213_AUX_L_GAIN, DA7213_AUX_R_GAIN, + DA7213_AUX_AMP_GAIN_SHIFT, DA7213_AUX_AMP_GAIN_MAX, + DA7213_NO_INVERT, aux_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("Mixin PGA Volume", DA7213_MIXIN_L_GAIN, + DA7213_MIXIN_R_GAIN, DA7213_MIXIN_AMP_GAIN_SHIFT, + DA7213_MIXIN_AMP_GAIN_MAX, DA7213_NO_INVERT, + snd_soc_get_volsw_2r, da7213_put_mixin_gain, + mixin_gain_tlv), + SOC_DOUBLE_R_TLV("ADC Volume", DA7213_ADC_L_GAIN, DA7213_ADC_R_GAIN, + DA7213_ADC_AMP_GAIN_SHIFT, DA7213_ADC_AMP_GAIN_MAX, + DA7213_NO_INVERT, digital_gain_tlv), + SOC_DOUBLE_R_TLV("DAC Volume", DA7213_DAC_L_GAIN, DA7213_DAC_R_GAIN, + DA7213_DAC_AMP_GAIN_SHIFT, DA7213_DAC_AMP_GAIN_MAX, + DA7213_NO_INVERT, digital_gain_tlv), + SOC_DOUBLE_R_TLV("Headphone Volume", DA7213_HP_L_GAIN, DA7213_HP_R_GAIN, + DA7213_HP_AMP_GAIN_SHIFT, DA7213_HP_AMP_GAIN_MAX, + DA7213_NO_INVERT, hp_vol_tlv), + SOC_SINGLE_TLV("Lineout Volume", DA7213_LINE_GAIN, + DA7213_LINE_AMP_GAIN_SHIFT, DA7213_LINE_AMP_GAIN_MAX, + DA7213_NO_INVERT, lineout_vol_tlv), + + /* DAC Equalizer controls */ + SOC_SINGLE("DAC EQ Switch", DA7213_DAC_FILTERS4, DA7213_DAC_EQ_EN_SHIFT, + DA7213_DAC_EQ_EN_MAX, DA7213_NO_INVERT), + SOC_SINGLE_TLV("DAC EQ1 Volume", DA7213_DAC_FILTERS2, + DA7213_DAC_EQ_BAND1_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ2 Volume", DA7213_DAC_FILTERS2, + DA7213_DAC_EQ_BAND2_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ3 Volume", DA7213_DAC_FILTERS3, + DA7213_DAC_EQ_BAND3_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ4 Volume", DA7213_DAC_FILTERS3, + DA7213_DAC_EQ_BAND4_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ5 Volume", DA7213_DAC_FILTERS4, + DA7213_DAC_EQ_BAND5_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + + /* High Pass Filter and Voice Mode controls */ + SOC_SINGLE("ADC HPF Switch", DA7213_ADC_FILTERS1, DA7213_HPF_EN_SHIFT, + DA7213_HPF_EN_MAX, DA7213_NO_INVERT), + SOC_ENUM("ADC HPF Cutoff", da7213_adc_audio_hpf_corner), + SOC_SINGLE("ADC Voice Mode Switch", DA7213_ADC_FILTERS1, + DA7213_VOICE_EN_SHIFT, DA7213_VOICE_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("ADC Voice Cutoff", da7213_adc_voice_hpf_corner), + + SOC_SINGLE("DAC HPF Switch", DA7213_DAC_FILTERS1, DA7213_HPF_EN_SHIFT, + DA7213_HPF_EN_MAX, DA7213_NO_INVERT), + SOC_ENUM("DAC HPF Cutoff", da7213_dac_audio_hpf_corner), + SOC_SINGLE("DAC Voice Mode Switch", DA7213_DAC_FILTERS1, + DA7213_VOICE_EN_SHIFT, DA7213_VOICE_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("DAC Voice Cutoff", da7213_dac_voice_hpf_corner), + + /* Mute controls */ + SOC_SINGLE("Mic 1 Switch", DA7213_MIC_1_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_SINGLE("Mic 2 Switch", DA7213_MIC_2_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("Aux Switch", DA7213_AUX_L_CTRL, DA7213_AUX_R_CTRL, + DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("Mixin PGA Switch", DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_R_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("ADC Switch", DA7213_ADC_L_CTRL, DA7213_ADC_R_CTRL, + DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("Headphone Switch", DA7213_HP_L_CTRL, DA7213_HP_R_CTRL, + DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_SINGLE("Lineout Switch", DA7213_LINE_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_SINGLE("DAC Soft Mute Switch", DA7213_DAC_FILTERS5, + DA7213_DAC_SOFTMUTE_EN_SHIFT, DA7213_DAC_SOFTMUTE_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("DAC Soft Mute Rate", da7213_dac_soft_mute_rate), + + /* Zero Cross controls */ + SOC_DOUBLE_R("Aux ZC Switch", DA7213_AUX_L_CTRL, DA7213_AUX_R_CTRL, + DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("Mixin PGA ZC Switch", DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_R_CTRL, DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, + DA7213_NO_INVERT), + SOC_DOUBLE_R("Headphone ZC Switch", DA7213_HP_L_CTRL, DA7213_HP_R_CTRL, + DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, DA7213_NO_INVERT), + + /* Gain Ramping controls */ + SOC_DOUBLE_R("Aux Gain Ramping Switch", DA7213_AUX_L_CTRL, + DA7213_AUX_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("Mixin Gain Ramping Switch", DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("ADC Gain Ramping Switch", DA7213_ADC_L_CTRL, + DA7213_ADC_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("DAC Gain Ramping Switch", DA7213_DAC_L_CTRL, + DA7213_DAC_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("Headphone Gain Ramping Switch", DA7213_HP_L_CTRL, + DA7213_HP_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_SINGLE("Lineout Gain Ramping Switch", DA7213_LINE_CTRL, + DA7213_GAIN_RAMP_EN_SHIFT, DA7213_GAIN_RAMP_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("Gain Ramping Rate", da7213_gain_ramp_rate), + + /* DAC Noise Gate controls */ + SOC_SINGLE("DAC NG Switch", DA7213_DAC_NG_CTRL, DA7213_DAC_NG_EN_SHIFT, + DA7213_DAC_NG_EN_MAX, DA7213_NO_INVERT), + SOC_ENUM("DAC NG Setup Time", da7213_dac_ng_setup_time), + SOC_ENUM("DAC NG Rampup Rate", da7213_dac_ng_rampup_rate), + SOC_ENUM("DAC NG Rampdown Rate", da7213_dac_ng_rampdown_rate), + SOC_SINGLE("DAC NG OFF Threshold", DA7213_DAC_NG_OFF_THRESHOLD, + DA7213_DAC_NG_THRESHOLD_SHIFT, DA7213_DAC_NG_THRESHOLD_MAX, + DA7213_NO_INVERT), + SOC_SINGLE("DAC NG ON Threshold", DA7213_DAC_NG_ON_THRESHOLD, + DA7213_DAC_NG_THRESHOLD_SHIFT, DA7213_DAC_NG_THRESHOLD_MAX, + DA7213_NO_INVERT), + + /* DAC Routing & Inversion */ + SOC_DOUBLE("DAC Mono Switch", DA7213_DIG_ROUTING_DAC, + DA7213_DAC_L_MONO_SHIFT, DA7213_DAC_R_MONO_SHIFT, + DA7213_DAC_MONO_MAX, DA7213_NO_INVERT), + SOC_DOUBLE("DAC Invert Switch", DA7213_DIG_CTRL, DA7213_DAC_L_INV_SHIFT, + DA7213_DAC_R_INV_SHIFT, DA7213_DAC_INV_MAX, + DA7213_NO_INVERT), + + /* DMIC controls */ + SOC_DOUBLE_R("DMIC Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_R_SELECT, DA7213_DMIC_EN_SHIFT, + DA7213_DMIC_EN_MAX, DA7213_NO_INVERT), + + /* ALC Controls */ + SOC_DOUBLE_EXT("ALC Switch", DA7213_ALC_CTRL1, DA7213_ALC_L_EN_SHIFT, + DA7213_ALC_R_EN_SHIFT, DA7213_ALC_EN_MAX, + DA7213_NO_INVERT, snd_soc_get_volsw, da7213_put_alc_sw), + SOC_ENUM("ALC Attack Rate", da7213_alc_attack_rate), + SOC_ENUM("ALC Release Rate", da7213_alc_release_rate), + SOC_ENUM("ALC Hold Time", da7213_alc_hold_time), + /* + * Rate at which input signal envelope is tracked as the signal gets + * larger + */ + SOC_ENUM("ALC Integ Attack Rate", da7213_alc_integ_attack_rate), + /* + * Rate at which input signal envelope is tracked as the signal gets + * smaller + */ + SOC_ENUM("ALC Integ Release Rate", da7213_alc_integ_release_rate), + SOC_SINGLE_TLV("ALC Noise Threshold Volume", DA7213_ALC_NOISE, + DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX, + DA7213_INVERT, alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Min Threshold Volume", DA7213_ALC_TARGET_MIN, + DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX, + DA7213_INVERT, alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Threshold Volume", DA7213_ALC_TARGET_MAX, + DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX, + DA7213_INVERT, alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Attenuation Volume", DA7213_ALC_GAIN_LIMITS, + DA7213_ALC_ATTEN_MAX_SHIFT, + DA7213_ALC_ATTEN_GAIN_MAX_MAX, DA7213_NO_INVERT, + alc_gain_tlv), + SOC_SINGLE_TLV("ALC Max Gain Volume", DA7213_ALC_GAIN_LIMITS, + DA7213_ALC_GAIN_MAX_SHIFT, DA7213_ALC_ATTEN_GAIN_MAX_MAX, + DA7213_NO_INVERT, alc_gain_tlv), + SOC_SINGLE_TLV("ALC Min Analog Gain Volume", DA7213_ALC_ANA_GAIN_LIMITS, + DA7213_ALC_ANA_GAIN_MIN_SHIFT, DA7213_ALC_ANA_GAIN_MAX, + DA7213_NO_INVERT, alc_analog_gain_tlv), + SOC_SINGLE_TLV("ALC Max Analog Gain Volume", DA7213_ALC_ANA_GAIN_LIMITS, + DA7213_ALC_ANA_GAIN_MAX_SHIFT, DA7213_ALC_ANA_GAIN_MAX, + DA7213_NO_INVERT, alc_analog_gain_tlv), + SOC_SINGLE("ALC Anticlip Mode Switch", DA7213_ALC_ANTICLIP_CTRL, + DA7213_ALC_ANTICLIP_EN_SHIFT, DA7213_ALC_ANTICLIP_EN_MAX, + DA7213_NO_INVERT), + SOC_SINGLE("ALC Anticlip Level", DA7213_ALC_ANTICLIP_LEVEL, + DA7213_ALC_ANTICLIP_LEVEL_SHIFT, + DA7213_ALC_ANTICLIP_LEVEL_MAX, DA7213_NO_INVERT), +}; + + +/* + * DAPM + */ + +/* + * Enums + */ + +/* MIC PGA source select */ +static const char * const da7213_mic_amp_in_sel_txt[] = { + "Differential", "MIC_P", "MIC_N" +}; + +static const struct soc_enum da7213_mic_1_amp_in_sel = + SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, + DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux = + SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); + +static const struct soc_enum da7213_mic_2_amp_in_sel = + SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, + DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux = + SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); + +/* DAI routing select */ +static const char * const da7213_dai_src_txt[] = { + "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right" +}; + +static const struct soc_enum da7213_dai_l_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT, + DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static const struct snd_kcontrol_new da7213_dai_l_src_mux = + SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); + +static const struct soc_enum da7213_dai_r_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT, + DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static const struct snd_kcontrol_new da7213_dai_r_src_mux = + SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); + +/* DAC routing select */ +static const char * const da7213_dac_src_txt[] = { + "ADC Output Left", "ADC Output Right", "DAI Input Left", + "DAI Input Right" +}; + +static const struct soc_enum da7213_dac_l_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT, + DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static const struct snd_kcontrol_new da7213_dac_l_src_mux = + SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); + +static const struct soc_enum da7213_dac_r_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT, + DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static const struct snd_kcontrol_new da7213_dac_r_src_mux = + SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); + +/* + * Mixer Controls + */ + +/* Mixin Left */ +static const struct snd_kcontrol_new da7213_dapm_mixinl_controls[] = { + SOC_DAPM_SINGLE("Aux Left Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 1 Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 2 Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + +/* Mixin Right */ +static const struct snd_kcontrol_new da7213_dapm_mixinr_controls[] = { + SOC_DAPM_SINGLE("Aux Right Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 2 Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 1 Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + +/* Mixout Left */ +static const struct snd_kcontrol_new da7213_dapm_mixoutl_controls[] = { + SOC_DAPM_SINGLE("Aux Left Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("DAC Left Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Aux Left Invert Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + +/* Mixout Right */ +static const struct snd_kcontrol_new da7213_dapm_mixoutr_controls[] = { + SOC_DAPM_SINGLE("Aux Right Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("DAC Right Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Aux Right Invert Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + + +/* + * DAPM widgets + */ + +static const struct snd_soc_dapm_widget da7213_dapm_widgets[] = { + /* + * Input & Output + */ + + /* Use a supply here as this controls both input & output DAIs */ + SND_SOC_DAPM_SUPPLY("DAI", DA7213_DAI_CTRL, DA7213_DAI_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + + /* + * Input + */ + + /* Input Lines */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("AUXL"), + SND_SOC_DAPM_INPUT("AUXR"), + + /* MUXs for Mic PGA source selection */ + SND_SOC_DAPM_MUX("Mic 1 Amp Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_mic_1_amp_in_sel_mux), + SND_SOC_DAPM_MUX("Mic 2 Amp Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_mic_2_amp_in_sel_mux), + + /* Input PGAs */ + SND_SOC_DAPM_PGA("Mic 1 PGA", DA7213_MIC_1_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mic 2 PGA", DA7213_MIC_2_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Aux Left PGA", DA7213_AUX_L_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Aux Right PGA", DA7213_AUX_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mixin Left PGA", DA7213_MIXIN_L_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mixin Right PGA", DA7213_MIXIN_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + + /* Mic Biases */ + SND_SOC_DAPM_SUPPLY("Mic Bias 1", DA7213_MICBIAS_CTRL, + DA7213_MICBIAS1_EN_SHIFT, DA7213_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias 2", DA7213_MICBIAS_CTRL, + DA7213_MICBIAS2_EN_SHIFT, DA7213_NO_INVERT, + NULL, 0), + + /* Input Mixers */ + SND_SOC_DAPM_MIXER("Mixin Left", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixinl_controls[0], + ARRAY_SIZE(da7213_dapm_mixinl_controls)), + SND_SOC_DAPM_MIXER("Mixin Right", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixinr_controls[0], + ARRAY_SIZE(da7213_dapm_mixinr_controls)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC Left", NULL, DA7213_ADC_L_CTRL, + DA7213_ADC_EN_SHIFT, DA7213_NO_INVERT), + SND_SOC_DAPM_ADC("ADC Right", NULL, DA7213_ADC_R_CTRL, + DA7213_ADC_EN_SHIFT, DA7213_NO_INVERT), + + /* DAI */ + SND_SOC_DAPM_MUX("DAI Left Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dai_l_src_mux), + SND_SOC_DAPM_MUX("DAI Right Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dai_r_src_mux), + SND_SOC_DAPM_AIF_OUT("DAIOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DAIOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), + + /* + * Output + */ + + /* DAI */ + SND_SOC_DAPM_AIF_IN("DAIINL", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DAIINR", "Playback", 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("DAC Left Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dac_l_src_mux), + SND_SOC_DAPM_MUX("DAC Right Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dac_r_src_mux), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC Left", NULL, DA7213_DAC_L_CTRL, + DA7213_DAC_EN_SHIFT, DA7213_NO_INVERT), + SND_SOC_DAPM_DAC("DAC Right", NULL, DA7213_DAC_R_CTRL, + DA7213_DAC_EN_SHIFT, DA7213_NO_INVERT), + + /* Output Mixers */ + SND_SOC_DAPM_MIXER("Mixout Left", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixoutl_controls[0], + ARRAY_SIZE(da7213_dapm_mixoutl_controls)), + SND_SOC_DAPM_MIXER("Mixout Right", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixoutr_controls[0], + ARRAY_SIZE(da7213_dapm_mixoutr_controls)), + + /* Output PGAs */ + SND_SOC_DAPM_PGA("Mixout Left PGA", DA7213_MIXOUT_L_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mixout Right PGA", DA7213_MIXOUT_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Lineout PGA", DA7213_LINE_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Headphone Left PGA", DA7213_HP_L_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Headphone Right PGA", DA7213_HP_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + + /* Charge Pump */ + SND_SOC_DAPM_SUPPLY("Charge Pump", DA7213_CP_CTRL, DA7213_CP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), + SND_SOC_DAPM_OUTPUT("LINE"), +}; + + +/* + * DAPM audio route definition + */ + +static const struct snd_soc_dapm_route da7213_audio_map[] = { + /* Dest Connecting Widget source */ + + /* Input path */ + {"MIC1", NULL, "Mic Bias 1"}, + {"MIC2", NULL, "Mic Bias 2"}, + + {"Mic 1 Amp Source MUX", "Differential", "MIC1"}, + {"Mic 1 Amp Source MUX", "MIC_P", "MIC1"}, + {"Mic 1 Amp Source MUX", "MIC_N", "MIC1"}, + + {"Mic 2 Amp Source MUX", "Differential", "MIC2"}, + {"Mic 2 Amp Source MUX", "MIC_P", "MIC2"}, + {"Mic 2 Amp Source MUX", "MIC_N", "MIC2"}, + + {"Mic 1 PGA", NULL, "Mic 1 Amp Source MUX"}, + {"Mic 2 PGA", NULL, "Mic 2 Amp Source MUX"}, + + {"Aux Left PGA", NULL, "AUXL"}, + {"Aux Right PGA", NULL, "AUXR"}, + + {"Mixin Left", "Aux Left Switch", "Aux Left PGA"}, + {"Mixin Left", "Mic 1 Switch", "Mic 1 PGA"}, + {"Mixin Left", "Mic 2 Switch", "Mic 2 PGA"}, + {"Mixin Left", "Mixin Right Switch", "Mixin Right PGA"}, + + {"Mixin Right", "Aux Right Switch", "Aux Right PGA"}, + {"Mixin Right", "Mic 2 Switch", "Mic 2 PGA"}, + {"Mixin Right", "Mic 1 Switch", "Mic 1 PGA"}, + {"Mixin Right", "Mixin Left Switch", "Mixin Left PGA"}, + + {"Mixin Left PGA", NULL, "Mixin Left"}, + {"ADC Left", NULL, "Mixin Left PGA"}, + + {"Mixin Right PGA", NULL, "Mixin Right"}, + {"ADC Right", NULL, "Mixin Right PGA"}, + + {"DAI Left Source MUX", "ADC Left", "ADC Left"}, + {"DAI Left Source MUX", "ADC Right", "ADC Right"}, + {"DAI Left Source MUX", "DAI Input Left", "DAIINL"}, + {"DAI Left Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAI Right Source MUX", "ADC Left", "ADC Left"}, + {"DAI Right Source MUX", "ADC Right", "ADC Right"}, + {"DAI Right Source MUX", "DAI Input Left", "DAIINL"}, + {"DAI Right Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAIOUTL", NULL, "DAI Left Source MUX"}, + {"DAIOUTR", NULL, "DAI Right Source MUX"}, + + {"DAIOUTL", NULL, "DAI"}, + {"DAIOUTR", NULL, "DAI"}, + + /* Output path */ + {"DAIINL", NULL, "DAI"}, + {"DAIINR", NULL, "DAI"}, + + {"DAC Left Source MUX", "ADC Output Left", "ADC Left"}, + {"DAC Left Source MUX", "ADC Output Right", "ADC Right"}, + {"DAC Left Source MUX", "DAI Input Left", "DAIINL"}, + {"DAC Left Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAC Right Source MUX", "ADC Output Left", "ADC Left"}, + {"DAC Right Source MUX", "ADC Output Right", "ADC Right"}, + {"DAC Right Source MUX", "DAI Input Left", "DAIINL"}, + {"DAC Right Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAC Left", NULL, "DAC Left Source MUX"}, + {"DAC Right", NULL, "DAC Right Source MUX"}, + + {"Mixout Left", "Aux Left Switch", "Aux Left PGA"}, + {"Mixout Left", "Mixin Left Switch", "Mixin Left PGA"}, + {"Mixout Left", "Mixin Right Switch", "Mixin Right PGA"}, + {"Mixout Left", "DAC Left Switch", "DAC Left"}, + {"Mixout Left", "Aux Left Invert Switch", "Aux Left PGA"}, + {"Mixout Left", "Mixin Left Invert Switch", "Mixin Left PGA"}, + {"Mixout Left", "Mixin Right Invert Switch", "Mixin Right PGA"}, + + {"Mixout Right", "Aux Right Switch", "Aux Right PGA"}, + {"Mixout Right", "Mixin Right Switch", "Mixin Right PGA"}, + {"Mixout Right", "Mixin Left Switch", "Mixin Left PGA"}, + {"Mixout Right", "DAC Right Switch", "DAC Right"}, + {"Mixout Right", "Aux Right Invert Switch", "Aux Right PGA"}, + {"Mixout Right", "Mixin Right Invert Switch", "Mixin Right PGA"}, + {"Mixout Right", "Mixin Left Invert Switch", "Mixin Left PGA"}, + + {"Mixout Left PGA", NULL, "Mixout Left"}, + {"Mixout Right PGA", NULL, "Mixout Right"}, + + {"Headphone Left PGA", NULL, "Mixout Left PGA"}, + {"Headphone Left PGA", NULL, "Charge Pump"}, + {"HPL", NULL, "Headphone Left PGA"}, + + {"Headphone Right PGA", NULL, "Mixout Right PGA"}, + {"Headphone Right PGA", NULL, "Charge Pump"}, + {"HPR", NULL, "Headphone Right PGA"}, + + {"Lineout PGA", NULL, "Mixout Right PGA"}, + {"LINE", NULL, "Lineout PGA"}, +}; + +static struct reg_default da7213_reg_defaults[] = { + { DA7213_DIG_ROUTING_DAI, 0x10 }, + { DA7213_SR, 0x0A }, + { DA7213_REFERENCES, 0x80 }, + { DA7213_PLL_FRAC_TOP, 0x00 }, + { DA7213_PLL_FRAC_BOT, 0x00 }, + { DA7213_PLL_INTEGER, 0x20 }, + { DA7213_PLL_CTRL, 0x0C }, + { DA7213_DAI_CLK_MODE, 0x01 }, + { DA7213_DAI_CTRL, 0x08 }, + { DA7213_DIG_ROUTING_DAC, 0x32 }, + { DA7213_AUX_L_GAIN, 0x35 }, + { DA7213_AUX_R_GAIN, 0x35 }, + { DA7213_MIXIN_L_SELECT, 0x00 }, + { DA7213_MIXIN_R_SELECT, 0x00 }, + { DA7213_MIXIN_L_GAIN, 0x03 }, + { DA7213_MIXIN_R_GAIN, 0x03 }, + { DA7213_ADC_L_GAIN, 0x6F }, + { DA7213_ADC_R_GAIN, 0x6F }, + { DA7213_ADC_FILTERS1, 0x80 }, + { DA7213_MIC_1_GAIN, 0x01 }, + { DA7213_MIC_2_GAIN, 0x01 }, + { DA7213_DAC_FILTERS5, 0x00 }, + { DA7213_DAC_FILTERS2, 0x88 }, + { DA7213_DAC_FILTERS3, 0x88 }, + { DA7213_DAC_FILTERS4, 0x08 }, + { DA7213_DAC_FILTERS1, 0x80 }, + { DA7213_DAC_L_GAIN, 0x6F }, + { DA7213_DAC_R_GAIN, 0x6F }, + { DA7213_CP_CTRL, 0x61 }, + { DA7213_HP_L_GAIN, 0x39 }, + { DA7213_HP_R_GAIN, 0x39 }, + { DA7213_LINE_GAIN, 0x30 }, + { DA7213_MIXOUT_L_SELECT, 0x00 }, + { DA7213_MIXOUT_R_SELECT, 0x00 }, + { DA7213_SYSTEM_MODES_INPUT, 0x00 }, + { DA7213_SYSTEM_MODES_OUTPUT, 0x00 }, + { DA7213_AUX_L_CTRL, 0x44 }, + { DA7213_AUX_R_CTRL, 0x44 }, + { DA7213_MICBIAS_CTRL, 0x11 }, + { DA7213_MIC_1_CTRL, 0x40 }, + { DA7213_MIC_2_CTRL, 0x40 }, + { DA7213_MIXIN_L_CTRL, 0x40 }, + { DA7213_MIXIN_R_CTRL, 0x40 }, + { DA7213_ADC_L_CTRL, 0x40 }, + { DA7213_ADC_R_CTRL, 0x40 }, + { DA7213_DAC_L_CTRL, 0x48 }, + { DA7213_DAC_R_CTRL, 0x40 }, + { DA7213_HP_L_CTRL, 0x41 }, + { DA7213_HP_R_CTRL, 0x40 }, + { DA7213_LINE_CTRL, 0x40 }, + { DA7213_MIXOUT_L_CTRL, 0x10 }, + { DA7213_MIXOUT_R_CTRL, 0x10 }, + { DA7213_LDO_CTRL, 0x00 }, + { DA7213_IO_CTRL, 0x00 }, + { DA7213_GAIN_RAMP_CTRL, 0x00}, + { DA7213_MIC_CONFIG, 0x00 }, + { DA7213_PC_COUNT, 0x00 }, + { DA7213_CP_VOL_THRESHOLD1, 0x32 }, + { DA7213_CP_DELAY, 0x95 }, + { DA7213_CP_DETECTOR, 0x00 }, + { DA7213_DAI_OFFSET, 0x00 }, + { DA7213_DIG_CTRL, 0x00 }, + { DA7213_ALC_CTRL2, 0x00 }, + { DA7213_ALC_CTRL3, 0x00 }, + { DA7213_ALC_NOISE, 0x3F }, + { DA7213_ALC_TARGET_MIN, 0x3F }, + { DA7213_ALC_TARGET_MAX, 0x00 }, + { DA7213_ALC_GAIN_LIMITS, 0xFF }, + { DA7213_ALC_ANA_GAIN_LIMITS, 0x71 }, + { DA7213_ALC_ANTICLIP_CTRL, 0x00 }, + { DA7213_ALC_ANTICLIP_LEVEL, 0x00 }, + { DA7213_ALC_OFFSET_MAN_M_L, 0x00 }, + { DA7213_ALC_OFFSET_MAN_U_L, 0x00 }, + { DA7213_ALC_OFFSET_MAN_M_R, 0x00 }, + { DA7213_ALC_OFFSET_MAN_U_R, 0x00 }, + { DA7213_ALC_CIC_OP_LVL_CTRL, 0x00 }, + { DA7213_DAC_NG_SETUP_TIME, 0x00 }, + { DA7213_DAC_NG_OFF_THRESHOLD, 0x00 }, + { DA7213_DAC_NG_ON_THRESHOLD, 0x00 }, + { DA7213_DAC_NG_CTRL, 0x00 }, +}; + +static bool da7213_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA7213_STATUS1: + case DA7213_PLL_STATUS: + case DA7213_AUX_L_GAIN_STATUS: + case DA7213_AUX_R_GAIN_STATUS: + case DA7213_MIC_1_GAIN_STATUS: + case DA7213_MIC_2_GAIN_STATUS: + case DA7213_MIXIN_L_GAIN_STATUS: + case DA7213_MIXIN_R_GAIN_STATUS: + case DA7213_ADC_L_GAIN_STATUS: + case DA7213_ADC_R_GAIN_STATUS: + case DA7213_DAC_L_GAIN_STATUS: + case DA7213_DAC_R_GAIN_STATUS: + case DA7213_HP_L_GAIN_STATUS: + case DA7213_HP_R_GAIN_STATUS: + case DA7213_LINE_GAIN_STATUS: + case DA7213_ALC_CTRL1: + case DA7213_ALC_OFFSET_AUTO_M_L: + case DA7213_ALC_OFFSET_AUTO_U_L: + case DA7213_ALC_OFFSET_AUTO_M_R: + case DA7213_ALC_OFFSET_AUTO_U_R: + case DA7213_ALC_CIC_OP_LVL_DATA: + return 1; + default: + return 0; + } +} + +static int da7213_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; + u8 dai_ctrl = 0; + u8 fs; + + /* Set DAI format */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S20_LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S24_LE; + break; + case SNDRV_PCM_FORMAT_S32_LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S32_LE; + break; + default: + return -EINVAL; + } + + /* Set sampling rate */ + switch (params_rate(params)) { + case 8000: + fs = DA7213_SR_8000; + break; + case 11025: + fs = DA7213_SR_11025; + break; + case 12000: + fs = DA7213_SR_12000; + break; + case 16000: + fs = DA7213_SR_16000; + break; + case 22050: + fs = DA7213_SR_22050; + break; + case 32000: + fs = DA7213_SR_32000; + break; + case 44100: + fs = DA7213_SR_44100; + break; + case 48000: + fs = DA7213_SR_48000; + break; + case 88200: + fs = DA7213_SR_88200; + break; + case 96000: + fs = DA7213_SR_96000; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_WORD_LENGTH_MASK, + dai_ctrl); + snd_soc_write(codec, DA7213_SR, fs); + + return 0; +} + +static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + u8 dai_clk_mode = 0, dai_ctrl = 0; + + /* Set master/slave mode */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + dai_clk_mode |= DA7213_DAI_CLK_EN_MASTER_MODE; + da7213->master = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + dai_clk_mode |= DA7213_DAI_CLK_EN_SLAVE_MODE; + da7213->master = false; + break; + default: + return -EINVAL; + } + + /* Set clock normal/inverted */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7213_DAI_WCLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + dai_clk_mode |= DA7213_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7213_DAI_WCLK_POL_INV | DA7213_DAI_CLK_POL_INV; + break; + default: + return -EINVAL; + } + + /* Only I2S is supported */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dai_ctrl |= DA7213_DAI_FORMAT_I2S_MODE; + break; + case SND_SOC_DAIFMT_LEFT_J: + dai_ctrl |= DA7213_DAI_FORMAT_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + dai_ctrl |= DA7213_DAI_FORMAT_RIGHT_J; + break; + default: + return -EINVAL; + } + + /* By default only 32 BCLK per WCLK is supported */ + dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_32; + + snd_soc_write(codec, DA7213_DAI_CLK_MODE, dai_clk_mode); + snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK, + dai_ctrl); + + return 0; +} + +static int da7213_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + snd_soc_update_bits(codec, DA7213_DAC_L_CTRL, + DA7213_MUTE_EN, DA7213_MUTE_EN); + snd_soc_update_bits(codec, DA7213_DAC_R_CTRL, + DA7213_MUTE_EN, DA7213_MUTE_EN); + } else { + snd_soc_update_bits(codec, DA7213_DAC_L_CTRL, + DA7213_MUTE_EN, 0); + snd_soc_update_bits(codec, DA7213_DAC_R_CTRL, + DA7213_MUTE_EN, 0); + } + + return 0; +} + +#define DA7213_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case DA7213_CLKSRC_MCLK: + if ((freq == 32768) || + ((freq >= 5000000) && (freq <= 54000000))) { + da7213->mclk_rate = freq; + return 0; + } else { + dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", + freq); + return -EINVAL; + } + break; + default: + dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + return -EINVAL; + } +} + +/* Supported PLL input frequencies are 5MHz - 54MHz. */ +static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + + u8 pll_ctrl, indiv_bits, indiv; + u8 pll_frac_top, pll_frac_bot, pll_integer; + u32 freq_ref; + u64 frac_div; + + /* Reset PLL configuration */ + snd_soc_write(codec, DA7213_PLL_CTRL, 0); + + pll_ctrl = 0; + + /* Workout input divider based on MCLK rate */ + if ((da7213->mclk_rate == 32768) && (source == DA7213_SYSCLK_PLL)) { + /* 32KHz PLL Mode */ + indiv_bits = DA7213_PLL_INDIV_10_20_MHZ; + indiv = DA7213_PLL_INDIV_10_20_MHZ_VAL; + freq_ref = 3750000; + pll_ctrl |= DA7213_PLL_32K_MODE; + } else { + /* 5 - 54MHz MCLK */ + if (da7213->mclk_rate < 5000000) { + goto pll_err; + } else if (da7213->mclk_rate <= 10000000) { + indiv_bits = DA7213_PLL_INDIV_5_10_MHZ; + indiv = DA7213_PLL_INDIV_5_10_MHZ_VAL; + } else if (da7213->mclk_rate <= 20000000) { + indiv_bits = DA7213_PLL_INDIV_10_20_MHZ; + indiv = DA7213_PLL_INDIV_10_20_MHZ_VAL; + } else if (da7213->mclk_rate <= 40000000) { + indiv_bits = DA7213_PLL_INDIV_20_40_MHZ; + indiv = DA7213_PLL_INDIV_20_40_MHZ_VAL; + } else if (da7213->mclk_rate <= 54000000) { + indiv_bits = DA7213_PLL_INDIV_40_54_MHZ; + indiv = DA7213_PLL_INDIV_40_54_MHZ_VAL; + } else { + goto pll_err; + } + freq_ref = (da7213->mclk_rate / indiv); + } + + pll_ctrl |= indiv_bits; + + /* PLL Bypass mode */ + if (source == DA7213_SYSCLK_MCLK) { + snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + return 0; + } + + /* + * If Codec is slave and SRM enabled, + * freq_out is (98304000 + 90316800)/2 = 94310400 + */ + if (!da7213->master && da7213->srm_en) { + fout = DA7213_PLL_FREQ_OUT_94310400; + pll_ctrl |= DA7213_PLL_SRM_EN; + } + + /* Enable MCLK squarer if required */ + if (da7213->mclk_squarer_en) + pll_ctrl |= DA7213_PLL_MCLK_SQR_EN; + + /* Calculate dividers for PLL */ + pll_integer = fout / freq_ref; + frac_div = (u64)(fout % freq_ref) * 8192ULL; + do_div(frac_div, freq_ref); + pll_frac_top = (frac_div >> DA7213_BYTE_SHIFT) & DA7213_BYTE_MASK; + pll_frac_bot = (frac_div) & DA7213_BYTE_MASK; + + /* Write PLL dividers */ + snd_soc_write(codec, DA7213_PLL_FRAC_TOP, pll_frac_top); + snd_soc_write(codec, DA7213_PLL_FRAC_BOT, pll_frac_bot); + snd_soc_write(codec, DA7213_PLL_INTEGER, pll_integer); + + /* Enable PLL */ + pll_ctrl |= DA7213_PLL_EN; + snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + + return 0; + +pll_err: + dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", + da7213->mclk_rate); + return -EINVAL; +} + +/* DAI operations */ +static const struct snd_soc_dai_ops da7213_dai_ops = { + .hw_params = da7213_hw_params, + .set_fmt = da7213_set_dai_fmt, + .set_sysclk = da7213_set_dai_sysclk, + .set_pll = da7213_set_dai_pll, + .digital_mute = da7213_mute, +}; + +static struct snd_soc_dai_driver da7213_dai = { + .name = "da7213-hifi", + /* Playback Capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7213_FORMATS, + }, + /* Capture Capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7213_FORMATS, + }, + .ops = &da7213_dai_ops, + .symmetric_rates = 1, +}; + +static int da7213_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + /* Enable VMID reference & master bias */ + snd_soc_update_bits(codec, DA7213_REFERENCES, + DA7213_VMID_EN | DA7213_BIAS_EN, + DA7213_VMID_EN | DA7213_BIAS_EN); + } + break; + case SND_SOC_BIAS_OFF: + /* Disable VMID reference & master bias */ + snd_soc_update_bits(codec, DA7213_REFERENCES, + DA7213_VMID_EN | DA7213_BIAS_EN, 0); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +static int da7213_probe(struct snd_soc_codec *codec) +{ + int ret; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + struct da7213_platform_data *pdata = da7213->pdata; + + codec->control_data = da7213->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + /* Default to using ALC auto offset calibration mode. */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_CALIB_MODE_MAN, 0); + da7213->alc_calib_auto = true; + + /* Default to using SRM for slave mode */ + da7213->srm_en = true; + + /* Enable all Gain Ramps */ + snd_soc_update_bits(codec, DA7213_AUX_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_AUX_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_MIXIN_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_MIXIN_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_ADC_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_ADC_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_DAC_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_DAC_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_HP_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_HP_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_LINE_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + + /* + * There are two separate control bits for input and output mixers as + * well as headphone and line outs. + * 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 + * enabled here + */ + snd_soc_update_bits(codec, DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN); + snd_soc_update_bits(codec, DA7213_MIXIN_R_CTRL, + DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN); + + snd_soc_update_bits(codec, DA7213_MIXOUT_L_CTRL, + DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN); + snd_soc_update_bits(codec, DA7213_MIXOUT_R_CTRL, + DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN); + + snd_soc_update_bits(codec, DA7213_HP_L_CTRL, + DA7213_HP_AMP_OE, DA7213_HP_AMP_OE); + snd_soc_update_bits(codec, DA7213_HP_R_CTRL, + DA7213_HP_AMP_OE, DA7213_HP_AMP_OE); + + snd_soc_update_bits(codec, DA7213_LINE_CTRL, + DA7213_LINE_AMP_OE, DA7213_LINE_AMP_OE); + + /* Set platform data values */ + if (da7213->pdata) { + u8 micbias_lvl = 0, dmic_cfg = 0; + + /* Set Mic Bias voltages */ + switch (pdata->micbias1_lvl) { + case DA7213_MICBIAS_1_6V: + case DA7213_MICBIAS_2_2V: + case DA7213_MICBIAS_2_5V: + case DA7213_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias1_lvl << + DA7213_MICBIAS1_LEVEL_SHIFT); + break; + } + switch (pdata->micbias2_lvl) { + case DA7213_MICBIAS_1_6V: + case DA7213_MICBIAS_2_2V: + case DA7213_MICBIAS_2_5V: + case DA7213_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias2_lvl << + DA7213_MICBIAS2_LEVEL_SHIFT); + break; + } + snd_soc_update_bits(codec, DA7213_MICBIAS_CTRL, + DA7213_MICBIAS1_LEVEL_MASK | + DA7213_MICBIAS2_LEVEL_MASK, micbias_lvl); + + /* Set DMIC configuration */ + switch (pdata->dmic_data_sel) { + case DA7213_DMIC_DATA_LFALL_RRISE: + case DA7213_DMIC_DATA_LRISE_RFALL: + dmic_cfg |= (pdata->dmic_data_sel << + DA7213_DMIC_DATA_SEL_SHIFT); + break; + } + switch (pdata->dmic_data_sel) { + case DA7213_DMIC_SAMPLE_ON_CLKEDGE: + case DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE: + dmic_cfg |= (pdata->dmic_data_sel << + DA7213_DMIC_SAMPLEPHASE_SHIFT); + break; + } + switch (pdata->dmic_data_sel) { + case DA7213_DMIC_CLK_3_0MHZ: + case DA7213_DMIC_CLK_1_5MHZ: + dmic_cfg |= (pdata->dmic_data_sel << + DA7213_DMIC_CLK_RATE_SHIFT); + break; + } + snd_soc_update_bits(codec, DA7213_MIC_CONFIG, + DA7213_DMIC_DATA_SEL_MASK | + DA7213_DMIC_SAMPLEPHASE_MASK | + DA7213_DMIC_CLK_RATE_MASK, dmic_cfg); + + /* Set MCLK squaring */ + da7213->mclk_squarer_en = pdata->mclk_squaring; + } + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_da7213 = { + .probe = da7213_probe, + .set_bias_level = da7213_set_bias_level, + + .controls = da7213_snd_controls, + .num_controls = ARRAY_SIZE(da7213_snd_controls), + + .dapm_widgets = da7213_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7213_dapm_widgets), + .dapm_routes = da7213_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7213_audio_map), +}; + +static const struct regmap_config da7213_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = da7213_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(da7213_reg_defaults), + .volatile_reg = da7213_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int da7213_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da7213_priv *da7213; + struct da7213_platform_data *pdata = dev_get_platdata(&i2c->dev); + int ret; + + da7213 = devm_kzalloc(&i2c->dev, sizeof(struct da7213_priv), + GFP_KERNEL); + if (!da7213) + return -ENOMEM; + + if (pdata) + da7213->pdata = pdata; + + i2c_set_clientdata(i2c, da7213); + + da7213->regmap = devm_regmap_init_i2c(i2c, &da7213_regmap_config); + if (IS_ERR(da7213->regmap)) { + ret = PTR_ERR(da7213->regmap); + dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_da7213, &da7213_dai, 1); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register da7213 codec: %d\n", + ret); + } + return ret; +} + +static int da7213_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id da7213_i2c_id[] = { + { "da7213", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, da7213_i2c_id); + +/* I2C codec control layer */ +static struct i2c_driver da7213_i2c_driver = { + .driver = { + .name = "da7213", + .owner = THIS_MODULE, + }, + .probe = da7213_i2c_probe, + .remove = da7213_remove, + .id_table = da7213_i2c_id, +}; + +module_i2c_driver(da7213_i2c_driver); + +MODULE_DESCRIPTION("ASoC DA7213 Codec driver"); +MODULE_AUTHOR("Adam Thomson "); +MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/da7213.h b/trunk/sound/soc/codecs/da7213.h new file mode 100644 index 000000000000..9cb9ddd01282 --- /dev/null +++ b/trunk/sound/soc/codecs/da7213.h @@ -0,0 +1,523 @@ +/* + * da7213.h - DA7213 ASoC Codec Driver + * + * Copyright (c) 2013 Dialog Semiconductor + * + * Author: Adam Thomson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DA7213_H +#define _DA7213_H + +#include +#include + +/* + * Registers + */ + +/* Status Registers */ +#define DA7213_STATUS1 0x02 +#define DA7213_PLL_STATUS 0x03 +#define DA7213_AUX_L_GAIN_STATUS 0x04 +#define DA7213_AUX_R_GAIN_STATUS 0x05 +#define DA7213_MIC_1_GAIN_STATUS 0x06 +#define DA7213_MIC_2_GAIN_STATUS 0x07 +#define DA7213_MIXIN_L_GAIN_STATUS 0x08 +#define DA7213_MIXIN_R_GAIN_STATUS 0x09 +#define DA7213_ADC_L_GAIN_STATUS 0x0A +#define DA7213_ADC_R_GAIN_STATUS 0x0B +#define DA7213_DAC_L_GAIN_STATUS 0x0C +#define DA7213_DAC_R_GAIN_STATUS 0x0D +#define DA7213_HP_L_GAIN_STATUS 0x0E +#define DA7213_HP_R_GAIN_STATUS 0x0F +#define DA7213_LINE_GAIN_STATUS 0x10 + +/* System Initialisation Registers */ +#define DA7213_DIG_ROUTING_DAI 0x21 +#define DA7213_SR 0x22 +#define DA7213_REFERENCES 0x23 +#define DA7213_PLL_FRAC_TOP 0x24 +#define DA7213_PLL_FRAC_BOT 0x25 +#define DA7213_PLL_INTEGER 0x26 +#define DA7213_PLL_CTRL 0x27 +#define DA7213_DAI_CLK_MODE 0x28 +#define DA7213_DAI_CTRL 0x29 +#define DA7213_DIG_ROUTING_DAC 0x2A +#define DA7213_ALC_CTRL1 0x2B + +/* Input - Gain, Select and Filter Registers */ +#define DA7213_AUX_L_GAIN 0x30 +#define DA7213_AUX_R_GAIN 0x31 +#define DA7213_MIXIN_L_SELECT 0x32 +#define DA7213_MIXIN_R_SELECT 0x33 +#define DA7213_MIXIN_L_GAIN 0x34 +#define DA7213_MIXIN_R_GAIN 0x35 +#define DA7213_ADC_L_GAIN 0x36 +#define DA7213_ADC_R_GAIN 0x37 +#define DA7213_ADC_FILTERS1 0x38 +#define DA7213_MIC_1_GAIN 0x39 +#define DA7213_MIC_2_GAIN 0x3A + +/* Output - Gain, Select and Filter Registers */ +#define DA7213_DAC_FILTERS5 0x40 +#define DA7213_DAC_FILTERS2 0x41 +#define DA7213_DAC_FILTERS3 0x42 +#define DA7213_DAC_FILTERS4 0x43 +#define DA7213_DAC_FILTERS1 0x44 +#define DA7213_DAC_L_GAIN 0x45 +#define DA7213_DAC_R_GAIN 0x46 +#define DA7213_CP_CTRL 0x47 +#define DA7213_HP_L_GAIN 0x48 +#define DA7213_HP_R_GAIN 0x49 +#define DA7213_LINE_GAIN 0x4A +#define DA7213_MIXOUT_L_SELECT 0x4B +#define DA7213_MIXOUT_R_SELECT 0x4C + +/* System Controller Registers */ +#define DA7213_SYSTEM_MODES_INPUT 0x50 +#define DA7213_SYSTEM_MODES_OUTPUT 0x51 + +/* Control Registers */ +#define DA7213_AUX_L_CTRL 0x60 +#define DA7213_AUX_R_CTRL 0x61 +#define DA7213_MICBIAS_CTRL 0x62 +#define DA7213_MIC_1_CTRL 0x63 +#define DA7213_MIC_2_CTRL 0x64 +#define DA7213_MIXIN_L_CTRL 0x65 +#define DA7213_MIXIN_R_CTRL 0x66 +#define DA7213_ADC_L_CTRL 0x67 +#define DA7213_ADC_R_CTRL 0x68 +#define DA7213_DAC_L_CTRL 0x69 +#define DA7213_DAC_R_CTRL 0x6A +#define DA7213_HP_L_CTRL 0x6B +#define DA7213_HP_R_CTRL 0x6C +#define DA7213_LINE_CTRL 0x6D +#define DA7213_MIXOUT_L_CTRL 0x6E +#define DA7213_MIXOUT_R_CTRL 0x6F + +/* Configuration Registers */ +#define DA7213_LDO_CTRL 0x90 +#define DA7213_IO_CTRL 0x91 +#define DA7213_GAIN_RAMP_CTRL 0x92 +#define DA7213_MIC_CONFIG 0x93 +#define DA7213_PC_COUNT 0x94 +#define DA7213_CP_VOL_THRESHOLD1 0x95 +#define DA7213_CP_DELAY 0x96 +#define DA7213_CP_DETECTOR 0x97 +#define DA7213_DAI_OFFSET 0x98 +#define DA7213_DIG_CTRL 0x99 +#define DA7213_ALC_CTRL2 0x9A +#define DA7213_ALC_CTRL3 0x9B +#define DA7213_ALC_NOISE 0x9C +#define DA7213_ALC_TARGET_MIN 0x9D +#define DA7213_ALC_TARGET_MAX 0x9E +#define DA7213_ALC_GAIN_LIMITS 0x9F +#define DA7213_ALC_ANA_GAIN_LIMITS 0xA0 +#define DA7213_ALC_ANTICLIP_CTRL 0xA1 +#define DA7213_ALC_ANTICLIP_LEVEL 0xA2 + +#define DA7213_ALC_OFFSET_AUTO_M_L 0xA3 +#define DA7213_ALC_OFFSET_AUTO_U_L 0xA4 +#define DA7213_ALC_OFFSET_MAN_M_L 0xA6 +#define DA7213_ALC_OFFSET_MAN_U_L 0xA7 +#define DA7213_ALC_OFFSET_AUTO_M_R 0xA8 +#define DA7213_ALC_OFFSET_AUTO_U_R 0xA9 +#define DA7213_ALC_OFFSET_MAN_M_R 0xAB +#define DA7213_ALC_OFFSET_MAN_U_R 0xAC +#define DA7213_ALC_CIC_OP_LVL_CTRL 0xAD +#define DA7213_ALC_CIC_OP_LVL_DATA 0xAE +#define DA7213_DAC_NG_SETUP_TIME 0xAF +#define DA7213_DAC_NG_OFF_THRESHOLD 0xB0 +#define DA7213_DAC_NG_ON_THRESHOLD 0xB1 +#define DA7213_DAC_NG_CTRL 0xB2 + + +/* + * Bit fields + */ + +/* DA7213_SR = 0x22 */ +#define DA7213_SR_8000 (0x1 << 0) +#define DA7213_SR_11025 (0x2 << 0) +#define DA7213_SR_12000 (0x3 << 0) +#define DA7213_SR_16000 (0x5 << 0) +#define DA7213_SR_22050 (0x6 << 0) +#define DA7213_SR_24000 (0x7 << 0) +#define DA7213_SR_32000 (0x9 << 0) +#define DA7213_SR_44100 (0xA << 0) +#define DA7213_SR_48000 (0xB << 0) +#define DA7213_SR_88200 (0xE << 0) +#define DA7213_SR_96000 (0xF << 0) + +/* DA7213_REFERENCES = 0x23 */ +#define DA7213_BIAS_EN (0x1 << 3) +#define DA7213_VMID_EN (0x1 << 7) + +/* DA7213_PLL_CTRL = 0x27 */ +#define DA7213_PLL_INDIV_5_10_MHZ (0x0 << 2) +#define DA7213_PLL_INDIV_10_20_MHZ (0x1 << 2) +#define DA7213_PLL_INDIV_20_40_MHZ (0x2 << 2) +#define DA7213_PLL_INDIV_40_54_MHZ (0x3 << 2) +#define DA7213_PLL_INDIV_MASK (0x3 << 2) +#define DA7213_PLL_MCLK_SQR_EN (0x1 << 4) +#define DA7213_PLL_32K_MODE (0x1 << 5) +#define DA7213_PLL_SRM_EN (0x1 << 6) +#define DA7213_PLL_EN (0x1 << 7) + +/* DA7213_DAI_CLK_MODE = 0x28 */ +#define DA7213_DAI_BCLKS_PER_WCLK_32 (0x0 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_64 (0x1 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_128 (0x2 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0) +#define DA7213_DAI_CLK_POL_INV (0x1 << 2) +#define DA7213_DAI_WCLK_POL_INV (0x1 << 3) +#define DA7213_DAI_CLK_EN_SLAVE_MODE (0x0 << 7) +#define DA7213_DAI_CLK_EN_MASTER_MODE (0x1 << 7) +#define DA7213_DAI_CLK_EN_MASK (0x1 << 7) + +/* DA7213_DAI_CTRL = 0x29 */ +#define DA7213_DAI_FORMAT_I2S_MODE (0x0 << 0) +#define DA7213_DAI_FORMAT_LEFT_J (0x1 << 0) +#define DA7213_DAI_FORMAT_RIGHT_J (0x2 << 0) +#define DA7213_DAI_FORMAT_MASK (0x3 << 0) +#define DA7213_DAI_WORD_LENGTH_S16_LE (0x0 << 2) +#define DA7213_DAI_WORD_LENGTH_S20_LE (0x1 << 2) +#define DA7213_DAI_WORD_LENGTH_S24_LE (0x2 << 2) +#define DA7213_DAI_WORD_LENGTH_S32_LE (0x3 << 2) +#define DA7213_DAI_WORD_LENGTH_MASK (0x3 << 2) +#define DA7213_DAI_EN_SHIFT 7 + +/* DA7213_DIG_ROUTING_DAI = 0x21 */ +#define DA7213_DAI_L_SRC_SHIFT 0 +#define DA7213_DAI_R_SRC_SHIFT 4 +#define DA7213_DAI_SRC_MAX 4 + +/* DA7213_DIG_ROUTING_DAC = 0x2A */ +#define DA7213_DAC_L_SRC_SHIFT 0 +#define DA7213_DAC_L_MONO_SHIFT 3 +#define DA7213_DAC_R_SRC_SHIFT 4 +#define DA7213_DAC_R_MONO_SHIFT 7 +#define DA7213_DAC_SRC_MAX 4 +#define DA7213_DAC_MONO_MAX 0x1 + +/* DA7213_ALC_CTRL1 = 0x2B */ +#define DA7213_ALC_OFFSET_EN_SHIFT 0 +#define DA7213_ALC_OFFSET_EN_MAX 0x1 +#define DA7213_ALC_OFFSET_EN (0x1 << 0) +#define DA7213_ALC_SYNC_MODE (0x1 << 1) +#define DA7213_ALC_CALIB_MODE_MAN (0x1 << 2) +#define DA7213_ALC_L_EN_SHIFT 3 +#define DA7213_ALC_AUTO_CALIB_EN (0x1 << 4) +#define DA7213_ALC_CALIB_OVERFLOW (0x1 << 5) +#define DA7213_ALC_R_EN_SHIFT 7 +#define DA7213_ALC_EN_MAX 0x1 + +/* DA7213_AUX_L/R_GAIN = 0x30/0x31 */ +#define DA7213_AUX_AMP_GAIN_SHIFT 0 +#define DA7213_AUX_AMP_GAIN_MAX 0x3F + +/* DA7213_MIXIN_L/R_SELECT = 0x32/0x33 */ +#define DA7213_DMIC_EN_SHIFT 7 +#define DA7213_DMIC_EN_MAX 0x1 + +/* DA7213_MIXIN_L_SELECT = 0x32 */ +#define DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT 0 +#define DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT 1 +#define DA7213_MIXIN_L_MIX_SELECT_MIC_1 (0x1 << 1) +#define DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT 2 +#define DA7213_MIXIN_L_MIX_SELECT_MIC_2 (0x1 << 2) +#define DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT 3 +#define DA7213_MIXIN_L_MIX_SELECT_MAX 0x1 + +/* DA7213_MIXIN_R_SELECT = 0x33 */ +#define DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT 0 +#define DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT 1 +#define DA7213_MIXIN_R_MIX_SELECT_MIC_2 (0x1 << 1) +#define DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT 2 +#define DA7213_MIXIN_R_MIX_SELECT_MIC_1 (0x1 << 2) +#define DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT 3 +#define DA7213_MIXIN_R_MIX_SELECT_MAX 0x1 +#define DA7213_MIC_BIAS_OUTPUT_SELECT_2 (0x1 << 6) + +/* DA7213_MIXIN_L/R_GAIN = 0x34/0x35 */ +#define DA7213_MIXIN_AMP_GAIN_SHIFT 0 +#define DA7213_MIXIN_AMP_GAIN_MAX 0xF + +/* DA7213_ADC_L/R_GAIN = 0x36/0x37 */ +#define DA7213_ADC_AMP_GAIN_SHIFT 0 +#define DA7213_ADC_AMP_GAIN_MAX 0x7F + +/* DA7213_ADC/DAC_FILTERS1 = 0x38/0x44 */ +#define DA7213_VOICE_HPF_CORNER_SHIFT 0 +#define DA7213_VOICE_HPF_CORNER_MAX 8 +#define DA7213_VOICE_EN_SHIFT 3 +#define DA7213_VOICE_EN_MAX 0x1 +#define DA7213_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7213_AUDIO_HPF_CORNER_MAX 4 +#define DA7213_HPF_EN_SHIFT 7 +#define DA7213_HPF_EN_MAX 0x1 + +/* DA7213_MIC_1/2_GAIN = 0x39/0x3A */ +#define DA7213_MIC_AMP_GAIN_SHIFT 0 +#define DA7213_MIC_AMP_GAIN_MAX 0x7 + +/* DA7213_DAC_FILTERS5 = 0x40 */ +#define DA7213_DAC_SOFTMUTE_EN_SHIFT 7 +#define DA7213_DAC_SOFTMUTE_EN_MAX 0x1 +#define DA7213_DAC_SOFTMUTE_RATE_SHIFT 4 +#define DA7213_DAC_SOFTMUTE_RATE_MAX 7 + +/* DA7213_DAC_FILTERS2/3/4 = 0x41/0x42/0x43 */ +#define DA7213_DAC_EQ_BAND_MAX 0xF + +/* DA7213_DAC_FILTERS2 = 0x41 */ +#define DA7213_DAC_EQ_BAND1_SHIFT 0 +#define DA7213_DAC_EQ_BAND2_SHIFT 4 + +/* DA7213_DAC_FILTERS2 = 0x42 */ +#define DA7213_DAC_EQ_BAND3_SHIFT 0 +#define DA7213_DAC_EQ_BAND4_SHIFT 4 + +/* DA7213_DAC_FILTERS4 = 0x43 */ +#define DA7213_DAC_EQ_BAND5_SHIFT 0 +#define DA7213_DAC_EQ_EN_SHIFT 7 +#define DA7213_DAC_EQ_EN_MAX 0x1 + +/* DA7213_DAC_L/R_GAIN = 0x45/0x46 */ +#define DA7213_DAC_AMP_GAIN_SHIFT 0 +#define DA7213_DAC_AMP_GAIN_MAX 0x7F + +/* DA7213_HP_L/R_GAIN = 0x45/0x46 */ +#define DA7213_HP_AMP_GAIN_SHIFT 0 +#define DA7213_HP_AMP_GAIN_MAX 0x3F + +/* DA7213_CP_CTRL = 0x47 */ +#define DA7213_CP_EN_SHIFT 7 + +/* DA7213_LINE_GAIN = 0x4A */ +#define DA7213_LINE_AMP_GAIN_SHIFT 0 +#define DA7213_LINE_AMP_GAIN_MAX 0x3F + +/* DA7213_MIXOUT_L_SELECT = 0x4B */ +#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT 0 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT 1 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT 2 +#define DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT 3 +#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT 4 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 5 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 6 +#define DA7213_MIXOUT_L_MIX_SELECT_MAX 0x1 + +/* DA7213_MIXOUT_R_SELECT = 0x4C */ +#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT 0 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT 1 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT 2 +#define DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT 3 +#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT 4 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 5 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 6 +#define DA7213_MIXOUT_R_MIX_SELECT_MAX 0x1 + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIC_1/2_CTRL = 0x63/0x64, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_ADC_L/R_CTRL = 0x65/0x66, + * DA7213_DAC_L/R_CTRL = 0x69/0x6A, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_MUTE_EN_SHIFT 6 +#define DA7213_MUTE_EN_MAX 0x1 +#define DA7213_MUTE_EN (0x1 << 6) + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_ADC_L/R_CTRL = 0x65/0x66, + * DA7213_DAC_L/R_CTRL = 0x69/0x6A, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_GAIN_RAMP_EN_SHIFT 5 +#define DA7213_GAIN_RAMP_EN_MAX 0x1 +#define DA7213_GAIN_RAMP_EN (0x1 << 5) + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_ZC_EN_SHIFT 4 +#define DA7213_ZC_EN_MAX 0x1 + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIC_1/2_CTRL = 0x63/0x64, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_AMP_EN_SHIFT 7 + +/* DA7213_MIC_1/2_CTRL = 0x63/0x64 */ +#define DA7213_MIC_AMP_IN_SEL_SHIFT 2 +#define DA7213_MIC_AMP_IN_SEL_MAX 3 + +/* DA7213_MICBIAS_CTRL = 0x62 */ +#define DA7213_MICBIAS1_LEVEL_SHIFT 0 +#define DA7213_MICBIAS1_LEVEL_MASK (0x3 << 0) +#define DA7213_MICBIAS1_EN_SHIFT 3 +#define DA7213_MICBIAS2_LEVEL_SHIFT 4 +#define DA7213_MICBIAS2_LEVEL_MASK (0x3 << 4) +#define DA7213_MICBIAS2_EN_SHIFT 7 + +/* DA7213_MIXIN_L/R_CTRL = 0x65/0x66 */ +#define DA7213_MIXIN_MIX_EN (0x1 << 3) + +/* DA7213_ADC_L/R_CTRL = 0x67/0x68 */ +#define DA7213_ADC_EN_SHIFT 7 +#define DA7213_ADC_EN (0x1 << 7) + +/* DA7213_DAC_L/R_CTRL = 0x69/0x6A*/ +#define DA7213_DAC_EN_SHIFT 7 + +/* DA7213_HP_L/R_CTRL = 0x6B/0x6C */ +#define DA7213_HP_AMP_OE (0x1 << 3) + +/* DA7213_LINE_CTRL = 0x6D */ +#define DA7213_LINE_AMP_OE (0x1 << 3) + +/* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F */ +#define DA7213_MIXOUT_MIX_EN (0x1 << 3) + +/* DA7213_GAIN_RAMP_CTRL = 0x92 */ +#define DA7213_GAIN_RAMP_RATE_SHIFT 0 +#define DA7213_GAIN_RAMP_RATE_MAX 4 + +/* DA7213_MIC_CONFIG = 0x93 */ +#define DA7213_DMIC_DATA_SEL_SHIFT 0 +#define DA7213_DMIC_DATA_SEL_MASK (0x1 << 0) +#define DA7213_DMIC_SAMPLEPHASE_SHIFT 1 +#define DA7213_DMIC_SAMPLEPHASE_MASK (0x1 << 1) +#define DA7213_DMIC_CLK_RATE_SHIFT 2 +#define DA7213_DMIC_CLK_RATE_MASK (0x1 << 2) + +/* DA7213_DIG_CTRL = 0x99 */ +#define DA7213_DAC_L_INV_SHIFT 3 +#define DA7213_DAC_R_INV_SHIFT 7 +#define DA7213_DAC_INV_MAX 0x1 + +/* DA7213_ALC_CTRL2 = 0x9A */ +#define DA7213_ALC_ATTACK_SHIFT 0 +#define DA7213_ALC_ATTACK_MAX 13 +#define DA7213_ALC_RELEASE_SHIFT 4 +#define DA7213_ALC_RELEASE_MAX 11 + +/* DA7213_ALC_CTRL3 = 0x9B */ +#define DA7213_ALC_HOLD_SHIFT 0 +#define DA7213_ALC_HOLD_MAX 16 +#define DA7213_ALC_INTEG_ATTACK_SHIFT 4 +#define DA7213_ALC_INTEG_RELEASE_SHIFT 6 +#define DA7213_ALC_INTEG_MAX 4 + +/* + * DA7213_ALC_NOISE = 0x9C, + * DA7213_ALC_TARGET_MIN/MAX = 0x9D/0x9E + */ +#define DA7213_ALC_THRESHOLD_SHIFT 0 +#define DA7213_ALC_THRESHOLD_MAX 0x3F + +/* DA7213_ALC_GAIN_LIMITS = 0x9F */ +#define DA7213_ALC_ATTEN_MAX_SHIFT 0 +#define DA7213_ALC_GAIN_MAX_SHIFT 4 +#define DA7213_ALC_ATTEN_GAIN_MAX_MAX 0xF + +/* DA7213_ALC_ANA_GAIN_LIMITS = 0xA0 */ +#define DA7213_ALC_ANA_GAIN_MIN_SHIFT 0 +#define DA7213_ALC_ANA_GAIN_MAX_SHIFT 4 +#define DA7213_ALC_ANA_GAIN_MAX 0x7 + +/* DA7213_ALC_ANTICLIP_CTRL = 0xA1 */ +#define DA7213_ALC_ANTICLIP_EN_SHIFT 7 +#define DA7213_ALC_ANTICLIP_EN_MAX 0x1 + +/* DA7213_ALC_ANTICLIP_LEVEL = 0xA2 */ +#define DA7213_ALC_ANTICLIP_LEVEL_SHIFT 0 +#define DA7213_ALC_ANTICLIP_LEVEL_MAX 0x7F + +/* DA7213_ALC_CIC_OP_LVL_CTRL = 0xAD */ +#define DA7213_ALC_DATA_MIDDLE (0x2 << 0) +#define DA7213_ALC_DATA_TOP (0x3 << 0) +#define DA7213_ALC_CIC_OP_CHANNEL_LEFT (0x0 << 7) +#define DA7213_ALC_CIC_OP_CHANNEL_RIGHT (0x1 << 7) + +/* DA7213_DAC_NG_SETUP_TIME = 0xAF */ +#define DA7213_DAC_NG_SETUP_TIME_SHIFT 0 +#define DA7213_DAC_NG_SETUP_TIME_MAX 4 +#define DA7213_DAC_NG_RAMPUP_RATE_SHIFT 2 +#define DA7213_DAC_NG_RAMPDN_RATE_SHIFT 3 +#define DA7213_DAC_NG_RAMP_RATE_MAX 2 + +/* DA7213_DAC_NG_OFF/ON_THRESH = 0xB0/0xB1 */ +#define DA7213_DAC_NG_THRESHOLD_SHIFT 0 +#define DA7213_DAC_NG_THRESHOLD_MAX 0x7 + +/* DA7213_DAC_NG_CTRL = 0xB2 */ +#define DA7213_DAC_NG_EN_SHIFT 7 +#define DA7213_DAC_NG_EN_MAX 0x1 + + +/* + * General defines + */ + +/* Register inversion */ +#define DA7213_NO_INVERT 0 +#define DA7213_INVERT 1 + +/* Byte related defines */ +#define DA7213_BYTE_SHIFT 8 +#define DA7213_BYTE_MASK 0xFF + +/* ALC related */ +#define DA7213_ALC_OFFSET_15_8 0x00FF00 +#define DA7213_ALC_OFFSET_19_16 0x0F0000 +#define DA7213_ALC_AVG_ITERATIONS 5 + +/* PLL related */ +#define DA7213_SYSCLK_MCLK 0 +#define DA7213_SYSCLK_PLL 1 +#define DA7213_PLL_FREQ_OUT_90316800 90316800 +#define DA7213_PLL_FREQ_OUT_98304000 98304000 +#define DA7213_PLL_FREQ_OUT_94310400 94310400 +#define DA7213_PLL_INDIV_5_10_MHZ_VAL 2 +#define DA7213_PLL_INDIV_10_20_MHZ_VAL 4 +#define DA7213_PLL_INDIV_20_40_MHZ_VAL 8 +#define DA7213_PLL_INDIV_40_54_MHZ_VAL 16 + +enum clk_src { + DA7213_CLKSRC_MCLK +}; + +/* Codec private data */ +struct da7213_priv { + struct regmap *regmap; + unsigned int mclk_rate; + bool master; + bool mclk_squarer_en; + bool srm_en; + bool alc_calib_auto; + bool alc_en; + struct da7213_platform_data *pdata; +}; + +#endif /* _DA7213_H */ diff --git a/trunk/sound/soc/codecs/max98090.c b/trunk/sound/soc/codecs/max98090.c old mode 100755 new mode 100644 index fc176044994d..c9772ca3da4f --- a/trunk/sound/soc/codecs/max98090.c +++ b/trunk/sound/soc/codecs/max98090.c @@ -1,2381 +1,562 @@ /* * max98090.c -- MAX98090 ALSA SoC Audio driver + * based on Rev0p8 datasheet * - * Copyright 2011-2012 Maxim Integrated Products + * Copyright (C) 2012 Renesas Solutions Corp. + * Kuninori Morimoto + * + * 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 #include #include -#include -#include #include -#include -#include -#include -#include #include #include -#include -#include "max98090.h" - -#include - -#define DEBUG -#define EXTMIC_METHOD -#define EXTMIC_METHOD_TEST - -/* Allows for sparsely populated register maps */ -static struct reg_default max98090_reg[] = { - { 0x00, 0x00 }, /* 00 Software Reset */ - { 0x03, 0x04 }, /* 03 Interrupt Masks */ - { 0x04, 0x00 }, /* 04 System Clock Quick */ - { 0x05, 0x00 }, /* 05 Sample Rate Quick */ - { 0x06, 0x00 }, /* 06 DAI Interface Quick */ - { 0x07, 0x00 }, /* 07 DAC Path Quick */ - { 0x08, 0x00 }, /* 08 Mic/Direct to ADC Quick */ - { 0x09, 0x00 }, /* 09 Line to ADC Quick */ - { 0x0A, 0x00 }, /* 0A Analog Mic Loop Quick */ - { 0x0B, 0x00 }, /* 0B Analog Line Loop Quick */ - { 0x0C, 0x00 }, /* 0C Reserved */ - { 0x0D, 0x00 }, /* 0D Input Config */ - { 0x0E, 0x1B }, /* 0E Line Input Level */ - { 0x0F, 0x00 }, /* 0F Line Config */ - - { 0x10, 0x14 }, /* 10 Mic1 Input Level */ - { 0x11, 0x14 }, /* 11 Mic2 Input Level */ - { 0x12, 0x00 }, /* 12 Mic Bias Voltage */ - { 0x13, 0x00 }, /* 13 Digital Mic Config */ - { 0x14, 0x00 }, /* 14 Digital Mic Mode */ - { 0x15, 0x00 }, /* 15 Left ADC Mixer */ - { 0x16, 0x00 }, /* 16 Right ADC Mixer */ - { 0x17, 0x03 }, /* 17 Left ADC Level */ - { 0x18, 0x03 }, /* 18 Right ADC Level */ - { 0x19, 0x00 }, /* 19 ADC Biquad Level */ - { 0x1A, 0x00 }, /* 1A ADC Sidetone */ - { 0x1B, 0x00 }, /* 1B System Clock */ - { 0x1C, 0x00 }, /* 1C Clock Mode */ - { 0x1D, 0x00 }, /* 1D Any Clock 1 */ - { 0x1E, 0x00 }, /* 1E Any Clock 2 */ - { 0x1F, 0x00 }, /* 1F Any Clock 3 */ - - { 0x20, 0x00 }, /* 20 Any Clock 4 */ - { 0x21, 0x00 }, /* 21 Master Mode */ - { 0x22, 0x00 }, /* 22 Interface Format */ - { 0x23, 0x00 }, /* 23 TDM Format 1*/ - { 0x24, 0x00 }, /* 24 TDM Format 2*/ - { 0x25, 0x00 }, /* 25 I/O Configuration */ - { 0x26, 0x80 }, /* 26 Filter Config */ - { 0x27, 0x00 }, /* 27 DAI Playback Level */ - { 0x28, 0x00 }, /* 28 EQ Playback Level */ - { 0x29, 0x00 }, /* 29 Left HP Mixer */ - { 0x2A, 0x00 }, /* 2A Right HP Mixer */ - { 0x2B, 0x00 }, /* 2B HP Control */ - { 0x2C, 0x1A }, /* 2C Left HP Volume */ - { 0x2D, 0x1A }, /* 2D Right HP Volume */ - { 0x2E, 0x00 }, /* 2E Left Spk Mixer */ - { 0x2F, 0x00 }, /* 2F Right Spk Mixer */ - - { 0x30, 0x00 }, /* 30 Spk Control */ - { 0x31, 0x2C }, /* 31 Left Spk Volume */ - { 0x32, 0x2C }, /* 32 Right Spk Volume */ - { 0x33, 0x00 }, /* 33 ALC Timing */ - { 0x34, 0x00 }, /* 34 ALC Compressor */ - { 0x35, 0x00 }, /* 35 ALC Expander */ - { 0x36, 0x00 }, /* 36 ALC Gain */ - { 0x37, 0x00 }, /* 37 Rcv/Line OutL Mixer */ - { 0x38, 0x00 }, /* 38 Rcv/Line OutL Control */ - { 0x39, 0x15 }, /* 39 Rcv/Line OutL Volume */ - { 0x3A, 0x00 }, /* 3A Line OutR Mixer */ - { 0x3B, 0x00 }, /* 3B Line OutR Control */ - { 0x3C, 0x15 }, /* 3C Line OutR Volume */ - { 0x3D, 0x00 }, /* 3D Jack Detect */ - { 0x3E, 0x00 }, /* 3E Input Enable */ - { 0x3F, 0x00 }, /* 3F Output Enable */ - - { 0x40, 0x00 }, /* 40 Level Control */ - { 0x41, 0x00 }, /* 41 DSP Filter Enable */ - { 0x42, 0x00 }, /* 42 Bias Control */ - { 0x43, 0x00 }, /* 43 DAC Control */ - { 0x44, 0x06 }, /* 44 ADC Control */ - { 0x45, 0x00 }, /* 45 Device Shutdown */ - { 0x46, 0x00 }, /* 46 Equalizer Band 1 Coefficient B0 */ - { 0x47, 0x00 }, /* 47 Equalizer Band 1 Coefficient B0 */ - { 0x48, 0x00 }, /* 48 Equalizer Band 1 Coefficient B0 */ - { 0x49, 0x00 }, /* 49 Equalizer Band 1 Coefficient B1 */ - { 0x4A, 0x00 }, /* 4A Equalizer Band 1 Coefficient B1 */ - { 0x4B, 0x00 }, /* 4B Equalizer Band 1 Coefficient B1 */ - { 0x4C, 0x00 }, /* 4C Equalizer Band 1 Coefficient B2 */ - { 0x4D, 0x00 }, /* 4D Equalizer Band 1 Coefficient B2 */ - { 0x4E, 0x00 }, /* 4E Equalizer Band 1 Coefficient B2 */ - { 0x4F, 0x00 }, /* 4F Equalizer Band 1 Coefficient A1 */ - - { 0x50, 0x00 }, /* 50 Equalizer Band 1 Coefficient A1 */ - { 0x51, 0x00 }, /* 51 Equalizer Band 1 Coefficient A1 */ - { 0x52, 0x00 }, /* 52 Equalizer Band 1 Coefficient A2 */ - { 0x53, 0x00 }, /* 53 Equalizer Band 1 Coefficient A2 */ - { 0x54, 0x00 }, /* 54 Equalizer Band 1 Coefficient A2 */ - { 0x55, 0x00 }, /* 55 Equalizer Band 2 Coefficient B0 */ - { 0x56, 0x00 }, /* 56 Equalizer Band 2 Coefficient B0 */ - { 0x57, 0x00 }, /* 57 Equalizer Band 2 Coefficient B0 */ - { 0x58, 0x00 }, /* 58 Equalizer Band 2 Coefficient B1 */ - { 0x59, 0x00 }, /* 59 Equalizer Band 2 Coefficient B1 */ - { 0x5A, 0x00 }, /* 5A Equalizer Band 2 Coefficient B1 */ - { 0x5B, 0x00 }, /* 5B Equalizer Band 2 Coefficient B2 */ - { 0x5C, 0x00 }, /* 5C Equalizer Band 2 Coefficient B2 */ - { 0x5D, 0x00 }, /* 5D Equalizer Band 2 Coefficient B2 */ - { 0x5E, 0x00 }, /* 5E Equalizer Band 2 Coefficient A1 */ - { 0x5F, 0x00 }, /* 5F Equalizer Band 2 Coefficient A1 */ - - { 0x60, 0x00 }, /* 60 Equalizer Band 2 Coefficient A1 */ - { 0x61, 0x00 }, /* 61 Equalizer Band 2 Coefficient A2 */ - { 0x62, 0x00 }, /* 62 Equalizer Band 2 Coefficient A2 */ - { 0x63, 0x00 }, /* 63 Equalizer Band 2 Coefficient A2 */ - { 0x64, 0x00 }, /* 64 Equalizer Band 3 Coefficient B0 */ - { 0x65, 0x00 }, /* 65 Equalizer Band 3 Coefficient B0 */ - { 0x66, 0x00 }, /* 66 Equalizer Band 3 Coefficient B0 */ - { 0x67, 0x00 }, /* 67 Equalizer Band 3 Coefficient B1 */ - { 0x68, 0x00 }, /* 68 Equalizer Band 3 Coefficient B1 */ - { 0x69, 0x00 }, /* 69 Equalizer Band 3 Coefficient B1 */ - { 0x6A, 0x00 }, /* 6A Equalizer Band 3 Coefficient B2 */ - { 0x6B, 0x00 }, /* 6B Equalizer Band 3 Coefficient B2 */ - { 0x6C, 0x00 }, /* 6C Equalizer Band 3 Coefficient B2 */ - { 0x6D, 0x00 }, /* 6D Equalizer Band 3 Coefficient A1 */ - { 0x6E, 0x00 }, /* 6E Equalizer Band 3 Coefficient A1 */ - { 0x6F, 0x00 }, /* 6F Equalizer Band 3 Coefficient A1 */ - - { 0x70, 0x00 }, /* 70 Equalizer Band 3 Coefficient A2 */ - { 0x71, 0x00 }, /* 71 Equalizer Band 3 Coefficient A2 */ - { 0x72, 0x00 }, /* 72 Equalizer Band 3 Coefficient A2 */ - { 0x73, 0x00 }, /* 73 Equalizer Band 4 Coefficient B0 */ - { 0x74, 0x00 }, /* 74 Equalizer Band 4 Coefficient B0 */ - { 0x75, 0x00 }, /* 75 Equalizer Band 4 Coefficient B0 */ - { 0x76, 0x00 }, /* 76 Equalizer Band 4 Coefficient B1 */ - { 0x77, 0x00 }, /* 77 Equalizer Band 4 Coefficient B1 */ - { 0x78, 0x00 }, /* 78 Equalizer Band 4 Coefficient B1 */ - { 0x79, 0x00 }, /* 79 Equalizer Band 4 Coefficient B2 */ - { 0x7A, 0x00 }, /* 7A Equalizer Band 4 Coefficient B2 */ - { 0x7B, 0x00 }, /* 7B Equalizer Band 4 Coefficient B2 */ - { 0x7C, 0x00 }, /* 7C Equalizer Band 4 Coefficient A1 */ - { 0x7D, 0x00 }, /* 7D Equalizer Band 4 Coefficient A1 */ - { 0x7E, 0x00 }, /* 7E Equalizer Band 4 Coefficient A1 */ - { 0x7F, 0x00 }, /* 7F Equalizer Band 4 Coefficient A2 */ - - { 0x80, 0x00 }, /* 80 Equalizer Band 4 Coefficient A2 */ - { 0x81, 0x00 }, /* 81 Equalizer Band 4 Coefficient A2 */ - { 0x82, 0x00 }, /* 82 Equalizer Band 5 Coefficient B0 */ - { 0x83, 0x00 }, /* 83 Equalizer Band 5 Coefficient B0 */ - { 0x84, 0x00 }, /* 84 Equalizer Band 5 Coefficient B0 */ - { 0x85, 0x00 }, /* 85 Equalizer Band 5 Coefficient B1 */ - { 0x86, 0x00 }, /* 86 Equalizer Band 5 Coefficient B1 */ - { 0x87, 0x00 }, /* 87 Equalizer Band 5 Coefficient B1 */ - { 0x88, 0x00 }, /* 88 Equalizer Band 5 Coefficient B2 */ - { 0x89, 0x00 }, /* 89 Equalizer Band 5 Coefficient B2 */ - { 0x8A, 0x00 }, /* 8A Equalizer Band 5 Coefficient B2 */ - { 0x8B, 0x00 }, /* 8B Equalizer Band 5 Coefficient A1 */ - { 0x8C, 0x00 }, /* 8C Equalizer Band 5 Coefficient A1 */ - { 0x8D, 0x00 }, /* 8D Equalizer Band 5 Coefficient A1 */ - { 0x8E, 0x00 }, /* 8E Equalizer Band 5 Coefficient A2 */ - { 0x8F, 0x00 }, /* 8F Equalizer Band 5 Coefficient A2 */ - - { 0x90, 0x00 }, /* 90 Equalizer Band 5 Coefficient A2 */ - { 0x91, 0x00 }, /* 91 Equalizer Band 6 Coefficient B0 */ - { 0x92, 0x00 }, /* 92 Equalizer Band 6 Coefficient B0 */ - { 0x93, 0x00 }, /* 93 Equalizer Band 6 Coefficient B0 */ - { 0x94, 0x00 }, /* 94 Equalizer Band 6 Coefficient B1 */ - { 0x95, 0x00 }, /* 95 Equalizer Band 6 Coefficient B1 */ - { 0x96, 0x00 }, /* 96 Equalizer Band 6 Coefficient B1 */ - { 0x97, 0x00 }, /* 97 Equalizer Band 6 Coefficient B2 */ - { 0x98, 0x00 }, /* 98 Equalizer Band 6 Coefficient B2 */ - { 0x99, 0x00 }, /* 99 Equalizer Band 6 Coefficient B2 */ - { 0x9A, 0x00 }, /* 9A Equalizer Band 6 Coefficient A1 */ - { 0x9B, 0x00 }, /* 9B Equalizer Band 6 Coefficient A1 */ - { 0x9C, 0x00 }, /* 9C Equalizer Band 6 Coefficient A1 */ - { 0x9D, 0x00 }, /* 9D Equalizer Band 6 Coefficient A2 */ - { 0x9E, 0x00 }, /* 9E Equalizer Band 6 Coefficient A2 */ - { 0x9F, 0x00 }, /* 9F Equalizer Band 6 Coefficient A2 */ - - { 0xA0, 0x00 }, /* A0 Equalizer Band 7 Coefficient B0 */ - { 0xA1, 0x00 }, /* A1 Equalizer Band 7 Coefficient B0 */ - { 0xA2, 0x00 }, /* A2 Equalizer Band 7 Coefficient B0 */ - { 0xA3, 0x00 }, /* A3 Equalizer Band 7 Coefficient B1 */ - { 0xA4, 0x00 }, /* A4 Equalizer Band 7 Coefficient B1 */ - { 0xA5, 0x00 }, /* A5 Equalizer Band 7 Coefficient B1 */ - { 0xA6, 0x00 }, /* A6 Equalizer Band 7 Coefficient B2 */ - { 0xA7, 0x00 }, /* A7 Equalizer Band 7 Coefficient B2 */ - { 0xA8, 0x00 }, /* A8 Equalizer Band 7 Coefficient B2 */ - { 0xA9, 0x00 }, /* A9 Equalizer Band 7 Coefficient A1 */ - { 0xAA, 0x00 }, /* AA Equalizer Band 7 Coefficient A1 */ - { 0xAB, 0x00 }, /* AB Equalizer Band 7 Coefficient A1 */ - { 0xAC, 0x00 }, /* AC Equalizer Band 7 Coefficient A2 */ - { 0xAD, 0x00 }, /* AD Equalizer Band 7 Coefficient A2 */ - { 0xAE, 0x00 }, /* AE Equalizer Band 7 Coefficient A2 */ - { 0xAF, 0x00 }, /* AF ADC Biquad Coefficient B0 */ - - { 0xB0, 0x00 }, /* B0 ADC Biquad Coefficient B0 */ - { 0xB1, 0x00 }, /* B1 ADC Biquad Coefficient B0 */ - { 0xB2, 0x00 }, /* B2 ADC Biquad Coefficient B1 */ - { 0xB3, 0x00 }, /* B3 ADC Biquad Coefficient B1 */ - { 0xB4, 0x00 }, /* B4 ADC Biquad Coefficient B1 */ - { 0xB5, 0x00 }, /* B5 ADC Biquad Coefficient B2 */ - { 0xB6, 0x00 }, /* B6 ADC Biquad Coefficient B2 */ - { 0xB7, 0x00 }, /* B7 ADC Biquad Coefficient B2 */ - { 0xB8, 0x00 }, /* B8 ADC Biquad Coefficient A1 */ - { 0xB9, 0x00 }, /* B9 ADC Biquad Coefficient A1 */ - { 0xBA, 0x00 }, /* BA ADC Biquad Coefficient A1 */ - { 0xBB, 0x00 }, /* BB ADC Biquad Coefficient A2 */ - { 0xBC, 0x00 }, /* BC ADC Biquad Coefficient A2 */ - { 0xBD, 0x00 }, /* BD ADC Biquad Coefficient A2 */ - { 0xBE, 0x00 }, /* BE Digital Mic 3 Volume */ - { 0xBF, 0x00 }, /* BF Digital Mic 4 Volume */ - - { 0xC0, 0x00 }, /* C0 Digital Mic 34 Biquad Pre Atten */ - { 0xC1, 0x00 }, /* C1 Record TDM Slot */ - { 0xC2, 0x00 }, /* C2 Sample Rate */ - { 0xC3, 0x00 }, /* C3 Digital Mic 34 Biquad Coefficient C3 */ - { 0xC4, 0x00 }, /* C4 Digital Mic 34 Biquad Coefficient C4 */ - { 0xC5, 0x00 }, /* C5 Digital Mic 34 Biquad Coefficient C5 */ - { 0xC6, 0x00 }, /* C6 Digital Mic 34 Biquad Coefficient C6 */ - { 0xC7, 0x00 }, /* C7 Digital Mic 34 Biquad Coefficient C7 */ - { 0xC8, 0x00 }, /* C8 Digital Mic 34 Biquad Coefficient C8 */ - { 0xC9, 0x00 }, /* C9 Digital Mic 34 Biquad Coefficient C9 */ - { 0xCA, 0x00 }, /* CA Digital Mic 34 Biquad Coefficient CA */ - { 0xCB, 0x00 }, /* CB Digital Mic 34 Biquad Coefficient CB */ - { 0xCC, 0x00 }, /* CC Digital Mic 34 Biquad Coefficient CC */ - { 0xCD, 0x00 }, /* CD Digital Mic 34 Biquad Coefficient CD */ - { 0xCE, 0x00 }, /* CE Digital Mic 34 Biquad Coefficient CE */ - { 0xCF, 0x00 }, /* CF Digital Mic 34 Biquad Coefficient CF */ - - { 0xD0, 0x00 }, /* D0 Digital Mic 34 Biquad Coefficient D0 */ - { 0xD1, 0x00 }, /* D1 Digital Mic 34 Biquad Coefficient D1 */ -}; - -static bool max98090_volatile_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case M98090_REG_DEVICE_STATUS: - case M98090_REG_JACK_STATUS: - case M98090_REG_REVISION_ID: - return true; - default: - return false; - } -} -static bool max98090_readable_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case M98090_REG_DEVICE_STATUS: - case M98090_REG_JACK_STATUS: - case M98090_REG_INTERRUPT_S: - case M98090_REG_RESERVED: - case M98090_REG_LINE_INPUT_CONFIG: - case M98090_REG_LINE_INPUT_LEVEL: - case M98090_REG_INPUT_MODE: - case M98090_REG_MIC1_INPUT_LEVEL: - case M98090_REG_MIC2_INPUT_LEVEL: - case M98090_REG_MIC_BIAS_VOLTAGE: - case M98090_REG_DIGITAL_MIC_ENABLE: - case M98090_REG_DIGITAL_MIC_CONFIG: - case M98090_REG_LEFT_ADC_MIXER: - case M98090_REG_RIGHT_ADC_MIXER: - case M98090_REG_LEFT_ADC_LEVEL: - case M98090_REG_RIGHT_ADC_LEVEL: - case M98090_REG_ADC_BIQUAD_LEVEL: - case M98090_REG_ADC_SIDETONE: - case M98090_REG_SYSTEM_CLOCK: - case M98090_REG_CLOCK_MODE: - case M98090_REG_CLOCK_RATIO_NI_MSB: - case M98090_REG_CLOCK_RATIO_NI_LSB: - case M98090_REG_CLOCK_RATIO_MI_MSB: - case M98090_REG_CLOCK_RATIO_MI_LSB: - case M98090_REG_MASTER_MODE: - case M98090_REG_INTERFACE_FORMAT: - case M98090_REG_TDM_CONTROL: - case M98090_REG_TDM_FORMAT: - case M98090_REG_IO_CONFIGURATION: - case M98090_REG_FILTER_CONFIG: - case M98090_REG_DAI_PLAYBACK_LEVEL: - case M98090_REG_DAI_PLAYBACK_LEVEL_EQ: - case M98090_REG_LEFT_HP_MIXER: - case M98090_REG_RIGHT_HP_MIXER: - case M98090_REG_HP_CONTROL: - case M98090_REG_LEFT_HP_VOLUME: - case M98090_REG_RIGHT_HP_VOLUME: - case M98090_REG_LEFT_SPK_MIXER: - case M98090_REG_RIGHT_SPK_MIXER: - case M98090_REG_SPK_CONTROL: - case M98090_REG_LEFT_SPK_VOLUME: - case M98090_REG_RIGHT_SPK_VOLUME: - case M98090_REG_DRC_TIMING: - case M98090_REG_DRC_COMPRESSOR: - case M98090_REG_DRC_EXPANDER: - case M98090_REG_DRC_GAIN: - case M98090_REG_RCV_LOUTL_MIXER: - case M98090_REG_RCV_LOUTL_CONTROL: - case M98090_REG_RCV_LOUTL_VOLUME: - case M98090_REG_LOUTR_MIXER: - case M98090_REG_LOUTR_CONTROL: - case M98090_REG_LOUTR_VOLUME: - case M98090_REG_JACK_DETECT: - case M98090_REG_INPUT_ENABLE: - case M98090_REG_OUTPUT_ENABLE: - case M98090_REG_LEVEL_CONTROL: - case M98090_REG_DSP_FILTER_ENABLE: - case M98090_REG_BIAS_CONTROL: - case M98090_REG_DAC_CONTROL: - case M98090_REG_ADC_CONTROL: - case M98090_REG_DEVICE_SHUTDOWN: - case M98090_REG_EQUALIZER_BASE ... M98090_REG_EQUALIZER_BASE + 0x68: - case M98090_REG_RECORD_BIQUAD_BASE ... M98090_REG_RECORD_BIQUAD_BASE + 0x0E: - case M98090_REG_DMIC3_VOLUME: - case M98090_REG_DMIC4_VOLUME: - case M98090_REG_DMIC34_BQ_PREATTEN: - case M98090_REG_RECORD_TDM_SLOT: - case M98090_REG_SAMPLE_RATE: - case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: - return true; - default: - return false; - } -} - -static int max98090_reset(struct max98090_priv *max98090) -{ - int ret; - - /* Reset the codec by writing to this write-only reset register */ - ret = regmap_write(max98090->regmap, M98090_REG_SOFTWARE_RESET, - M98090_SWRESET_MASK); - if (ret < 0) { - dev_err(max98090->codec->dev, - "Failed to reset codec: %d\n", ret); - return ret; - } - - msleep(20); - return ret; -} - -static const unsigned int max98090_micboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), - 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), - 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; - -static const DECLARE_TLV_DB_SCALE(max98090_mic_tlv, 0, 100, 0); - -static const DECLARE_TLV_DB_SCALE(max98090_line_single_ended_tlv, - -600, 600, 0); - -static const unsigned int max98090_line_tlv[] = { - TLV_DB_RANGE_HEAD(2), - 0, 3, TLV_DB_SCALE_ITEM(-600, 300, 0), - 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0), -}; - -static const DECLARE_TLV_DB_SCALE(max98090_avg_tlv, 0, 600, 0); -static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0); - -static const DECLARE_TLV_DB_SCALE(max98090_dvg_tlv, 0, 600, 0); -static const DECLARE_TLV_DB_SCALE(max98090_dv_tlv, -1500, 100, 0); +/* + * + * MAX98090 Registers Definition + * + */ -static const DECLARE_TLV_DB_SCALE(max98090_sidetone_tlv, -6050, 200, 0); +/* 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 -static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0); -static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0); -static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0); -static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); +/* + * + * MAX98090 Registers Bit Fields + * + */ -static const unsigned int max98090_mixout_tlv[] = { - TLV_DB_RANGE_HEAD(2), - 0, 1, TLV_DB_SCALE_ITEM(-1200, 250, 0), - 2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0), +/* 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), - 0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0), - 7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0), - 15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0), - 22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0), + 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 const unsigned int max98090_spk_tlv[] = { - TLV_DB_RANGE_HEAD(5), - 0, 4, TLV_DB_SCALE_ITEM(-4800, 400, 0), - 5, 10, TLV_DB_SCALE_ITEM(-2900, 300, 0), - 11, 14, TLV_DB_SCALE_ITEM(-1200, 200, 0), - 15, 29, TLV_DB_SCALE_ITEM(-500, 100, 0), - 30, 39, TLV_DB_SCALE_ITEM(950, 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), }; -static const unsigned int max98090_rcv_lout_tlv[] = { - TLV_DB_RANGE_HEAD(5), - 0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0), - 7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0), - 15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0), - 22, 27, TLV_DB_SCALE_ITEM(100, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0), +/* 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), }; -static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int mask = (1 << fls(mc->max)) - 1; - unsigned int val = snd_soc_read(codec, mc->reg); - unsigned int *select; - - switch (mc->reg) { - case M98090_REG_MIC1_INPUT_LEVEL: - select = &(max98090->pa1en); - break; - case M98090_REG_MIC2_INPUT_LEVEL: - select = &(max98090->pa2en); - break; - case M98090_REG_ADC_SIDETONE: - select = &(max98090->sidetone); - break; - default: - return -EINVAL; - } - - val = (val >> mc->shift) & mask; - - if (val >= 1) { - /* If on, return the volume */ - val = val - 1; - *select = val; - } else { - /* If off, return last stored value */ - val = *select; - } - - ucontrol->value.integer.value[0] = val; - return 0; -} - -static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int mask = (1 << fls(mc->max)) - 1; - unsigned int sel = ucontrol->value.integer.value[0]; - unsigned int val = snd_soc_read(codec, mc->reg); - unsigned int *select; - - switch (mc->reg) { - case M98090_REG_MIC1_INPUT_LEVEL: - select = &(max98090->pa1en); - break; - case M98090_REG_MIC2_INPUT_LEVEL: - select = &(max98090->pa2en); - break; - case M98090_REG_ADC_SIDETONE: - select = &(max98090->sidetone); - break; - default: - return -EINVAL; - } - - val = (val >> mc->shift) & mask; - - *select = sel; - - /* Setting a volume is only valid if it is already On */ - if (val >= 1) { - sel = sel + 1; - } else { - /* Write what was already there */ - sel = val; - } - - snd_soc_update_bits(codec, mc->reg, - mask << mc->shift, - sel << mc->shift); - - return 0; -} - -static const char * max98090_perf_pwr_text[] = - { "High Performance", "Low Power" }; -static const char * max98090_pwr_perf_text[] = - { "Low Power", "High Performance" }; - -static const struct soc_enum max98090_vcmbandgap_enum = - SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT, - ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); - -static const char * max98090_osr128_text[] = { "64*fs", "128*fs" }; - -static const struct soc_enum max98090_osr128_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT, - ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text); - -static const char *max98090_mode_text[] = { "Voice", "Music" }; - -static const struct soc_enum max98090_mode_enum = - SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT, - ARRAY_SIZE(max98090_mode_text), max98090_mode_text); - -static const struct soc_enum max98090_filter_dmic34mode_enum = - SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, - M98090_FLT_DMIC34MODE_SHIFT, - ARRAY_SIZE(max98090_mode_text), max98090_mode_text); - -static const char * max98090_drcatk_text[] = - { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; - -static const struct soc_enum max98090_drcatk_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT, - ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text); - -static const char * max98090_drcrls_text[] = - { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; - -static const struct soc_enum max98090_drcrls_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT, - ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text); - -static const char * max98090_alccmp_text[] = - { "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; - -static const struct soc_enum max98090_alccmp_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT, - ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text); - -static const char * max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; - -static const struct soc_enum max98090_drcexp_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT, - ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text); - -static const struct soc_enum max98090_dac_perfmode_enum = - SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT, - ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text); - -static const struct soc_enum max98090_dachp_enum = - SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT, - ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); - -static const struct soc_enum max98090_adchp_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT, - ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); - -static const struct snd_kcontrol_new max98090_snd_controls[] = { - SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), - - SOC_SINGLE("DMIC MIC Comp Filter Config", M98090_REG_DIGITAL_MIC_CONFIG, - M98090_DMIC_COMP_SHIFT, M98090_DMIC_COMP_NUM - 1, 0), - - SOC_SINGLE_EXT_TLV("MIC1 Boost Volume", - M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, - M98090_MIC_PA1EN_NUM - 1, 0, max98090_get_enab_tlv, - max98090_put_enab_tlv, max98090_micboost_tlv), - - SOC_SINGLE_EXT_TLV("MIC2 Boost Volume", - M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT, - M98090_MIC_PA2EN_NUM - 1, 0, max98090_get_enab_tlv, - max98090_put_enab_tlv, max98090_micboost_tlv), - - SOC_SINGLE_TLV("MIC1 Volume", M98090_REG_MIC1_INPUT_LEVEL, - M98090_MIC_PGAM1_SHIFT, M98090_MIC_PGAM1_NUM - 1, 1, - max98090_mic_tlv), - - SOC_SINGLE_TLV("MIC2 Volume", M98090_REG_MIC2_INPUT_LEVEL, - M98090_MIC_PGAM2_SHIFT, M98090_MIC_PGAM2_NUM - 1, 1, - max98090_mic_tlv), - - SOC_SINGLE_RANGE_TLV("LINEA Single Ended Volume", - M98090_REG_LINE_INPUT_LEVEL, M98090_MIXG135_SHIFT, 0, - M98090_MIXG135_NUM - 1, 1, max98090_line_single_ended_tlv), - - SOC_SINGLE_RANGE_TLV("LINEB Single Ended Volume", - M98090_REG_LINE_INPUT_LEVEL, M98090_MIXG246_SHIFT, 0, - M98090_MIXG246_NUM - 1, 1, max98090_line_single_ended_tlv), - - SOC_SINGLE_RANGE_TLV("LINEA Volume", M98090_REG_LINE_INPUT_LEVEL, - M98090_LINAPGA_SHIFT, 0, M98090_LINAPGA_NUM - 1, 1, - max98090_line_tlv), - - SOC_SINGLE_RANGE_TLV("LINEB Volume", M98090_REG_LINE_INPUT_LEVEL, - M98090_LINBPGA_SHIFT, 0, M98090_LINBPGA_NUM - 1, 1, - max98090_line_tlv), - - SOC_SINGLE("LINEA Ext Resistor Gain Mode", M98090_REG_INPUT_MODE, - M98090_EXTBUFA_SHIFT, M98090_EXTBUFA_NUM - 1, 0), - SOC_SINGLE("LINEB Ext Resistor Gain Mode", M98090_REG_INPUT_MODE, - M98090_EXTBUFB_SHIFT, M98090_EXTBUFB_NUM - 1, 0), - - SOC_SINGLE_TLV("ADCL Boost Volume", M98090_REG_LEFT_ADC_LEVEL, - M98090_AVLG_SHIFT, M98090_AVLG_NUM - 1, 0, - max98090_avg_tlv), - SOC_SINGLE_TLV("ADCR Boost Volume", M98090_REG_RIGHT_ADC_LEVEL, - M98090_AVRG_SHIFT, M98090_AVLG_NUM - 1, 0, - max98090_avg_tlv), - - SOC_SINGLE_TLV("ADCL Volume", M98090_REG_LEFT_ADC_LEVEL, - M98090_AVL_SHIFT, M98090_AVL_NUM - 1, 1, - max98090_av_tlv), - SOC_SINGLE_TLV("ADCR Volume", M98090_REG_RIGHT_ADC_LEVEL, - M98090_AVR_SHIFT, M98090_AVR_NUM - 1, 1, - max98090_av_tlv), - - SOC_ENUM("ADC Oversampling Rate", max98090_osr128_enum), - SOC_SINGLE("ADC Quantizer Dither", M98090_REG_ADC_CONTROL, - M98090_ADCDITHER_SHIFT, M98090_ADCDITHER_NUM - 1, 0), - SOC_ENUM("ADC High Performance Mode", max98090_adchp_enum), - - SOC_SINGLE("DAC Mono Mode", M98090_REG_IO_CONFIGURATION, - M98090_DMONO_SHIFT, M98090_DMONO_NUM - 1, 0), - SOC_SINGLE("SDIN Mode", M98090_REG_IO_CONFIGURATION, - M98090_SDIEN_SHIFT, M98090_SDIEN_NUM - 1, 0), - SOC_SINGLE("SDOUT Mode", M98090_REG_IO_CONFIGURATION, - M98090_SDOEN_SHIFT, M98090_SDOEN_NUM - 1, 0), - SOC_SINGLE("SDOUT Hi-Z Mode", M98090_REG_IO_CONFIGURATION, - M98090_HIZOFF_SHIFT, M98090_HIZOFF_NUM - 1, 1), - SOC_ENUM("Filter Mode", max98090_mode_enum), - SOC_SINGLE("Record Path DC Blocking", M98090_REG_FILTER_CONFIG, - M98090_AHPF_SHIFT, M98090_AHPF_NUM - 1, 0), - SOC_SINGLE("Playback Path DC Blocking", M98090_REG_FILTER_CONFIG, - M98090_DHPF_SHIFT, M98090_DHPF_NUM - 1, 0), - SOC_SINGLE_TLV("Digital BQ Volume", M98090_REG_ADC_BIQUAD_LEVEL, - M98090_AVBQ_SHIFT, M98090_AVBQ_NUM - 1, 1, max98090_dv_tlv), - SOC_SINGLE_EXT_TLV("Digital Sidetone Volume", - M98090_REG_ADC_SIDETONE, M98090_DVST_SHIFT, - M98090_DVST_NUM - 1, 1, max98090_get_enab_tlv, - max98090_put_enab_tlv, max98090_micboost_tlv), - SOC_SINGLE_TLV("Digital Coarse Volume", M98090_REG_DAI_PLAYBACK_LEVEL, - M98090_DVG_SHIFT, M98090_DVG_NUM - 1, 0, - max98090_dvg_tlv), - SOC_SINGLE_TLV("Digital Volume", M98090_REG_DAI_PLAYBACK_LEVEL, - M98090_DV_SHIFT, M98090_DV_NUM - 1, 1, - max98090_dv_tlv), - SND_SOC_BYTES("EQ Coefficients", M98090_REG_EQUALIZER_BASE, 105), - SOC_SINGLE("Digital EQ 3 Band Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_EQ3BANDEN_SHIFT, M98090_EQ3BANDEN_NUM - 1, 0), - SOC_SINGLE("Digital EQ 5 Band Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_EQ5BANDEN_SHIFT, M98090_EQ5BANDEN_NUM - 1, 0), - SOC_SINGLE("Digital EQ 7 Band Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_EQ7BANDEN_SHIFT, M98090_EQ7BANDEN_NUM - 1, 0), - SOC_SINGLE("Digital EQ Clipping Detection", M98090_REG_DAI_PLAYBACK_LEVEL_EQ, - M98090_EQCLPN_SHIFT, M98090_EQCLPN_NUM - 1, - 1), - SOC_SINGLE_TLV("Digital EQ Volume", M98090_REG_DAI_PLAYBACK_LEVEL_EQ, - M98090_DVEQ_SHIFT, M98090_DVEQ_NUM - 1, 1, - max98090_dv_tlv), - - SOC_SINGLE("ALC Enable", M98090_REG_DRC_TIMING, - M98090_DRCEN_SHIFT, M98090_DRCEN_NUM - 1, 0), - SOC_ENUM("ALC Attack Time", max98090_drcatk_enum), - SOC_ENUM("ALC Release Time", max98090_drcrls_enum), - SOC_SINGLE_TLV("ALC Make Up Volume", M98090_REG_DRC_GAIN, - M98090_DRCG_SHIFT, M98090_DRCG_NUM - 1, 0, - max98090_alcmakeup_tlv), - SOC_ENUM("ALC Compression Ratio", max98090_alccmp_enum), - SOC_ENUM("ALC Expansion Ratio", max98090_drcexp_enum), - SOC_SINGLE_TLV("ALC Compression Threshold Volume", - M98090_REG_DRC_COMPRESSOR, M98090_DRCTHC_SHIFT, - M98090_DRCTHC_NUM - 1, 1, max98090_alccomp_tlv), - SOC_SINGLE_TLV("ALC Expansion Threshold Volume", - M98090_REG_DRC_EXPANDER, M98090_DRCTHE_SHIFT, - M98090_DRCTHE_NUM - 1, 1, max98090_drcexp_tlv), - - SOC_ENUM("DAC HP Playback Performance Mode", - max98090_dac_perfmode_enum), - SOC_ENUM("DAC High Performance Mode", max98090_dachp_enum), - - SOC_SINGLE_TLV("Headphone Left Mixer Volume", - M98090_REG_HP_CONTROL, M98090_MIXHPLG_SHIFT, - M98090_MIXHPLG_NUM - 1, 1, max98090_mixout_tlv), - SOC_SINGLE_TLV("Headphone Right Mixer Volume", - M98090_REG_HP_CONTROL, M98090_MIXHPRG_SHIFT, - M98090_MIXHPRG_NUM - 1, 1, max98090_mixout_tlv), - - SOC_SINGLE_TLV("Speaker Left Mixer Volume", - M98090_REG_SPK_CONTROL, M98090_MIXSPLG_SHIFT, - M98090_MIXSPLG_NUM - 1, 1, max98090_mixout_tlv), - SOC_SINGLE_TLV("Speaker Right Mixer Volume", - M98090_REG_SPK_CONTROL, M98090_MIXSPRG_SHIFT, - M98090_MIXSPRG_NUM - 1, 1, max98090_mixout_tlv), - - SOC_SINGLE_TLV("Receiver Left Mixer Volume", - M98090_REG_RCV_LOUTL_CONTROL, M98090_MIXRCVLG_SHIFT, - M98090_MIXRCVLG_NUM - 1, 1, max98090_mixout_tlv), - SOC_SINGLE_TLV("Receiver Right Mixer Volume", - M98090_REG_LOUTR_CONTROL, M98090_MIXRCVRG_SHIFT, - M98090_MIXRCVRG_NUM - 1, 1, max98090_mixout_tlv), - - SOC_DOUBLE_R_TLV("Headphone Volume", M98090_REG_LEFT_HP_VOLUME, - M98090_REG_RIGHT_HP_VOLUME, M98090_HPVOLL_SHIFT, - M98090_HPVOLL_NUM - 1, 0, max98090_hp_tlv), - - SOC_DOUBLE_R_RANGE_TLV("Speaker Volume", - M98090_REG_LEFT_SPK_VOLUME, M98090_REG_RIGHT_SPK_VOLUME, - M98090_SPVOLL_SHIFT, 24, M98090_SPVOLL_NUM - 1 + 24, - 0, max98090_spk_tlv), - - SOC_DOUBLE_R_TLV("Receiver Volume", M98090_REG_RCV_LOUTL_VOLUME, - M98090_REG_LOUTR_VOLUME, M98090_RCVLVOL_SHIFT, - M98090_RCVLVOL_NUM - 1, 0, max98090_rcv_lout_tlv), - - SOC_SINGLE("Headphone Left Switch", M98090_REG_LEFT_HP_VOLUME, - M98090_HPLM_SHIFT, 1, 1), - SOC_SINGLE("Headphone Right Switch", M98090_REG_RIGHT_HP_VOLUME, - M98090_HPRM_SHIFT, 1, 1), - - SOC_SINGLE("Speaker Left Switch", M98090_REG_LEFT_SPK_VOLUME, - M98090_SPLM_SHIFT, 1, 1), - SOC_SINGLE("Speaker Right Switch", M98090_REG_RIGHT_SPK_VOLUME, - M98090_SPRM_SHIFT, 1, 1), - - SOC_SINGLE("Receiver Left Switch", M98090_REG_RCV_LOUTL_VOLUME, - M98090_RCVLM_SHIFT, 1, 1), - SOC_SINGLE("Receiver Right Switch", M98090_REG_LOUTR_VOLUME, - M98090_RCVRM_SHIFT, 1, 1), - - SOC_SINGLE("Zero-Crossing Detection", M98090_REG_LEVEL_CONTROL, - M98090_ZDENN_SHIFT, M98090_ZDENN_NUM - 1, 1), - SOC_SINGLE("Enhanced Vol Smoothing", M98090_REG_LEVEL_CONTROL, - M98090_VS2ENN_SHIFT, M98090_VS2ENN_NUM - 1, 1), - SOC_SINGLE("Volume Adjustment Smoothing", M98090_REG_LEVEL_CONTROL, - M98090_VSENN_SHIFT, M98090_VSENN_NUM - 1, 1), - - SND_SOC_BYTES("Biquad Coefficients", M98090_REG_RECORD_BIQUAD_BASE, 15), - SOC_SINGLE("Biquad Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_ADCBQEN_SHIFT, M98090_ADCBQEN_NUM - 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 const struct snd_kcontrol_new max98091_snd_controls[] = { - - SOC_SINGLE("DMIC34 Zeropad", M98090_REG_SAMPLE_RATE, - M98090_DMIC34_ZEROPAD_SHIFT, - M98090_DMIC34_ZEROPAD_NUM - 1, 0), - - SOC_ENUM("Filter DMIC34 Mode", max98090_filter_dmic34mode_enum), - SOC_SINGLE("DMIC34 DC Blocking", M98090_REG_FILTER_CONFIG, - M98090_FLT_DMIC34HPF_SHIFT, - M98090_FLT_DMIC34HPF_NUM - 1, 0), - - SOC_SINGLE_TLV("DMIC3 Boost Volume", M98090_REG_DMIC3_VOLUME, - M98090_DMIC_AV3G_SHIFT, M98090_DMIC_AV3G_NUM - 1, 0, - max98090_avg_tlv), - SOC_SINGLE_TLV("DMIC4 Boost Volume", M98090_REG_DMIC4_VOLUME, - M98090_DMIC_AV4G_SHIFT, M98090_DMIC_AV4G_NUM - 1, 0, - max98090_avg_tlv), - - SOC_SINGLE_TLV("DMIC3 Volume", M98090_REG_DMIC3_VOLUME, - M98090_DMIC_AV3_SHIFT, M98090_DMIC_AV3_NUM - 1, 1, - max98090_av_tlv), - SOC_SINGLE_TLV("DMIC4 Volume", M98090_REG_DMIC4_VOLUME, - M98090_DMIC_AV4_SHIFT, M98090_DMIC_AV4_NUM - 1, 1, - max98090_av_tlv), - - SND_SOC_BYTES("DMIC34 Biquad Coefficients", - M98090_REG_DMIC34_BIQUAD_BASE, 15), - SOC_SINGLE("DMIC34 Biquad Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_DMIC34BQEN_SHIFT, M98090_DMIC34BQEN_NUM - 1, 0), - - SOC_SINGLE_TLV("DMIC34 BQ PreAttenuation Volume", - M98090_REG_DMIC34_BQ_PREATTEN, M98090_AV34BQ_SHIFT, - M98090_AV34BQ_NUM - 1, 1, max98090_dv_tlv), -}; - -static int max98090_micinput_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - - unsigned int val = snd_soc_read(codec, w->reg); - - if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) - val = (val & M98090_MIC_PA1EN_MASK) >> M98090_MIC_PA1EN_SHIFT; - else - val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT; - - - if (val >= 1) { - if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) { - max98090->pa1en = val - 1; /* Update for volatile */ - } else { - max98090->pa2en = val - 1; /* Update for volatile */ - } - } - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - /* If turning on, set to most recently selected volume */ - if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) - val = max98090->pa1en + 1; - else - val = max98090->pa2en + 1; - break; - case SND_SOC_DAPM_POST_PMD: - /* If turning off, turn off */ - val = 0; - break; - default: - return -EINVAL; - } - - if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) - snd_soc_update_bits(codec, w->reg, M98090_MIC_PA1EN_MASK, - val << M98090_MIC_PA1EN_SHIFT); - else - snd_soc_update_bits(codec, w->reg, M98090_MIC_PA2EN_MASK, - val << M98090_MIC_PA2EN_SHIFT); - - return 0; -} - -static const char *mic1_mux_text[] = { "IN12", "IN56" }; - -static const struct soc_enum mic1_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT, - ARRAY_SIZE(mic1_mux_text), mic1_mux_text); - -static const struct snd_kcontrol_new max98090_mic1_mux = - SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum); - -static const char *mic2_mux_text[] = { "IN34", "IN56" }; - -static const struct soc_enum mic2_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT, - ARRAY_SIZE(mic2_mux_text), mic2_mux_text); - -static const struct snd_kcontrol_new max98090_mic2_mux = - SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum); - -static const char * max98090_micpre_text[] = { "Off", "On" }; - -static const struct soc_enum max98090_pa1en_enum = - SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, - ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); - -static const struct soc_enum max98090_pa2en_enum = - SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT, - ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); - -/* LINEA mixer switch */ -static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN1SEEN_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN3 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN3SEEN_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN5 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN5SEEN_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN34 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN34DIFF_SHIFT, 1, 0), -}; - -/* LINEB mixer switch */ -static const struct snd_kcontrol_new max98090_lineb_mixer_controls[] = { - SOC_DAPM_SINGLE("IN2 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN2SEEN_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN4 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN4SEEN_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN6 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN6SEEN_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN56 Switch", M98090_REG_LINE_INPUT_CONFIG, - M98090_IN56DIFF_SHIFT, 1, 0), -}; - -/* Left ADC mixer switch */ -static const struct snd_kcontrol_new max98090_left_adc_mixer_controls[] = { - SOC_DAPM_SINGLE("IN12 Switch", M98090_REG_LEFT_ADC_MIXER, - M98090_MIXADL_IN12DIFF_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN34 Switch", M98090_REG_LEFT_ADC_MIXER, - M98090_MIXADL_IN34DIFF_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN56 Switch", M98090_REG_LEFT_ADC_MIXER, - M98090_MIXADL_IN65DIFF_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LEFT_ADC_MIXER, - M98090_MIXADL_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LEFT_ADC_MIXER, - M98090_MIXADL_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LEFT_ADC_MIXER, - M98090_MIXADL_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LEFT_ADC_MIXER, - M98090_MIXADL_MIC2_SHIFT, 1, 0), -}; - -/* Right ADC mixer switch */ -static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = { - SOC_DAPM_SINGLE("IN12 Switch", M98090_REG_RIGHT_ADC_MIXER, - M98090_MIXADR_IN12DIFF_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN34 Switch", M98090_REG_RIGHT_ADC_MIXER, - M98090_MIXADR_IN34DIFF_SHIFT, 1, 0), - SOC_DAPM_SINGLE("IN56 Switch", M98090_REG_RIGHT_ADC_MIXER, - M98090_MIXADR_IN65DIFF_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RIGHT_ADC_MIXER, - M98090_MIXADR_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RIGHT_ADC_MIXER, - M98090_MIXADR_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RIGHT_ADC_MIXER, - M98090_MIXADR_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RIGHT_ADC_MIXER, - M98090_MIXADR_MIC2_SHIFT, 1, 0), -}; - -static const char *lten_mux_text[] = { "Normal", "Loopthrough" }; - -static const struct soc_enum ltenl_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, - ARRAY_SIZE(lten_mux_text), lten_mux_text); - -static const struct soc_enum ltenr_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, - ARRAY_SIZE(lten_mux_text), lten_mux_text); - -static const struct snd_kcontrol_new max98090_ltenl_mux = - SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); - -static const struct snd_kcontrol_new max98090_ltenr_mux = - SOC_DAPM_ENUM("LTENR Mux", ltenr_mux_enum); - -static const char *lben_mux_text[] = { "Normal", "Loopback" }; - -static const struct soc_enum lbenl_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, - ARRAY_SIZE(lben_mux_text), lben_mux_text); - -static const struct soc_enum lbenr_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, - ARRAY_SIZE(lben_mux_text), lben_mux_text); - -static const struct snd_kcontrol_new max98090_lbenl_mux = - SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); - -static const struct snd_kcontrol_new max98090_lbenr_mux = - SOC_DAPM_ENUM("LBENR Mux", lbenr_mux_enum); - -static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" }; - -static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" }; - -static const struct soc_enum stenl_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT, - ARRAY_SIZE(stenl_mux_text), stenl_mux_text); - -static const struct soc_enum stenr_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT, - ARRAY_SIZE(stenr_mux_text), stenr_mux_text); - -static const struct snd_kcontrol_new max98090_stenl_mux = - SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum); - -static const struct snd_kcontrol_new max98090_stenr_mux = - SOC_DAPM_ENUM("STENR Mux", stenr_mux_enum); - -/* Left speaker mixer switch */ -static const struct - snd_kcontrol_new max98090_left_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_LEFT_SPK_MIXER, - M98090_MIXSPL_DACL_SHIFT, 1, 0), - SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_LEFT_SPK_MIXER, - M98090_MIXSPL_DACR_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LEFT_SPK_MIXER, - M98090_MIXSPL_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LEFT_SPK_MIXER, - M98090_MIXSPL_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LEFT_SPK_MIXER, - M98090_MIXSPL_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LEFT_SPK_MIXER, - M98090_MIXSPL_MIC2_SHIFT, 1, 0), -}; - -/* Right speaker mixer switch */ -static const struct - snd_kcontrol_new max98090_right_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_RIGHT_SPK_MIXER, - M98090_MIXSPR_DACL_SHIFT, 1, 0), - SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_RIGHT_SPK_MIXER, - M98090_MIXSPR_DACR_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RIGHT_SPK_MIXER, - M98090_MIXSPR_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RIGHT_SPK_MIXER, - M98090_MIXSPR_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RIGHT_SPK_MIXER, - M98090_MIXSPR_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RIGHT_SPK_MIXER, - M98090_MIXSPR_MIC2_SHIFT, 1, 0), -}; - -/* Left headphone mixer switch */ -static const struct snd_kcontrol_new max98090_left_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_LEFT_HP_MIXER, - M98090_MIXHPL_DACL_SHIFT, 1, 0), - SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_LEFT_HP_MIXER, - M98090_MIXHPL_DACR_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LEFT_HP_MIXER, - M98090_MIXHPL_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LEFT_HP_MIXER, - M98090_MIXHPL_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LEFT_HP_MIXER, - M98090_MIXHPL_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LEFT_HP_MIXER, - M98090_MIXHPL_MIC2_SHIFT, 1, 0), -}; - -/* Right headphone mixer switch */ -static const struct snd_kcontrol_new max98090_right_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_RIGHT_HP_MIXER, - M98090_MIXHPR_DACL_SHIFT, 1, 0), - SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_RIGHT_HP_MIXER, - M98090_MIXHPR_DACR_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RIGHT_HP_MIXER, - M98090_MIXHPR_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RIGHT_HP_MIXER, - M98090_MIXHPR_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RIGHT_HP_MIXER, - M98090_MIXHPR_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RIGHT_HP_MIXER, - M98090_MIXHPR_MIC2_SHIFT, 1, 0), -}; - -/* Left receiver mixer switch */ -static const struct snd_kcontrol_new max98090_left_rcv_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_RCV_LOUTL_MIXER, - M98090_MIXRCVL_DACL_SHIFT, 1, 0), - SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_RCV_LOUTL_MIXER, - M98090_MIXRCVL_DACR_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RCV_LOUTL_MIXER, - M98090_MIXRCVL_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RCV_LOUTL_MIXER, - M98090_MIXRCVL_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RCV_LOUTL_MIXER, - M98090_MIXRCVL_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RCV_LOUTL_MIXER, - M98090_MIXRCVL_MIC2_SHIFT, 1, 0), -}; - -/* Right receiver mixer switch */ -static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_LOUTR_MIXER, - M98090_MIXRCVR_DACL_SHIFT, 1, 0), - SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_LOUTR_MIXER, - M98090_MIXRCVR_DACR_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LOUTR_MIXER, - M98090_MIXRCVR_LINEA_SHIFT, 1, 0), - SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LOUTR_MIXER, - M98090_MIXRCVR_LINEB_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LOUTR_MIXER, - M98090_MIXRCVR_MIC1_SHIFT, 1, 0), - SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LOUTR_MIXER, - M98090_MIXRCVR_MIC2_SHIFT, 1, 0), -}; - -static const char *linmod_mux_text[] = { "Left Only", "Left and Right" }; - -static const struct soc_enum linmod_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT, - ARRAY_SIZE(linmod_mux_text), linmod_mux_text); - -static const struct snd_kcontrol_new max98090_linmod_mux = - SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum); - -static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" }; - -/* - * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable - */ -static const struct soc_enum mixhplsel_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT, - ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); - -static const struct snd_kcontrol_new max98090_mixhplsel_mux = - SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum); - -static const struct soc_enum mixhprsel_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT, - ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); - -static const struct snd_kcontrol_new max98090_mixhprsel_mux = - SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); - -static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { - - SND_SOC_DAPM_INPUT("MIC1"), - SND_SOC_DAPM_INPUT("MIC2"), - SND_SOC_DAPM_INPUT("DMICL"), - SND_SOC_DAPM_INPUT("DMICR"), - SND_SOC_DAPM_INPUT("IN1"), - SND_SOC_DAPM_INPUT("IN2"), - SND_SOC_DAPM_INPUT("IN3"), - SND_SOC_DAPM_INPUT("IN4"), - SND_SOC_DAPM_INPUT("IN5"), - SND_SOC_DAPM_INPUT("IN6"), - SND_SOC_DAPM_INPUT("IN12"), - SND_SOC_DAPM_INPUT("IN34"), - SND_SOC_DAPM_INPUT("IN56"), - - SND_SOC_DAPM_SUPPLY("MICBIAS", M98090_REG_INPUT_ENABLE, - M98090_MBEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("SHDN", M98090_REG_DEVICE_SHUTDOWN, - M98090_SHDNN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("SDIEN", M98090_REG_IO_CONFIGURATION, - M98090_SDIEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("SDOEN", M98090_REG_IO_CONFIGURATION, - M98090_SDOEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DMICL_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMICL_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DMICR_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMICR_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("AHPF", M98090_REG_FILTER_CONFIG, - M98090_AHPF_SHIFT, 0, NULL, 0), - -/* - * Note: Sysclk and misc power supplies are taken care of by SHDN - */ - - SND_SOC_DAPM_MUX("MIC1 Mux", SND_SOC_NOPM, - 0, 0, &max98090_mic1_mux), - - SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM, - 0, 0, &max98090_mic2_mux), - - SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL, - M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - - SND_SOC_DAPM_PGA_E("MIC2 Input", M98090_REG_MIC2_INPUT_LEVEL, - M98090_MIC_PA2EN_SHIFT, 0, NULL, 0, max98090_micinput_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - - SND_SOC_DAPM_MIXER("LINEA Mixer", SND_SOC_NOPM, 0, 0, - &max98090_linea_mixer_controls[0], - ARRAY_SIZE(max98090_linea_mixer_controls)), - - SND_SOC_DAPM_MIXER("LINEB Mixer", SND_SOC_NOPM, 0, 0, - &max98090_lineb_mixer_controls[0], - ARRAY_SIZE(max98090_lineb_mixer_controls)), - - SND_SOC_DAPM_PGA("LINEA Input", M98090_REG_INPUT_ENABLE, - M98090_LINEAEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("LINEB Input", M98090_REG_INPUT_ENABLE, - M98090_LINEBEN_SHIFT, 0, NULL, 0), - - SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0, - &max98090_left_adc_mixer_controls[0], - ARRAY_SIZE(max98090_left_adc_mixer_controls)), - - SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0, - &max98090_right_adc_mixer_controls[0], - ARRAY_SIZE(max98090_right_adc_mixer_controls)), - - SND_SOC_DAPM_ADC("ADCL", NULL, M98090_REG_INPUT_ENABLE, - M98090_ADLEN_SHIFT, 0), - SND_SOC_DAPM_ADC("ADCR", NULL, M98090_REG_INPUT_ENABLE, - M98090_ADREN_SHIFT, 0), - - SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0, - SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AIFOUTR", "HiFi Capture", 1, - SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_MUX("LBENL Mux", SND_SOC_NOPM, - 0, 0, &max98090_lbenl_mux), - - SND_SOC_DAPM_MUX("LBENR Mux", SND_SOC_NOPM, - 0, 0, &max98090_lbenr_mux), - - SND_SOC_DAPM_MUX("LTENL Mux", SND_SOC_NOPM, - 0, 0, &max98090_ltenl_mux), - - SND_SOC_DAPM_MUX("LTENR Mux", SND_SOC_NOPM, - 0, 0, &max98090_ltenr_mux), - - SND_SOC_DAPM_MUX("STENL Mux", SND_SOC_NOPM, - 0, 0, &max98090_stenl_mux), - - SND_SOC_DAPM_MUX("STENR Mux", SND_SOC_NOPM, - 0, 0, &max98090_stenr_mux), - - SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_DAC("DACL", NULL, M98090_REG_OUTPUT_ENABLE, - M98090_DALEN_SHIFT, 0), - SND_SOC_DAPM_DAC("DACR", NULL, M98090_REG_OUTPUT_ENABLE, - M98090_DAREN_SHIFT, 0), - - SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0, - &max98090_left_hp_mixer_controls[0], - ARRAY_SIZE(max98090_left_hp_mixer_controls)), - - SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0, - &max98090_right_hp_mixer_controls[0], - ARRAY_SIZE(max98090_right_hp_mixer_controls)), - - SND_SOC_DAPM_MIXER("Left Speaker Mixer", SND_SOC_NOPM, 0, 0, - &max98090_left_speaker_mixer_controls[0], - ARRAY_SIZE(max98090_left_speaker_mixer_controls)), - - SND_SOC_DAPM_MIXER("Right Speaker Mixer", SND_SOC_NOPM, 0, 0, - &max98090_right_speaker_mixer_controls[0], - ARRAY_SIZE(max98090_right_speaker_mixer_controls)), - - SND_SOC_DAPM_MIXER("Left Receiver Mixer", SND_SOC_NOPM, 0, 0, - &max98090_left_rcv_mixer_controls[0], - ARRAY_SIZE(max98090_left_rcv_mixer_controls)), - - SND_SOC_DAPM_MIXER("Right Receiver Mixer", SND_SOC_NOPM, 0, 0, - &max98090_right_rcv_mixer_controls[0], - ARRAY_SIZE(max98090_right_rcv_mixer_controls)), - - SND_SOC_DAPM_MUX("LINMOD Mux", M98090_REG_LOUTR_MIXER, - M98090_LINMOD_SHIFT, 0, &max98090_linmod_mux), - - SND_SOC_DAPM_MUX("MIXHPLSEL Mux", M98090_REG_HP_CONTROL, - M98090_MIXHPLSEL_SHIFT, 0, &max98090_mixhplsel_mux), - - SND_SOC_DAPM_MUX("MIXHPRSEL Mux", M98090_REG_HP_CONTROL, - M98090_MIXHPRSEL_SHIFT, 0, &max98090_mixhprsel_mux), - - SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE, - M98090_HPLEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("HP Right Out", M98090_REG_OUTPUT_ENABLE, - M98090_HPREN_SHIFT, 0, NULL, 0), - - SND_SOC_DAPM_PGA("SPK Left Out", M98090_REG_OUTPUT_ENABLE, - M98090_SPLEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("SPK Right Out", M98090_REG_OUTPUT_ENABLE, - M98090_SPREN_SHIFT, 0, NULL, 0), - - SND_SOC_DAPM_PGA("RCV Left Out", M98090_REG_OUTPUT_ENABLE, - M98090_RCVLEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("RCV Right Out", M98090_REG_OUTPUT_ENABLE, - M98090_RCVREN_SHIFT, 0, NULL, 0), - +static struct snd_soc_dapm_widget max98090_dapm_widgets[] = { + /* Output */ SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), - SND_SOC_DAPM_OUTPUT("SPKL"), - SND_SOC_DAPM_OUTPUT("SPKR"), - SND_SOC_DAPM_OUTPUT("RCVL"), - SND_SOC_DAPM_OUTPUT("RCVR"), -}; - -static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("DMIC3"), - SND_SOC_DAPM_INPUT("DMIC4"), + /* 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), - SND_SOC_DAPM_SUPPLY("DMIC3_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMIC3_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DMIC4_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMIC4_SHIFT, 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)), -static const struct snd_soc_dapm_route max98090_dapm_routes[] = { - - {"MIC1 Input", NULL, "MIC1"}, - {"MIC2 Input", NULL, "MIC2"}, - - {"DMICL", NULL, "DMICL_ENA"}, - {"DMICR", NULL, "DMICR_ENA"}, - {"DMICL", NULL, "AHPF"}, - {"DMICR", NULL, "AHPF"}, - - /* MIC1 input mux */ - {"MIC1 Mux", "IN12", "IN12"}, - {"MIC1 Mux", "IN56", "IN56"}, - - /* MIC2 input mux */ - {"MIC2 Mux", "IN34", "IN34"}, - {"MIC2 Mux", "IN56", "IN56"}, - - {"MIC1 Input", NULL, "MIC1 Mux"}, - {"MIC2 Input", NULL, "MIC2 Mux"}, - - /* Left ADC input mixer */ - {"Left ADC Mixer", "IN12 Switch", "IN12"}, - {"Left ADC Mixer", "IN34 Switch", "IN34"}, - {"Left ADC Mixer", "IN56 Switch", "IN56"}, - {"Left ADC Mixer", "LINEA Switch", "LINEA Input"}, - {"Left ADC Mixer", "LINEB Switch", "LINEB Input"}, - {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"}, - - /* Right ADC input mixer */ - {"Right ADC Mixer", "IN12 Switch", "IN12"}, - {"Right ADC Mixer", "IN34 Switch", "IN34"}, - {"Right ADC Mixer", "IN56 Switch", "IN56"}, - {"Right ADC Mixer", "LINEA Switch", "LINEA Input"}, - {"Right ADC Mixer", "LINEB Switch", "LINEB Input"}, - {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"}, - - /* Line A input mixer */ - {"LINEA Mixer", "IN1 Switch", "IN1"}, - {"LINEA Mixer", "IN3 Switch", "IN3"}, - {"LINEA Mixer", "IN5 Switch", "IN5"}, - {"LINEA Mixer", "IN34 Switch", "IN34"}, - - /* Line B input mixer */ - {"LINEB Mixer", "IN2 Switch", "IN2"}, - {"LINEB Mixer", "IN4 Switch", "IN4"}, - {"LINEB Mixer", "IN6 Switch", "IN6"}, - {"LINEB Mixer", "IN56 Switch", "IN56"}, - - {"LINEA Input", NULL, "LINEA Mixer"}, - {"LINEB Input", NULL, "LINEB Mixer"}, - - /* Inputs */ - {"ADCL", NULL, "Left ADC Mixer"}, - {"ADCR", NULL, "Right ADC Mixer"}, - {"ADCL", NULL, "SHDN"}, - {"ADCR", NULL, "SHDN"}, - - {"LBENL Mux", "Normal", "ADCL"}, - {"LBENL Mux", "Normal", "DMICL"}, - {"LBENL Mux", "Loopback", "LTENL Mux"}, - {"LBENR Mux", "Normal", "ADCR"}, - {"LBENR Mux", "Normal", "DMICR"}, - {"LBENR Mux", "Loopback", "LTENR Mux"}, - - {"AIFOUTL", NULL, "LBENL Mux"}, - {"AIFOUTR", NULL, "LBENR Mux"}, - {"AIFOUTL", NULL, "SHDN"}, - {"AIFOUTR", NULL, "SHDN"}, - {"AIFOUTL", NULL, "SDOEN"}, - {"AIFOUTR", NULL, "SDOEN"}, - - {"LTENL Mux", "Normal", "AIFINL"}, - {"LTENL Mux", "Loopthrough", "LBENL Mux"}, - {"LTENR Mux", "Normal", "AIFINR"}, - {"LTENR Mux", "Loopthrough", "LBENR Mux"}, - - {"DACL", NULL, "LTENL Mux"}, - {"DACR", NULL, "LTENR Mux"}, - - {"STENL Mux", "Sidetone Left", "ADCL"}, - {"STENL Mux", "Sidetone Left", "DMICL"}, - {"STENR Mux", "Sidetone Right", "ADCR"}, - {"STENR Mux", "Sidetone Right", "DMICR"}, - {"DACL", "NULL", "STENL Mux"}, - {"DACR", "NULL", "STENL Mux"}, - - {"AIFINL", NULL, "SHDN"}, - {"AIFINR", NULL, "SHDN"}, - {"AIFINL", NULL, "SDIEN"}, - {"AIFINR", NULL, "SDIEN"}, - {"DACL", NULL, "SHDN"}, - {"DACR", NULL, "SHDN"}, - - /* Left headphone output mixer */ - {"Left Headphone Mixer", "Left DAC Switch", "DACL"}, - {"Left Headphone Mixer", "Right DAC Switch", "DACR"}, - {"Left Headphone Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Left Headphone Mixer", "MIC2 Switch", "MIC2 Input"}, - {"Left Headphone Mixer", "LINEA Switch", "LINEA Input"}, - {"Left Headphone Mixer", "LINEB Switch", "LINEB Input"}, - - /* Right headphone output mixer */ - {"Right Headphone Mixer", "Left DAC Switch", "DACL"}, - {"Right Headphone Mixer", "Right DAC Switch", "DACR"}, - {"Right Headphone Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Right Headphone Mixer", "MIC2 Switch", "MIC2 Input"}, - {"Right Headphone Mixer", "LINEA Switch", "LINEA Input"}, - {"Right Headphone Mixer", "LINEB Switch", "LINEB Input"}, - - /* Left speaker output mixer */ - {"Left Speaker Mixer", "Left DAC Switch", "DACL"}, - {"Left Speaker Mixer", "Right DAC Switch", "DACR"}, - {"Left Speaker Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Left Speaker Mixer", "MIC2 Switch", "MIC2 Input"}, - {"Left Speaker Mixer", "LINEA Switch", "LINEA Input"}, - {"Left Speaker Mixer", "LINEB Switch", "LINEB Input"}, - - /* Right speaker output mixer */ - {"Right Speaker Mixer", "Left DAC Switch", "DACL"}, - {"Right Speaker Mixer", "Right DAC Switch", "DACR"}, - {"Right Speaker Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Right Speaker Mixer", "MIC2 Switch", "MIC2 Input"}, - {"Right Speaker Mixer", "LINEA Switch", "LINEA Input"}, - {"Right Speaker Mixer", "LINEB Switch", "LINEB Input"}, - - /* Left Receiver output mixer */ - {"Left Receiver Mixer", "Left DAC Switch", "DACL"}, - {"Left Receiver Mixer", "Right DAC Switch", "DACR"}, - {"Left Receiver Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Left Receiver Mixer", "MIC2 Switch", "MIC2 Input"}, - {"Left Receiver Mixer", "LINEA Switch", "LINEA Input"}, - {"Left Receiver Mixer", "LINEB Switch", "LINEB Input"}, - - /* Right Receiver output mixer */ - {"Right Receiver Mixer", "Left DAC Switch", "DACL"}, - {"Right Receiver Mixer", "Right DAC Switch", "DACR"}, - {"Right Receiver Mixer", "MIC1 Switch", "MIC1 Input"}, - {"Right Receiver Mixer", "MIC2 Switch", "MIC2 Input"}, - {"Right Receiver Mixer", "LINEA Switch", "LINEA Input"}, - {"Right Receiver Mixer", "LINEB Switch", "LINEB Input"}, - - {"MIXHPLSEL Mux", "HP Mixer", "Left Headphone Mixer"}, - - /* - * Disable this for lowest power if bypassing - * the DAC with an analog signal - */ - {"HP Left Out", NULL, "DACL"}, - {"HP Left Out", NULL, "MIXHPLSEL Mux"}, - - {"MIXHPRSEL Mux", "HP Mixer", "Right Headphone Mixer"}, - - /* - * Disable this for lowest power if bypassing - * the DAC with an analog signal - */ - {"HP Right Out", NULL, "DACR"}, - {"HP Right Out", NULL, "MIXHPRSEL Mux"}, - - {"SPK Left Out", NULL, "Left Speaker Mixer"}, - {"SPK Right Out", NULL, "Right Speaker Mixer"}, - {"RCV Left Out", NULL, "Left Receiver Mixer"}, - - {"LINMOD Mux", "Left and Right", "Right Receiver Mixer"}, - {"LINMOD Mux", "Left Only", "Left Receiver Mixer"}, - {"RCV Right Out", NULL, "LINMOD Mux"}, - - {"HPL", NULL, "HP Left Out"}, - {"HPR", NULL, "HP Right Out"}, - {"SPKL", NULL, "SPK Left Out"}, - {"SPKR", NULL, "SPK Right Out"}, - {"RCVL", NULL, "RCV Left Out"}, - {"RCVR", NULL, "RCV Right Out"}, + 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 const struct snd_soc_dapm_route max98091_dapm_routes[] = { - - /* DMIC inputs */ - {"DMIC3", NULL, "DMIC3_ENA"}, - {"DMIC4", NULL, "DMIC4_ENA"}, - {"DMIC3", NULL, "AHPF"}, - {"DMIC4", NULL, "AHPF"}, - -}; - -static int max98090_add_widgets(struct snd_soc_codec *codec) -{ - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_add_codec_controls(codec, max98090_snd_controls, - ARRAY_SIZE(max98090_snd_controls)); +static struct snd_soc_dapm_route max98090_audio_map[] = { + /* Output */ + {"HPL", NULL, "HPL Out"}, + {"HPR", NULL, "HPR Out"}, - if (max98090->devtype == MAX98091) { - snd_soc_add_codec_controls(codec, max98091_snd_controls, - ARRAY_SIZE(max98091_snd_controls)); - } - - snd_soc_dapm_new_controls(dapm, max98090_dapm_widgets, - ARRAY_SIZE(max98090_dapm_widgets)); - - snd_soc_dapm_add_routes(dapm, max98090_dapm_routes, - ARRAY_SIZE(max98090_dapm_routes)); - - if (max98090->devtype == MAX98091) { - snd_soc_dapm_new_controls(dapm, max98091_dapm_widgets, - ARRAY_SIZE(max98091_dapm_widgets)); - - snd_soc_dapm_add_routes(dapm, max98091_dapm_routes, - ARRAY_SIZE(max98091_dapm_routes)); - - } + /* PGA */ + {"HPL Out", NULL, "HPL Mixer"}, + {"HPR Out", NULL, "HPR Mixer"}, - return 0; -} - -static const int pclk_rates[] = { - 12000000, 12000000, 13000000, 13000000, - 16000000, 16000000, 19200000, 19200000 -}; - -static const int lrclk_rates[] = { - 8000, 16000, 8000, 16000, - 8000, 16000, 8000, 16000 -}; + /* Mixer*/ + {"HPL Mixer", "DACR Switch", "DACR"}, + {"HPL Mixer", "DACL Switch", "DACL"}, -static const int user_pclk_rates[] = { - 13000000, 13000000 + {"HPR Mixer", "DACR Switch", "DACR"}, + {"HPR Mixer", "DACL Switch", "DACL"}, }; -static const int user_lrclk_rates[] = { - 44100, 48000 -}; - -static const unsigned long long ni_value[] = { - 3528, 768 -}; - -static const unsigned long long mi_value[] = { - 8125, 1625 -}; - -static void max98090_configure_bclk(struct snd_soc_codec *codec) -{ - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - unsigned long long ni; - int i; - - if (!max98090->sysclk) { - dev_err(codec->dev, "No SYSCLK configured\n"); - return; - } - - if (!max98090->bclk || !max98090->lrclk) { - dev_err(codec->dev, "No audio clocks configured\n"); - return; - } - - /* Skip configuration when operating as slave */ - if (!(snd_soc_read(codec, M98090_REG_MASTER_MODE) & - M98090_MAS_MASK)) { - return; - } - - /* Check for supported PCLK to LRCLK ratios */ - for (i = 0; i < ARRAY_SIZE(pclk_rates); i++) { - if ((pclk_rates[i] == max98090->sysclk) && - (lrclk_rates[i] == max98090->lrclk)) { - dev_dbg(codec->dev, - "Found supported PCLK to LRCLK rates 0x%x\n", - i + 0x8); - - snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE, - M98090_FREQ_MASK, - (i + 0x8) << M98090_FREQ_SHIFT); - snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE, - M98090_USE_M1_MASK, 0); - return; - } - } - - /* Check for user calculated MI and NI ratios */ - for (i = 0; i < ARRAY_SIZE(user_pclk_rates); i++) { - if ((user_pclk_rates[i] == max98090->sysclk) && - (user_lrclk_rates[i] == max98090->lrclk)) { - dev_dbg(codec->dev, - "Found user supported PCLK to LRCLK rates\n"); - dev_dbg(codec->dev, "i %d ni %lld mi %lld\n", - i, ni_value[i], mi_value[i]); - - snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE, - M98090_FREQ_MASK, 0); - snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE, - M98090_USE_M1_MASK, - 1 << M98090_USE_M1_SHIFT); - - snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_MSB, - (ni_value[i] >> 8) & 0x7F); - snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_LSB, - ni_value[i] & 0xFF); - snd_soc_write(codec, M98090_REG_CLOCK_RATIO_MI_MSB, - (mi_value[i] >> 8) & 0x7F); - snd_soc_write(codec, M98090_REG_CLOCK_RATIO_MI_LSB, - mi_value[i] & 0xFF); - - return; - } - } - - /* - * Calculate based on MI = 65536 (not as good as either method above) - */ - snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE, - M98090_FREQ_MASK, 0); - snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE, - M98090_USE_M1_MASK, 0); - - /* - * Configure NI when operating as master - * Note: There is a small, but significant audio quality improvement - * by calculating ni and mi. - */ - ni = 65536ULL * (max98090->lrclk < 50000 ? 96ULL : 48ULL) - * (unsigned long long int)max98090->lrclk; - do_div(ni, (unsigned long long int)max98090->sysclk); - dev_info(codec->dev, "No better method found\n"); - dev_info(codec->dev, "Calculating ni %lld with mi 65536\n", ni); - snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_MSB, - (ni >> 8) & 0x7F); - snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_LSB, ni & 0xFF); -} - -static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct max98090_cdata *cdata; - u8 regval; - - max98090->dai_fmt = fmt; - cdata = &max98090->dai[0]; - - if (fmt != cdata->fmt) { - cdata->fmt = fmt; - - regval = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Set to slave mode PLL - MAS mode off */ - snd_soc_write(codec, - M98090_REG_CLOCK_RATIO_NI_MSB, 0x00); - snd_soc_write(codec, - M98090_REG_CLOCK_RATIO_NI_LSB, 0x00); - snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE, - M98090_USE_M1_MASK, 0); - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ - if (max98090->tdm_slots == 4) { - /* TDM */ - regval |= M98090_MAS_MASK | - M98090_BSEL_64; - } else if (max98090->tdm_slots == 3) { - /* TDM */ - regval |= M98090_MAS_MASK | - M98090_BSEL_48; - } else { - /* Few TDM slots, or No TDM */ - regval |= M98090_MAS_MASK | - M98090_BSEL_32; - } - break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: - default: - dev_err(codec->dev, "DAI clock mode unsupported"); - return -EINVAL; - } - snd_soc_write(codec, M98090_REG_MASTER_MODE, regval); - - regval = 0; - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - regval |= M98090_DLY_MASK; - break; - case SND_SOC_DAIFMT_LEFT_J: - break; - case SND_SOC_DAIFMT_RIGHT_J: - regval |= M98090_RJ_MASK; - break; - case SND_SOC_DAIFMT_DSP_A: - /* Not supported mode */ - default: - dev_err(codec->dev, "DAI format unsupported"); - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_NB_IF: - regval |= M98090_WCI_MASK; - break; - case SND_SOC_DAIFMT_IB_NF: - regval |= M98090_BCI_MASK; - break; - case SND_SOC_DAIFMT_IB_IF: - regval |= M98090_BCI_MASK|M98090_WCI_MASK; - break; - default: - dev_err(codec->dev, "DAI invert mode unsupported"); - return -EINVAL; - } - - /* - * This accommodates an inverted logic in the MAX98090 chip - * for Bit Clock Invert (BCI). The inverted logic is only - * seen for the case of TDM mode. The remaining cases have - * normal logic. - */ - if (max98090->tdm_slots > 1) { - regval ^= M98090_BCI_MASK; - } - - snd_soc_write(codec, - M98090_REG_INTERFACE_FORMAT, regval); - } - - return 0; -} - -static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai, - unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) +static bool max98090_volatile(struct device *dev, unsigned int reg) { - struct snd_soc_codec *codec = codec_dai->codec; - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct max98090_cdata *cdata; - cdata = &max98090->dai[0]; - - if (slots < 0 || slots > 4) - return -EINVAL; - - max98090->tdm_slots = slots; - max98090->tdm_width = slot_width; - - if (max98090->tdm_slots > 1) { - /* SLOTL SLOTR SLOTDLY */ - snd_soc_write(codec, M98090_REG_TDM_FORMAT, - 0 << M98090_TDM_SLOTL_SHIFT | - 1 << M98090_TDM_SLOTR_SHIFT | - 0 << M98090_TDM_SLOTDLY_SHIFT); - - /* FSW TDM */ - snd_soc_update_bits(codec, M98090_REG_TDM_CONTROL, - M98090_TDM_MASK, - M98090_TDM_MASK); - } - - /* - * Normally advisable to set TDM first, but this permits either order - */ - cdata->fmt = 0; - max98090_dai_set_fmt(codec_dai, max98090->dai_fmt); + if ((reg == MAX98090_0x01_INT_STS) || + (reg == MAX98090_0x02_JACK_STS) || + (reg > MAX98090_REG_MAX_CACHED)) + return true; - return 0; + return false; } -static int max98090_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static int max98090_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - int ret; + struct snd_soc_codec *codec = dai->codec; + unsigned int val; - switch (level) { - case SND_SOC_BIAS_ON: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = regcache_sync(max98090->regmap); - - if (ret != 0) { - dev_err(codec->dev, - "Failed to sync cache: %d\n", ret); - return ret; - } - } - - if (max98090->jack_state == M98090_JACK_STATE_HEADSET) { - /* - * Set to normal bias level. - */ - snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, - M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); - } + switch (params_rate(params)) { + case 96000: + val = 1 << 5; break; - - case SND_SOC_BIAS_PREPARE: + case 32000: + val = 1 << 4; break; - - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_OFF: - /* Set internal pull-up to lowest power mode */ - snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, - M98090_JDWK_MASK, M98090_JDWK_MASK); - regcache_mark_dirty(max98090->regmap); + case 48000: + val = 1 << 3; break; - } - codec->dapm.bias_level = level; - return 0; -} - -static const int comp_pclk_rates[] = { - 11289600, 12288000, 12000000, 13000000, 19200000 -}; - -static const int dmic_micclk[] = { - 2, 2, 2, 2, 4, 2 -}; - -static const int comp_lrclk_rates[] = { - 8000, 16000, 32000, 44100, 48000, 96000 -}; - -static const int dmic_comp[6][6] = { - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 1, 1, 1}, - {7, 8, 3, 1, 2, 2}, - {7, 8, 3, 3, 3, 3} -}; - -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; - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct max98090_cdata *cdata; - int i, j; - - cdata = &max98090->dai[0]; - max98090->bclk = snd_soc_params_to_bclk(params); - if (params_channels(params) == 1) - max98090->bclk *= 2; - - max98090->lrclk = params_rate(params); - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - snd_soc_update_bits(codec, M98090_REG_INTERFACE_FORMAT, - M98090_WS_MASK, 0); + 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; } - - max98090_configure_bclk(codec); - - cdata->rate = max98090->lrclk; - - /* Update filter mode */ - if (max98090->lrclk < 24000) - snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, - M98090_MODE_MASK, 0); - else - snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, - M98090_MODE_MASK, M98090_MODE_MASK); - - /* Update sample rate mode */ - if (max98090->lrclk < 50000) - snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, - M98090_DHF_MASK, 0); - else - snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, - M98090_DHF_MASK, M98090_DHF_MASK); - - /* Check for supported PCLK to LRCLK ratios */ - for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) { - if (comp_pclk_rates[j] == max98090->sysclk) { - break; - } - } - - for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { - if (max98090->lrclk <= (comp_lrclk_rates[i] + - comp_lrclk_rates[i + 1]) / 2) { - break; - } - } - - snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE, - M98090_MICCLK_MASK, - dmic_micclk[j] << M98090_MICCLK_SHIFT); - - snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG, - M98090_DMIC_COMP_MASK, - dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT); + snd_soc_update_bits(codec, MAX98090_0x05_SAMPLE_RATE, 0x03F, val); return 0; } -/* - * PLL / Sysclk - */ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir) + int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = dai->codec; - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - - /* Requested clock frequency is already setup */ - if (freq == max98090->sysclk) - return 0; - - /* Setup clocks for slave mode, and using the PLL - * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) - * 0x02 (when master clk is 20MHz to 40MHz).. - * 0x03 (when master clk is 40MHz to 60MHz).. - */ - if ((freq >= 10000000) && (freq < 20000000)) { - snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, - M98090_PSCLK_DIV1); - } else if ((freq >= 20000000) && (freq < 40000000)) { - snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, - M98090_PSCLK_DIV2); - } else if ((freq >= 40000000) && (freq < 60000000)) { - snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, - M98090_PSCLK_DIV4); - } else { + 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); - max98090->sysclk = freq; - - max98090_configure_bclk(codec); + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, MAX98090_SHDNRUN); - return 0; -} - -static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute) -{ - struct snd_soc_codec *codec = codec_dai->codec; - int regval; - - regval = mute ? M98090_DVM_MASK : 0; - snd_soc_update_bits(codec, M98090_REG_DAI_PLAYBACK_LEVEL, - M98090_DVM_MASK, regval); + dev_dbg(dai->dev, "sysclk is %uHz\n", freq); return 0; } -static void max98090_jack_work(struct work_struct *work) -{ - struct max98090_priv *max98090 = container_of(work, - struct max98090_priv, - jack_work.work); - struct snd_soc_codec *codec = max98090->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int status = 0; - int reg; - - /* Read a second time */ - if (max98090->jack_state == M98090_JACK_STATE_NO_HEADSET) { - - /* Strong pull up allows mic detection */ - snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, - M98090_JDWK_MASK, 0); - - msleep(50); - - reg = snd_soc_read(codec, M98090_REG_JACK_STATUS); - - /* Weak pull up allows only insertion detection */ - snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, - M98090_JDWK_MASK, M98090_JDWK_MASK); - } else { - reg = snd_soc_read(codec, M98090_REG_JACK_STATUS); - } - - reg = snd_soc_read(codec, M98090_REG_JACK_STATUS); - - switch (reg & (M98090_LSNS_MASK | M98090_JKSNS_MASK)) { - case M98090_LSNS_MASK | M98090_JKSNS_MASK: - dev_dbg(codec->dev, "No Headset Detected\n"); - - max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; - - status |= 0; - - break; - - case 0: - if (max98090->jack_state == - M98090_JACK_STATE_HEADSET) { - - dev_dbg(codec->dev, - "Headset Button Down Detected\n"); - - /* - * max98090_headset_button_event(codec) - * could be defined, then called here. - */ - - status |= SND_JACK_HEADSET; - status |= SND_JACK_BTN_0; - - break; - } - - /* Line is reported as Headphone */ - /* Nokia Headset is reported as Headphone */ - /* Mono Headphone is reported as Headphone */ - dev_dbg(codec->dev, "Headphone Detected\n"); - - max98090->jack_state = M98090_JACK_STATE_HEADPHONE; - - status |= SND_JACK_HEADPHONE; - - break; - - case M98090_JKSNS_MASK: - dev_dbg(codec->dev, "Headset Detected\n"); - - max98090->jack_state = M98090_JACK_STATE_HEADSET; - - status |= SND_JACK_HEADSET; - - break; - - default: - dev_dbg(codec->dev, "Unrecognized Jack Status\n"); - break; - } - - snd_soc_jack_report(max98090->jack, status, - SND_JACK_HEADSET | SND_JACK_BTN_0); - - snd_soc_dapm_sync(dapm); -} - -static irqreturn_t max98090_interrupt(int irq, void *data) +static int max98090_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) { - struct snd_soc_codec *codec = data; - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - int ret; - unsigned int mask; - unsigned int active; - - dev_dbg(codec->dev, "***** max98090_interrupt *****\n"); - - ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); - - if (ret != 0) { - dev_err(codec->dev, - "failed to read M98090_REG_INTERRUPT_S: %d\n", - ret); - return IRQ_NONE; - } - - ret = regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &active); - - if (ret != 0) { - dev_err(codec->dev, - "failed to read M98090_REG_DEVICE_STATUS: %d\n", - ret); - return IRQ_NONE; - } - - dev_dbg(codec->dev, "active=0x%02x mask=0x%02x -> active=0x%02x\n", - active, mask, active & mask); - - active &= mask; - - if (!active) - return IRQ_NONE; - - if (active & M98090_CLD_MASK) { - dev_err(codec->dev, "M98090_CLD_MASK\n"); - } - - if (active & M98090_SLD_MASK) { - dev_dbg(codec->dev, "M98090_SLD_MASK\n"); - } - - if (active & M98090_ULK_MASK) { - dev_err(codec->dev, "M98090_ULK_MASK\n"); - } - - if (active & M98090_JDET_MASK) { - dev_dbg(codec->dev, "M98090_JDET_MASK\n"); - - pm_wakeup_event(codec->dev, 100); - - schedule_delayed_work(&max98090->jack_work, - msecs_to_jiffies(100)); - } - - if (active & M98090_DRCACT_MASK) { - dev_dbg(codec->dev, "M98090_DRCACT_MASK\n"); - } + struct snd_soc_codec *codec = dai->codec; + int is_master; + u8 val; - if (active & M98090_DRCCLP_MASK) { - dev_err(codec->dev, "M98090_DRCCLP_MASK\n"); + /* 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; } - return IRQ_HANDLED; -} - -/** - * max98090_mic_detect - Enable microphone detection via the MAX98090 IRQ - * - * @codec: MAX98090 codec - * @jack: jack to report detection events on - * - * Enable microphone detection via IRQ on the MAX98090. If GPIOs are - * being used to bring out signals to the processor then only platform - * data configuration is needed for MAX98090 and processor GPIOs should - * be configured using snd_soc_jack_add_gpios() instead. - * - * If no jack is supplied detection will be disabled. - */ -int max98090_mic_detect(struct snd_soc_codec *codec, - struct snd_soc_jack *jack) -{ - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - - dev_dbg(codec->dev, "max98090_mic_detect\n"); - - max98090->jack = jack; - if (jack) { - snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, - M98090_IJDET_MASK, - 1 << M98090_IJDET_SHIFT); - } else { - snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, - M98090_IJDET_MASK, - 0); + /* 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; } - - /* Send an initial empty report */ - snd_soc_jack_report(max98090->jack, 0, - SND_JACK_HEADSET | SND_JACK_BTN_0); - - schedule_delayed_work(&max98090->jack_work, - msecs_to_jiffies(100)); + snd_soc_update_bits(codec, MAX98090_0x06_DAI_IF, + MAX98090_DAI_IF_MASK, val); return 0; } -EXPORT_SYMBOL_GPL(max98090_mic_detect); #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, - .set_tdm_slot = max98090_set_tdm_slot, - .hw_params = max98090_dai_hw_params, - .digital_mute = max98090_dai_digital_mute, + .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 = "HiFi", +static struct snd_soc_dai_driver max98090_dai = { + .name = "max98090-Hifi", .playback = { - .stream_name = "HiFi Playback", - .channels_min = 2, - .channels_max = 2, - .rates = MAX98090_RATES, - .formats = MAX98090_FORMATS, - }, - .capture = { - .stream_name = "HiFi Capture", - .channels_min = 1, - .channels_max = 2, - .rates = MAX98090_RATES, - .formats = MAX98090_FORMATS, + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98090_RATES, + .formats = MAX98090_FORMATS, }, - .ops = &max98090_dai_ops, -} + .ops = &max98090_dai_ops, }; -static void max98090_handle_pdata(struct snd_soc_codec *codec) -{ - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct max98090_pdata *pdata = max98090->pdata; - - if (!pdata) { - dev_err(codec->dev, "No platform data\n"); - return; - } - -} - static int max98090_probe(struct snd_soc_codec *codec) { - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct max98090_cdata *cdata; - int ret = 0; - - dev_dbg(codec->dev, "max98090_probe\n"); - - max98090->codec = codec; - - codec->control_data = max98090->regmap; + 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(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } - - /* Reset the codec, the DSP core, and disable all interrupts */ - max98090_reset(max98090); - - /* Initialize private data */ - - max98090->sysclk = (unsigned)-1; - - cdata = &max98090->dai[0]; - cdata->rate = (unsigned)-1; - cdata->fmt = (unsigned)-1; - - max98090->lin_state = 0; - max98090->pa1en = 0; - max98090->pa2en = 0; - max98090->extmic_mux = 0; - - ret = snd_soc_read(codec, M98090_REG_REVISION_ID); if (ret < 0) { - dev_err(codec->dev, "Failed to read device revision: %d\n", - ret); - goto err_access; - } - - if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) { - max98090->devtype = MAX98090; - dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret); - } else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) { - max98090->devtype = MAX98091; - dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret); - } else { - max98090->devtype = MAX98090; - dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret); + dev_err(dev, "Failed to set cache I/O: %d\n", ret); + return ret; } - max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; - - INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); + /* Device active */ + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, MAX98090_SHDNRUN); - /* Enable jack detection */ - snd_soc_write(codec, M98090_REG_JACK_DETECT, - M98090_JDETEN_MASK | M98090_JDEB_25MS); - - /* Register for interrupts */ - dev_dbg(codec->dev, "irq = %d\n", max98090->irq); - - ret = request_threaded_irq(max98090->irq, NULL, - max98090_interrupt, IRQF_TRIGGER_FALLING, - "max98090_interrupt", codec); - if (ret < 0) { - dev_err(codec->dev, "request_irq failed: %d\n", - ret); - } - - /* - * Clear any old interrupts. - * An old interrupt ocurring prior to installing the ISR - * can keep a new interrupt from generating a trigger. - */ - snd_soc_read(codec, M98090_REG_DEVICE_STATUS); - - /* High Performance is default */ - snd_soc_update_bits(codec, M98090_REG_DAC_CONTROL, - M98090_DACHP_MASK, - 1 << M98090_DACHP_SHIFT); - snd_soc_update_bits(codec, M98090_REG_DAC_CONTROL, - M98090_PERFMODE_MASK, - 0 << M98090_PERFMODE_SHIFT); - snd_soc_update_bits(codec, M98090_REG_ADC_CONTROL, - M98090_ADCHP_MASK, - 1 << M98090_ADCHP_SHIFT); - - /* Turn on VCM bandgap reference */ - snd_soc_write(codec, M98090_REG_BIAS_CONTROL, - M98090_VCM_MODE_MASK); - - max98090_handle_pdata(codec); - - max98090_add_widgets(codec); - -err_access: - return ret; + return 0; } static int max98090_remove(struct snd_soc_codec *codec) { - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - - cancel_delayed_work_sync(&max98090->jack_work); - return 0; } static struct snd_soc_codec_driver soc_codec_dev_max98090 = { - .probe = max98090_probe, - .remove = max98090_remove, - .set_bias_level = max98090_set_bias_level, + .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_MAX_REGISTER, - .reg_defaults = max98090_reg, - .num_reg_defaults = ARRAY_SIZE(max98090_reg), - .volatile_reg = max98090_volatile_register, - .readable_reg = max98090_readable_register, - .cache_type = REGCACHE_RBTREE, + .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) + const struct i2c_device_id *id) { - struct max98090_priv *max98090; + struct max98090_priv *priv; + struct device *dev = &i2c->dev; + unsigned int val; int ret; - pr_debug("max98090_i2c_probe\n"); - - max98090 = devm_kzalloc(&i2c->dev, sizeof(struct max98090_priv), - GFP_KERNEL); - if (max98090 == NULL) + priv = devm_kzalloc(dev, sizeof(struct max98090_priv), + GFP_KERNEL); + if (!priv) return -ENOMEM; - max98090->devtype = id->driver_data; - i2c_set_clientdata(i2c, max98090); - max98090->control_data = i2c; - max98090->pdata = i2c->dev.platform_data; - max98090->irq = i2c->irq; - - max98090->regmap = regmap_init_i2c(i2c, &max98090_regmap); - if (IS_ERR(max98090->regmap)) { - ret = PTR_ERR(max98090->regmap); - dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); - goto err_enable; + 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; } - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_max98090, max98090_dai, - ARRAY_SIZE(max98090_dai)); - if (ret < 0) - regmap_exit(max98090->regmap); + 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); -err_enable: return ret; } static int max98090_i2c_remove(struct i2c_client *client) { - struct max98090_priv *max98090 = dev_get_drvdata(&client->dev); snd_soc_unregister_codec(&client->dev); - regmap_exit(max98090->regmap); - return 0; -} - -static int max98090_runtime_resume(struct device *dev) -{ - struct max98090_priv *max98090 = dev_get_drvdata(dev); - - regcache_cache_only(max98090->regmap, false); - - regcache_sync(max98090->regmap); - return 0; } -static int max98090_runtime_suspend(struct device *dev) -{ - struct max98090_priv *max98090 = dev_get_drvdata(dev); - - regcache_cache_only(max98090->regmap, true); - - return 0; -} - -static struct dev_pm_ops max98090_pm = { - SET_RUNTIME_PM_OPS(max98090_runtime_suspend, - max98090_runtime_resume, NULL) -}; - static const struct i2c_device_id max98090_i2c_id[] = { - { "max98090", MAX98090 }, + { "max98090", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); @@ -2384,15 +565,13 @@ static struct i2c_driver max98090_i2c_driver = { .driver = { .name = "max98090", .owner = THIS_MODULE, - .pm = &max98090_pm, }, - .probe = max98090_i2c_probe, - .remove = max98090_i2c_remove, - .id_table = max98090_i2c_id, + .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, Jesse Marroqin, Jerry Wong"); +MODULE_AUTHOR("Peter Hsiang, Kuninori Morimoto"); MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/max98090.h b/trunk/sound/soc/codecs/max98090.h deleted file mode 100755 index 7e103f249053..000000000000 --- a/trunk/sound/soc/codecs/max98090.h +++ /dev/null @@ -1,1549 +0,0 @@ -/* - * max98090.h -- MAX98090 ALSA SoC Audio driver - * - * Copyright 2011-2012 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. - */ - -#ifndef _MAX98090_H -#define _MAX98090_H - -#include - -/* One can override the Linux version here with an explicit version number */ -#define M98090_LINUX_VERSION LINUX_VERSION_CODE - -/* - * MAX98090 Register Definitions - */ - -#define M98090_REG_SOFTWARE_RESET 0x00 -#define M98090_REG_DEVICE_STATUS 0x01 -#define M98090_REG_JACK_STATUS 0x02 -#define M98090_REG_INTERRUPT_S 0x03 -#define M98090_REG_QUICK_SYSTEM_CLOCK 0x04 -#define M98090_REG_QUICK_SAMPLE_RATE 0x05 -#define M98090_REG_DAI_INTERFACE 0x06 -#define M98090_REG_DAC_PATH 0x07 -#define M98090_REG_MIC_DIRECT_TO_ADC 0x08 -#define M98090_REG_LINE_TO_ADC 0x09 -#define M98090_REG_ANALOG_MIC_LOOP 0x0A -#define M98090_REG_ANALOG_LINE_LOOP 0x0B -#define M98090_REG_RESERVED 0x0C -#define M98090_REG_LINE_INPUT_CONFIG 0x0D -#define M98090_REG_LINE_INPUT_LEVEL 0x0E -#define M98090_REG_INPUT_MODE 0x0F -#define M98090_REG_MIC1_INPUT_LEVEL 0x10 -#define M98090_REG_MIC2_INPUT_LEVEL 0x11 -#define M98090_REG_MIC_BIAS_VOLTAGE 0x12 -#define M98090_REG_DIGITAL_MIC_ENABLE 0x13 -#define M98090_REG_DIGITAL_MIC_CONFIG 0x14 -#define M98090_REG_LEFT_ADC_MIXER 0x15 -#define M98090_REG_RIGHT_ADC_MIXER 0x16 -#define M98090_REG_LEFT_ADC_LEVEL 0x17 -#define M98090_REG_RIGHT_ADC_LEVEL 0x18 -#define M98090_REG_ADC_BIQUAD_LEVEL 0x19 -#define M98090_REG_ADC_SIDETONE 0x1A -#define M98090_REG_SYSTEM_CLOCK 0x1B -#define M98090_REG_CLOCK_MODE 0x1C -#define M98090_REG_CLOCK_RATIO_NI_MSB 0x1D -#define M98090_REG_CLOCK_RATIO_NI_LSB 0x1E -#define M98090_REG_CLOCK_RATIO_MI_MSB 0x1F -#define M98090_REG_CLOCK_RATIO_MI_LSB 0x20 -#define M98090_REG_MASTER_MODE 0x21 -#define M98090_REG_INTERFACE_FORMAT 0x22 -#define M98090_REG_TDM_CONTROL 0x23 -#define M98090_REG_TDM_FORMAT 0x24 -#define M98090_REG_IO_CONFIGURATION 0x25 -#define M98090_REG_FILTER_CONFIG 0x26 -#define M98090_REG_DAI_PLAYBACK_LEVEL 0x27 -#define M98090_REG_DAI_PLAYBACK_LEVEL_EQ 0x28 -#define M98090_REG_LEFT_HP_MIXER 0x29 -#define M98090_REG_RIGHT_HP_MIXER 0x2A -#define M98090_REG_HP_CONTROL 0x2B -#define M98090_REG_LEFT_HP_VOLUME 0x2C -#define M98090_REG_RIGHT_HP_VOLUME 0x2D -#define M98090_REG_LEFT_SPK_MIXER 0x2E -#define M98090_REG_RIGHT_SPK_MIXER 0x2F -#define M98090_REG_SPK_CONTROL 0x30 -#define M98090_REG_LEFT_SPK_VOLUME 0x31 -#define M98090_REG_RIGHT_SPK_VOLUME 0x32 -#define M98090_REG_DRC_TIMING 0x33 -#define M98090_REG_DRC_COMPRESSOR 0x34 -#define M98090_REG_DRC_EXPANDER 0x35 -#define M98090_REG_DRC_GAIN 0x36 -#define M98090_REG_RCV_LOUTL_MIXER 0x37 -#define M98090_REG_RCV_LOUTL_CONTROL 0x38 -#define M98090_REG_RCV_LOUTL_VOLUME 0x39 -#define M98090_REG_LOUTR_MIXER 0x3A -#define M98090_REG_LOUTR_CONTROL 0x3B -#define M98090_REG_LOUTR_VOLUME 0x3C -#define M98090_REG_JACK_DETECT 0x3D -#define M98090_REG_INPUT_ENABLE 0x3E -#define M98090_REG_OUTPUT_ENABLE 0x3F -#define M98090_REG_LEVEL_CONTROL 0x40 -#define M98090_REG_DSP_FILTER_ENABLE 0x41 -#define M98090_REG_BIAS_CONTROL 0x42 -#define M98090_REG_DAC_CONTROL 0x43 -#define M98090_REG_ADC_CONTROL 0x44 -#define M98090_REG_DEVICE_SHUTDOWN 0x45 -#define M98090_REG_EQUALIZER_BASE 0x46 -#define M98090_REG_RECORD_BIQUAD_BASE 0xAF -#define M98090_REG_DMIC3_VOLUME 0xBE -#define M98090_REG_DMIC4_VOLUME 0xBF -#define M98090_REG_DMIC34_BQ_PREATTEN 0xC0 -#define M98090_REG_RECORD_TDM_SLOT 0xC1 -#define M98090_REG_SAMPLE_RATE 0xC2 -#define M98090_REG_DMIC34_BIQUAD_BASE 0xC3 -#define M98090_REG_REVISION_ID 0xFF - -#define M98090_REG_CNT (0xFF+1) -#define MAX98090_MAX_REGISTER 0xFF - -/* MAX98090 Register Bit Fields */ - -/* - * M98090_REG_SOFTWARE_RESET - */ -#define M98090_SWRESET_MASK (1<<7) -#define M98090_SWRESET_SHIFT 7 -#define M98090_SWRESET_WIDTH 1 - -/* - * M98090_REG_DEVICE_STATUS - */ -#define M98090_CLD_MASK (1<<7) -#define M98090_CLD_SHIFT 7 -#define M98090_CLD_WIDTH 1 -#define M98090_SLD_MASK (1<<6) -#define M98090_SLD_SHIFT 6 -#define M98090_SLD_WIDTH 1 -#define M98090_ULK_MASK (1<<5) -#define M98090_ULK_SHIFT 5 -#define M98090_ULK_WIDTH 1 -#define M98090_JDET_MASK (1<<2) -#define M98090_JDET_SHIFT 2 -#define M98090_JDET_WIDTH 1 -#define M98090_DRCACT_MASK (1<<1) -#define M98090_DRCACT_SHIFT 1 -#define M98090_DRCACT_WIDTH 1 -#define M98090_DRCCLP_MASK (1<<0) -#define M98090_DRCCLP_SHIFT 0 -#define M98090_DRCCLP_WIDTH 1 - -/* - * M98090_REG_JACK_STATUS - */ -#define M98090_LSNS_MASK (1<<2) -#define M98090_LSNS_SHIFT 2 -#define M98090_LSNS_WIDTH 1 -#define M98090_JKSNS_MASK (1<<1) -#define M98090_JKSNS_SHIFT 1 -#define M98090_JKSNS_WIDTH 1 - -/* - * M98090_REG_INTERRUPT_S - */ -#define M98090_ICLD_MASK (1<<7) -#define M98090_ICLD_SHIFT 7 -#define M98090_ICLD_WIDTH 1 -#define M98090_ISLD_MASK (1<<6) -#define M98090_ISLD_SHIFT 6 -#define M98090_ISLD_WIDTH 1 -#define M98090_IULK_MASK (1<<5) -#define M98090_IULK_SHIFT 5 -#define M98090_IULK_WIDTH 1 -#define M98090_IJDET_MASK (1<<2) -#define M98090_IJDET_SHIFT 2 -#define M98090_IJDET_WIDTH 1 -#define M98090_IDRCACT_MASK (1<<1) -#define M98090_IDRCACT_SHIFT 1 -#define M98090_IDRCACT_WIDTH 1 -#define M98090_IDRCCLP_MASK (1<<0) -#define M98090_IDRCCLP_SHIFT 0 -#define M98090_IDRCCLP_WIDTH 1 - -/* - * M98090_REG_QUICK_SYSTEM_CLOCK - */ -#define M98090_26M_MASK (1<<7) -#define M98090_26M_SHIFT 7 -#define M98090_26M_WIDTH 1 -#define M98090_19P2M_MASK (1<<6) -#define M98090_19P2M_SHIFT 6 -#define M98090_19P2M_WIDTH 1 -#define M98090_13M_MASK (1<<5) -#define M98090_13M_SHIFT 5 -#define M98090_13M_WIDTH 1 -#define M98090_12P288M_MASK (1<<4) -#define M98090_12P288M_SHIFT 4 -#define M98090_12P288M_WIDTH 1 -#define M98090_12M_MASK (1<<3) -#define M98090_12M_SHIFT 3 -#define M98090_12M_WIDTH 1 -#define M98090_11P2896M_MASK (1<<2) -#define M98090_11P2896M_SHIFT 2 -#define M98090_11P2896M_WIDTH 1 -#define M98090_256FS_MASK (1<<0) -#define M98090_256FS_SHIFT 0 -#define M98090_256FS_WIDTH 1 -#define M98090_CLK_ALL_SHIFT 0 -#define M98090_CLK_ALL_WIDTH 8 -#define M98090_CLK_ALL_NUM (1<> 8) & 0xff) -#define M98090_BYTE0(w) (w & 0xff) - -/* Silicon revision number */ -#define M98090_REVA 0x40 -#define M98091_REVA 0x50 - -enum max98090_type { - MAX98090, - MAX98091, -}; - -struct max98090_cdata { - unsigned int rate; - unsigned int fmt; -}; - -struct max98090_priv { - struct regmap *regmap; - struct snd_soc_codec *codec; - enum max98090_type devtype; - void *control_data; - struct max98090_pdata *pdata; - unsigned int sysclk; - unsigned int bclk; - unsigned int lrclk; - struct max98090_cdata dai[1]; - int irq; - int jack_state; - struct delayed_work jack_work; - struct snd_soc_jack *jack; - unsigned int dai_fmt; - int tdm_slots; - int tdm_width; - u8 lin_state; - unsigned int pa1en; - unsigned int pa2en; - unsigned int extmic_mux; - unsigned int sidetone; -}; - -int max98090_mic_detect(struct snd_soc_codec *codec, - struct snd_soc_jack *jack); - -#endif diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index 65d09d60b7c6..5708a973a776 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -85,9 +85,6 @@ struct aic3x_priv { #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 u16 model; - - /* Selects the micbias voltage */ - enum aic3x_micbias_voltage micbias_vg; }; /* @@ -198,37 +195,6 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, return ret; } -/* - * mic bias power on/off share the same register bits with - * output voltage of mic bias. when power on mic bias, we - * need reclaim it to voltage value. - * 0x0 = Powered off - * 0x1 = MICBIAS output is powered to 2.0V, - * 0x2 = MICBIAS output is powered to 2.5V - * 0x3 = MICBIAS output is connected to AVDD - */ -static int mic_bias_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - /* change mic bias voltage to user defined */ - snd_soc_update_bits(codec, MICBIAS_CTRL, - MICBIAS_LEVEL_MASK, - aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT); - break; - - case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(codec, MICBIAS_CTRL, - MICBIAS_LEVEL_MASK, 0); - break; - } - return 0; -} - static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; static const char *aic3x_left_hpcom_mux[] = @@ -630,9 +596,12 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), /* Mic Bias */ - SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0, - mic_bias_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", + MICBIAS_CTRL, 6, 3, 1, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", + MICBIAS_CTRL, 6, 3, 2, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", + MICBIAS_CTRL, 6, 3, 3, 0), /* Output mixers */ SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, @@ -1241,13 +1210,13 @@ static struct snd_soc_dai_driver aic3x_dai = { .name = "tlv320aic3x-hifi", .playback = { .stream_name = "Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = AIC3X_RATES, .formats = AIC3X_FORMATS,}, .capture = { .stream_name = "Capture", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = AIC3X_RATES, .formats = AIC3X_FORMATS,}, @@ -1417,24 +1386,6 @@ static int aic3x_probe(struct snd_soc_codec *codec) if (aic3x->model == AIC3X_MODEL_3007) snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); - /* set mic bias voltage */ - switch (aic3x->micbias_vg) { - case AIC3X_MICBIAS_2_0V: - case AIC3X_MICBIAS_2_5V: - case AIC3X_MICBIAS_AVDDV: - snd_soc_update_bits(codec, MICBIAS_CTRL, - MICBIAS_LEVEL_MASK, - (aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT); - break; - case AIC3X_MICBIAS_OFF: - /* - * noting to do. target won't enter here. This is just to avoid - * compile time warning "warning: enumeration value - * 'AIC3X_MICBIAS_OFF' not handled in switch" - */ - break; - } - aic3x_add_widgets(codec); list_add(&aic3x->list, &reset_list); @@ -1510,7 +1461,6 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, struct aic3x_setup_data *ai3x_setup; struct device_node *np = i2c->dev.of_node; int ret; - u32 value; aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); if (aic3x == NULL) { @@ -1524,7 +1474,6 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, if (pdata) { aic3x->gpio_reset = pdata->gpio_reset; aic3x->setup = pdata->setup; - aic3x->micbias_vg = pdata->micbias_vg; } else if (np) { ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup), GFP_KERNEL); @@ -1544,26 +1493,6 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, aic3x->setup = ai3x_setup; } - if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) { - switch (value) { - case 1 : - aic3x->micbias_vg = AIC3X_MICBIAS_2_0V; - break; - case 2 : - aic3x->micbias_vg = AIC3X_MICBIAS_2_5V; - break; - case 3 : - aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV; - break; - default : - aic3x->micbias_vg = AIC3X_MICBIAS_OFF; - dev_err(&i2c->dev, "Unsuitable MicBias voltage " - "found in DT\n"); - } - } else { - aic3x->micbias_vg = AIC3X_MICBIAS_OFF; - } - } else { aic3x->gpio_reset = -1; } diff --git a/trunk/sound/soc/codecs/tlv320aic3x.h b/trunk/sound/soc/codecs/tlv320aic3x.h index e521ac3ddde8..6db3c41b0163 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.h +++ b/trunk/sound/soc/codecs/tlv320aic3x.h @@ -238,10 +238,6 @@ /* Default input volume */ #define DEFAULT_GAIN 0x20 -/* MICBIAS Control Register */ -#define MICBIAS_LEVEL_SHIFT (6) -#define MICBIAS_LEVEL_MASK (3 << 6) - /* headset detection / button API */ /* The AIC3x supports detection of stereo headsets (GND + left + right signal) diff --git a/trunk/sound/soc/codecs/tlv320dac33.c b/trunk/sound/soc/codecs/tlv320dac33.c index 4f358393d6d6..782b0cded2e6 100644 --- a/trunk/sound/soc/codecs/tlv320dac33.c +++ b/trunk/sound/soc/codecs/tlv320dac33.c @@ -1452,6 +1452,20 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) return 0; } +static int dac33_soc_suspend(struct snd_soc_codec *codec) +{ + dac33_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int dac33_soc_resume(struct snd_soc_codec *codec) +{ + dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} + static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { .read = dac33_read_reg_cache, .write = dac33_write_locked, @@ -1462,6 +1476,8 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { .reg_cache_default = dac33_reg, .probe = dac33_soc_probe, .remove = dac33_soc_remove, + .suspend = dac33_soc_suspend, + .resume = dac33_soc_resume, .controls = dac33_snd_controls, .num_controls = ARRAY_SIZE(dac33_snd_controls), diff --git a/trunk/sound/soc/codecs/twl4030.c b/trunk/sound/soc/codecs/twl4030.c index 8e6e5b016021..63b280b06035 100644 --- a/trunk/sound/soc/codecs/twl4030.c +++ b/trunk/sound/soc/codecs/twl4030.c @@ -41,11 +41,6 @@ /* Register descriptions are here */ #include -/* TWL4030 PMBR1 Register */ -#define TWL4030_PMBR1_REG 0x0D -/* TWL4030 PMBR1 Register GPIO6 mux bits */ -#define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2) - /* Shadow register used by the audio driver */ #define TWL4030_REG_SW_SHADOW 0x4A #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) @@ -353,32 +348,19 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) pdata = twl4030_get_pdata(codec); - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { - int ret; - - if (!pdata->hs_extmute_gpio) - dev_warn(codec->dev, - "Extmute GPIO is 0 is this correct?\n"); - - ret = gpio_request_one(pdata->hs_extmute_gpio, - GPIOF_OUT_INIT_LOW, - "hs_extmute"); - if (ret) { - dev_err(codec->dev, - "Failed to get hs_extmute GPIO\n"); - pdata->hs_extmute_gpio = -1; - } - } else { - u8 pin_mux; - - /* Set TWL4030 GPIO6 as EXTMUTE signal */ - twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, - TWL4030_PMBR1_REG); - pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03); - pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02); - twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, - TWL4030_PMBR1_REG); + if (pdata && pdata->hs_extmute && + gpio_is_valid(pdata->hs_extmute_gpio)) { + int ret; + + if (!pdata->hs_extmute_gpio) + dev_warn(codec->dev, + "Extmute GPIO is 0 is this correct?\n"); + + ret = gpio_request_one(pdata->hs_extmute_gpio, + GPIOF_OUT_INIT_LOW, "hs_extmute"); + if (ret) { + dev_err(codec->dev, "Failed to get hs_extmute GPIO\n"); + pdata->hs_extmute_gpio = -1; } } @@ -1324,9 +1306,6 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC Left2", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC("DAC Voice", NULL, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("VAIFIN", "Voice Playback", 0, - TWL4030_REG_VOICE_IF, 6, 0), - /* Analog bypasses */ SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, &twl4030_dapm_abypassr1_control), @@ -1459,9 +1438,6 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADC Virtual Left2", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADC Virtual Right2", NULL, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("VAIFOUT", "Voice Capture", 0, - TWL4030_REG_VOICE_IF, 5, 0), - /* Analog/Digital mic path selection. TX1 Left/Right: either analog Left/Right or Digimic0 TX2 Left/Right: either analog Left/Right or Digimic1 */ @@ -1497,15 +1473,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0, NULL, 0), - /* Microphone bias */ - SND_SOC_DAPM_SUPPLY("Mic Bias 1", - TWL4030_REG_MICBIAS_CTL, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Mic Bias 2", - TWL4030_REG_MICBIAS_CTL, 1, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headset Mic Bias", - TWL4030_REG_MICBIAS_CTL, 2, 0, NULL, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), + SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0), - SND_SOC_DAPM_SUPPLY("VIF Enable", TWL4030_REG_VOICE_IF, 0, 0, NULL, 0), }; static const struct snd_soc_dapm_route intercon[] = { @@ -1514,16 +1485,17 @@ static const struct snd_soc_dapm_route intercon[] = { {"DAC Left1", NULL, "HiFi Playback"}, {"DAC Right2", NULL, "HiFi Playback"}, {"DAC Left2", NULL, "HiFi Playback"}, - {"DAC Voice", NULL, "VAIFIN"}, + {"DAC Voice", NULL, "Voice Playback"}, /* ADC -> Stream mapping */ {"HiFi Capture", NULL, "ADC Virtual Left1"}, {"HiFi Capture", NULL, "ADC Virtual Right1"}, {"HiFi Capture", NULL, "ADC Virtual Left2"}, {"HiFi Capture", NULL, "ADC Virtual Right2"}, - {"VAIFOUT", NULL, "ADC Virtual Left2"}, - {"VAIFOUT", NULL, "ADC Virtual Right2"}, - {"VAIFOUT", NULL, "VIF Enable"}, + {"Voice Capture", NULL, "ADC Virtual Left1"}, + {"Voice Capture", NULL, "ADC Virtual Right1"}, + {"Voice Capture", NULL, "ADC Virtual Left2"}, + {"Voice Capture", NULL, "ADC Virtual Right2"}, {"Digital L1 Playback Mixer", NULL, "DAC Left1"}, {"Digital R1 Playback Mixer", NULL, "DAC Right1"}, @@ -1538,7 +1510,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"DAC Right1", NULL, "AIF Enable"}, {"DAC Left2", NULL, "AIF Enable"}, {"DAC Right1", NULL, "AIF Enable"}, - {"DAC Voice", NULL, "VIF Enable"}, {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, @@ -2296,6 +2267,18 @@ static struct snd_soc_dai_driver twl4030_dai[] = { }, }; +static int twl4030_soc_suspend(struct snd_soc_codec *codec) +{ + twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int twl4030_soc_resume(struct snd_soc_codec *codec) +{ + twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} + static int twl4030_soc_probe(struct snd_soc_codec *codec) { struct twl4030_priv *twl4030; @@ -2333,6 +2316,8 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { .probe = twl4030_soc_probe, .remove = twl4030_soc_remove, + .suspend = twl4030_soc_suspend, + .resume = twl4030_soc_resume, .read = twl4030_read_reg_cache, .write = twl4030_write, .set_bias_level = twl4030_set_bias_level, diff --git a/trunk/sound/soc/codecs/twl6040.c b/trunk/sound/soc/codecs/twl6040.c index 9b9a6e587610..3fc3fc64dd8b 100644 --- a/trunk/sound/soc/codecs/twl6040.c +++ b/trunk/sound/soc/codecs/twl6040.c @@ -69,8 +69,13 @@ struct twl6040_data { int hs_power_mode_locked; unsigned int clk_in; unsigned int sysclk; + u16 hs_left_step; + u16 hs_right_step; + u16 hf_left_step; + u16 hf_right_step; struct twl6040_jack_data hs_jack; struct snd_soc_codec *codec; + struct workqueue_struct *workqueue; struct mutex mutex; }; @@ -399,7 +404,8 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data) struct snd_soc_codec *codec = data; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - schedule_delayed_work(&priv->hs_jack.work, msecs_to_jiffies(200)); + queue_delayed_work(priv->workqueue, &priv->hs_jack.work, + msecs_to_jiffies(200)); return IRQ_HANDLED; } @@ -1109,6 +1115,7 @@ static int twl6040_suspend(struct snd_soc_codec *codec) static int twl6040_resume(struct snd_soc_codec *codec) { twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + twl6040_set_bias_level(codec, codec->dapm.suspend_bias_level); return 0; } @@ -1120,46 +1127,83 @@ static int twl6040_resume(struct snd_soc_codec *codec) static int twl6040_probe(struct snd_soc_codec *codec) { struct twl6040_data *priv; + struct twl6040_codec_data *pdata = dev_get_platdata(codec->dev); struct platform_device *pdev = container_of(codec->dev, struct platform_device, dev); int ret = 0; - priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - snd_soc_codec_set_drvdata(codec, priv); priv->codec = codec; codec->control_data = dev_get_drvdata(codec->dev->parent); + if (pdata && pdata->hs_left_step && pdata->hs_right_step) { + priv->hs_left_step = pdata->hs_left_step; + priv->hs_right_step = pdata->hs_right_step; + } else { + priv->hs_left_step = 1; + priv->hs_right_step = 1; + } + + if (pdata && pdata->hf_left_step && pdata->hf_right_step) { + priv->hf_left_step = pdata->hf_left_step; + priv->hf_right_step = pdata->hf_right_step; + } else { + priv->hf_left_step = 1; + priv->hf_right_step = 1; + } + priv->plug_irq = platform_get_irq(pdev, 0); if (priv->plug_irq < 0) { dev_err(codec->dev, "invalid irq\n"); - return -EINVAL; + ret = -EINVAL; + goto work_err; + } + + priv->workqueue = alloc_workqueue("twl6040-codec", 0, 0); + if (!priv->workqueue) { + ret = -ENOMEM; + goto work_err; } INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work); mutex_init(&priv->mutex); - ret = devm_request_threaded_irq(codec->dev, priv->plug_irq, NULL, - twl6040_audio_handler, IRQF_NO_SUSPEND, - "twl6040_irq_plug", codec); + ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler, + 0, "twl6040_irq_plug", codec); if (ret) { dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret); - return ret; + goto plugirq_err; } twl6040_init_chip(codec); /* power on device */ - return twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + if (!ret) + return 0; + + /* Error path */ + free_irq(priv->plug_irq, codec); +plugirq_err: + destroy_workqueue(priv->workqueue); +work_err: + kfree(priv); + return ret; } static int twl6040_remove(struct snd_soc_codec *codec) { + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); + free_irq(priv->plug_irq, codec); + destroy_workqueue(priv->workqueue); + kfree(priv); return 0; } diff --git a/trunk/sound/soc/codecs/wm2000.c b/trunk/sound/soc/codecs/wm2000.c index f2ac38b61a1b..12bcae63a7f0 100644 --- a/trunk/sound/soc/codecs/wm2000.c +++ b/trunk/sound/soc/codecs/wm2000.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -63,7 +62,6 @@ enum wm2000_anc_mode { struct wm2000_priv { struct i2c_client *i2c; struct regmap *regmap; - struct clk *mclk; struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES]; @@ -73,12 +71,11 @@ struct wm2000_priv { unsigned int anc_eng_ena:1; unsigned int spk_ena:1; + unsigned int mclk_div:1; unsigned int speech_clarity:1; int anc_download_size; char *anc_download; - - struct mutex lock; }; static int wm2000_write(struct i2c_client *i2c, unsigned int reg, @@ -134,7 +131,6 @@ static int wm2000_poll_bit(struct i2c_client *i2c, static int wm2000_power_up(struct i2c_client *i2c, int analogue) { struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); - unsigned long rate; int ret; BUG_ON(wm2000->anc_mode != ANC_OFF); @@ -147,8 +143,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) return ret; } - rate = clk_get_rate(wm2000->mclk); - if (rate <= 13500000) { + if (!wm2000->mclk_div) { dev_dbg(&i2c->dev, "Disabling MCLK divider\n"); wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_MCLK_DIV2_ENA_CLR); @@ -555,15 +550,6 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, return -EINVAL; } - /* Maintain clock while active */ - if (anc_transitions[i].source == ANC_OFF) { - ret = clk_prepare_enable(wm2000->mclk); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to enable MCLK: %d\n", ret); - return ret; - } - } - for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) { if (!anc_transitions[i].step[j]) break; @@ -573,10 +559,7 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, return ret; } - if (anc_transitions[i].dest == ANC_OFF) - clk_disable_unprepare(wm2000->mclk); - - return ret; + return 0; } static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) @@ -616,20 +599,13 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); int anc_active = ucontrol->value.enumerated.item[0]; - int ret; if (anc_active > 1) return -EINVAL; - mutex_lock(&wm2000->lock); - wm2000->anc_active = anc_active; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, @@ -649,24 +625,16 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); int val = ucontrol->value.enumerated.item[0]; - int ret; if (val > 1) return -EINVAL; - mutex_lock(&wm2000->lock); - wm2000->spk_ena = val; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static const struct snd_kcontrol_new wm2000_controls[] = { - SOC_SINGLE("ANC Volume", WM2000_REG_ANC_GAIN_CTRL, 0, 255, 0), SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0, wm2000_anc_mode_get, wm2000_anc_mode_put), @@ -680,9 +648,6 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = w->codec; struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - int ret; - - mutex_lock(&wm2000->lock); if (SND_SOC_DAPM_EVENT_ON(event)) wm2000->anc_eng_ena = 1; @@ -690,11 +655,7 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, if (SND_SOC_DAPM_EVENT_OFF(event)) wm2000->anc_eng_ena = 0; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { @@ -741,9 +702,6 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { case WM2000_REG_SYS_START: - case WM2000_REG_ANC_GAIN_CTRL: - case WM2000_REG_MSE_TH1: - case WM2000_REG_MSE_TH2: case WM2000_REG_SPEECH_CLARITY: case WM2000_REG_SYS_WATCHDOG: case WM2000_REG_ANA_VMID_PD_TIME: @@ -779,8 +737,6 @@ static int wm2000_probe(struct snd_soc_codec *codec) { struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_REGMAP); - /* This will trigger a transition to standby mode by default */ wm2000_anc_set_mode(wm2000); @@ -826,8 +782,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c, return -ENOMEM; } - mutex_init(&wm2000->lock); - dev_set_drvdata(&i2c->dev, wm2000); wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap); @@ -869,16 +823,10 @@ static int wm2000_i2c_probe(struct i2c_client *i2c, reg = wm2000_read(i2c, WM2000_REG_REVISON); dev_info(&i2c->dev, "revision %c\n", reg + 'A'); - wm2000->mclk = devm_clk_get(&i2c->dev, "MCLK"); - if (IS_ERR(wm2000->mclk)) { - ret = PTR_ERR(wm2000->mclk); - dev_err(&i2c->dev, "Failed to get MCLK: %d\n", ret); - goto err_supplies; - } - filename = "wm2000_anc.bin"; pdata = dev_get_platdata(&i2c->dev); if (pdata) { + wm2000->mclk_div = pdata->mclkdiv2; wm2000->speech_clarity = !pdata->speech_enh_disable; if (pdata->download_file) diff --git a/trunk/sound/soc/codecs/wm2000.h b/trunk/sound/soc/codecs/wm2000.h index fb812cd9e77d..abcd82a93995 100644 --- a/trunk/sound/soc/codecs/wm2000.h +++ b/trunk/sound/soc/codecs/wm2000.h @@ -10,9 +10,6 @@ #define _WM2000_H #define WM2000_REG_SYS_START 0x8000 -#define WM2000_REG_ANC_GAIN_CTRL 0x8fa2 -#define WM2000_REG_MSE_TH2 0x8fdf -#define WM2000_REG_MSE_TH1 0x8fe0 #define WM2000_REG_SPEECH_CLARITY 0x8fef #define WM2000_REG_SYS_WATCHDOG 0x8ff6 #define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7 diff --git a/trunk/sound/soc/codecs/wm2200.c b/trunk/sound/soc/codecs/wm2200.c index ddc98f02ecbd..d8c65f574658 100644 --- a/trunk/sound/soc/codecs/wm2200.c +++ b/trunk/sound/soc/codecs/wm2200.c @@ -1109,16 +1109,6 @@ static int wm2200_mixer_values[] = { static WM2200_MUX_CTL_DECL(name##_aux5); \ static WM2200_MUX_CTL_DECL(name##_aux6); -static const char *wm2200_rxanc_input_sel_texts[] = { - "None", "IN1", "IN2", "IN3", -}; - -static const struct soc_enum wm2200_rxanc_input_sel = - SOC_ENUM_SINGLE(WM2200_RXANC_SRC, - WM2200_IN_RXANC_SEL_SHIFT, - ARRAY_SIZE(wm2200_rxanc_input_sel_texts), - wm2200_rxanc_input_sel_texts); - static const struct snd_kcontrol_new wm2200_snd_controls[] = { SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL, WM2200_IN1_OSR_SHIFT, 1, 0), @@ -1136,9 +1126,9 @@ SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL, SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1), -SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_2L, +SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1), -SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_3L, +SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1), SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L, @@ -1151,12 +1141,6 @@ SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L, WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SND_SOC_BYTES_MASK("EQL Coefficients", WM2200_EQL_1, 20, WM2200_EQL_ENA), -SND_SOC_BYTES_MASK("EQR Coefficients", WM2200_EQR_1, 20, WM2200_EQR_ENA), - -SND_SOC_BYTES("LHPF1 Coefficeints", WM2200_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficeints", WM2200_HPLPF2_2, 1), - SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L, WM2200_OUT1_OSR_SHIFT, 1, 0), SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L, @@ -1178,7 +1162,6 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L, digital_tlv), SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT, WM2200_SPK1R_MUTE_SHIFT, 1, 1), -SOC_ENUM("RxANC Src", wm2200_rxanc_input_sel), }; WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE); @@ -1565,10 +1548,6 @@ static int wm2200_probe(struct snd_soc_codec *codec) return ret; } - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); - if (ret != 0) - return ret; - return ret; } @@ -2203,7 +2182,6 @@ static int wm2200_i2c_probe(struct i2c_client *i2c, struct wm2200_priv *wm2200; unsigned int reg; int ret, i; - int val; wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv), GFP_KERNEL); @@ -2227,9 +2205,6 @@ static int wm2200_i2c_probe(struct i2c_client *i2c, wm2200->dsp[i].num = i + 1; wm2200->dsp[i].dev = &i2c->dev; wm2200->dsp[i].regmap = wm2200->regmap; - wm2200->dsp[i].sysclk_reg = WM2200_CLOCKING_3; - wm2200->dsp[i].sysclk_mask = WM2200_SYSCLK_FREQ_MASK; - wm2200->dsp[i].sysclk_shift = WM2200_SYSCLK_FREQ_SHIFT; } wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1; @@ -2240,9 +2215,6 @@ static int wm2200_i2c_probe(struct i2c_client *i2c, wm2200->dsp[1].mem = wm2200_dsp2_regions; wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions); - for (i = 0; i < ARRAY_SIZE(wm2200->dsp); i++) - wm_adsp1_init(&wm2200->dsp[i]); - if (pdata) wm2200->pdata = *pdata; @@ -2354,36 +2326,6 @@ static int wm2200_i2c_probe(struct i2c_client *i2c, regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i); } - for (i = 0; i < WM2200_MAX_MICBIAS; i++) { - if (!wm2200->pdata.micbias[i].mb_lvl && - !wm2200->pdata.micbias[i].bypass) - continue; - - /* Apply default for bypass mode */ - if (!wm2200->pdata.micbias[i].mb_lvl) - wm2200->pdata.micbias[i].mb_lvl - = WM2200_MBIAS_LVL_1V5; - - val = (wm2200->pdata.micbias[i].mb_lvl -1) - << WM2200_MICB1_LVL_SHIFT; - - if (wm2200->pdata.micbias[i].discharge) - val |= WM2200_MICB1_DISCH; - - if (wm2200->pdata.micbias[i].fast_start) - val |= WM2200_MICB1_RATE; - - if (wm2200->pdata.micbias[i].bypass) - val |= WM2200_MICB1_MODE; - - regmap_update_bits(wm2200->regmap, - WM2200_MIC_BIAS_CTRL_1 + i, - WM2200_MICB1_LVL_MASK | - WM2200_MICB1_DISCH | - WM2200_MICB1_MODE | - WM2200_MICB1_RATE, val); - } - for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) { regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i], WM2200_IN1_MODE_MASK | diff --git a/trunk/sound/soc/codecs/wm5100.c b/trunk/sound/soc/codecs/wm5100.c index ac1745d030d6..54397a508073 100644 --- a/trunk/sound/soc/codecs/wm5100.c +++ b/trunk/sound/soc/codecs/wm5100.c @@ -563,19 +563,6 @@ SOC_DOUBLE_R("IN3 Switch", WM5100_ADC_DIGITAL_VOLUME_3L, SOC_DOUBLE_R("IN4 Switch", WM5100_ADC_DIGITAL_VOLUME_4L, WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_MUTE_SHIFT, 1, 1), -SND_SOC_BYTES_MASK("EQ1 Coefficients", WM5100_EQ1_1, 20, WM5100_EQ1_ENA), -SND_SOC_BYTES_MASK("EQ2 Coefficients", WM5100_EQ2_1, 20, WM5100_EQ2_ENA), -SND_SOC_BYTES_MASK("EQ3 Coefficients", WM5100_EQ3_1, 20, WM5100_EQ3_ENA), -SND_SOC_BYTES_MASK("EQ4 Coefficients", WM5100_EQ4_1, 20, WM5100_EQ4_ENA), - -SND_SOC_BYTES_MASK("DRC Coefficients", WM5100_DRC1_CTRL1, 5, - WM5100_DRCL_ENA | WM5100_DRCR_ENA), - -SND_SOC_BYTES("LHPF1 Coefficeints", WM5100_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficeints", WM5100_HPLPF2_2, 1), -SND_SOC_BYTES("LHPF3 Coefficeints", WM5100_HPLPF3_2, 1), -SND_SOC_BYTES("LHPF4 Coefficeints", WM5100_HPLPF4_2, 1), - SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L, WM5100_OUT1_OSR_SHIFT, 1, 0), SOC_SINGLE("HPOUT2 High Performance Switch", WM5100_OUT_VOLUME_2L, diff --git a/trunk/sound/soc/codecs/wm5102.c b/trunk/sound/soc/codecs/wm5102.c index ab69c83626cd..1440b3f9b7bb 100644 --- a/trunk/sound/soc/codecs/wm5102.c +++ b/trunk/sound/soc/codecs/wm5102.c @@ -45,7 +45,6 @@ static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); -static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); static const struct wm_adsp_region wm5102_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x100000 }, @@ -604,17 +603,6 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } -#define WM5102_NG_SRC(name, base) \ - SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ - SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ - SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \ - SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \ - SOC_SINGLE(name " NG EPOUT Switch", base, 4, 1, 0), \ - SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \ - SOC_SINGLE(name " NG SPKOUTR Switch", base, 7, 1, 0), \ - SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \ - SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0) - static const struct snd_kcontrol_new wm5102_snd_controls[] = { SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT, 1, 0), @@ -623,31 +611,32 @@ SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL, SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT, 1, 0), -SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL, - ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL, - ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL, - ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL, - ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL, - ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL, - ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), - -SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL, + ARIZONA_IN1R_CONTROL, + ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), +SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL, + ARIZONA_IN2R_CONTROL, + ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), +SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL, + ARIZONA_IN3R_CONTROL, + ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), + +SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L, + ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L, + ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), @@ -785,22 +774,6 @@ SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, ARIZONA_SPK1R_MUTE_SHIFT, 1, 1), -SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL, - ARIZONA_NGATE_ENA_SHIFT, 1, 0), -SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL, - ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv), -SOC_ENUM("Noise Gate Hold", arizona_ng_hold), - -WM5102_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L), -WM5102_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R), -WM5102_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L), -WM5102_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R), -WM5102_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L), -WM5102_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L), -WM5102_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R), -WM5102_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L), -WM5102_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R), - ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), @@ -907,18 +880,6 @@ ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); -ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE); -ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE); - -ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE); -ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE); - -ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE); -ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE); - -ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE); -ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE); - ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE); @@ -1041,26 +1002,6 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0, SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3, - ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3, - ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), - -SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3, - ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3, - ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), - -SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3, - ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3, - ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), - -SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3, - ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, - ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, @@ -1197,18 +1138,6 @@ ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"), ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), -ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), -ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), - -ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), -ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), - -ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), -ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), - -ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), -ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), - WM_ADSP2("DSP1", 0), SND_SOC_DAPM_OUTPUT("HPOUT1L"), @@ -1264,14 +1193,6 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"), { name, "ASRC1R", "ASRC1R" }, \ { name, "ASRC2L", "ASRC2L" }, \ { name, "ASRC2R", "ASRC2R" }, \ - { name, "ISRC1DEC1", "ISRC1DEC1" }, \ - { name, "ISRC1DEC2", "ISRC1DEC2" }, \ - { name, "ISRC1INT1", "ISRC1INT1" }, \ - { name, "ISRC1INT2", "ISRC1INT2" }, \ - { name, "ISRC2DEC1", "ISRC2DEC1" }, \ - { name, "ISRC2DEC2", "ISRC2DEC2" }, \ - { name, "ISRC2INT1", "ISRC2INT1" }, \ - { name, "ISRC2INT2", "ISRC2INT2" }, \ { name, "DSP1.1", "DSP1" }, \ { name, "DSP1.2", "DSP1" }, \ { name, "DSP1.3", "DSP1" }, \ @@ -1368,18 +1289,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "ASRC2L", NULL, "ASRC2L Input" }, { "ASRC2R", NULL, "ASRC2R Input" }, - { "ISRC1DEC1", NULL, "ISRC1DEC1 Input" }, - { "ISRC1DEC2", NULL, "ISRC1DEC2 Input" }, - - { "ISRC1INT1", NULL, "ISRC1INT1 Input" }, - { "ISRC1INT2", NULL, "ISRC1INT2 Input" }, - - { "ISRC2DEC1", NULL, "ISRC2DEC1 Input" }, - { "ISRC2DEC2", NULL, "ISRC2DEC2 Input" }, - - { "ISRC2INT1", NULL, "ISRC2INT1 Input" }, - { "ISRC2INT2", NULL, "ISRC2INT2 Input" }, - ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"), @@ -1427,18 +1336,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { ARIZONA_MUX_ROUTES("ASRC2L"), ARIZONA_MUX_ROUTES("ASRC2R"), - ARIZONA_MUX_ROUTES("ISRC1INT1"), - ARIZONA_MUX_ROUTES("ISRC1INT2"), - - ARIZONA_MUX_ROUTES("ISRC1DEC1"), - ARIZONA_MUX_ROUTES("ISRC1DEC2"), - - ARIZONA_MUX_ROUTES("ISRC2INT1"), - ARIZONA_MUX_ROUTES("ISRC2INT2"), - - ARIZONA_MUX_ROUTES("ISRC2DEC1"), - ARIZONA_MUX_ROUTES("ISRC2DEC2"), - ARIZONA_DSP_ROUTES("DSP1"), { "AEC Loopback", "HPOUT1L", "OUT1L" }, @@ -1566,10 +1463,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1); - if (ret != 0) - return ret; - snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); priv->core.arizona->dapm = &codec->dapm; diff --git a/trunk/sound/soc/codecs/wm5110.c b/trunk/sound/soc/codecs/wm5110.c index a1631320b448..7a090968c4f7 100644 --- a/trunk/sound/soc/codecs/wm5110.c +++ b/trunk/sound/soc/codecs/wm5110.c @@ -41,21 +41,6 @@ static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); -static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); - -#define WM5110_NG_SRC(name, base) \ - SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ - SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ - SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \ - SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \ - SOC_SINGLE(name " NG HPOUT3L Switch", base, 4, 1, 0), \ - SOC_SINGLE(name " NG HPOUT3R Switch", base, 5, 1, 0), \ - SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \ - SOC_SINGLE(name " NG SPKOUTR Switch", base, 7, 1, 0), \ - SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \ - SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0), \ - SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \ - SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0) static const struct snd_kcontrol_new wm5110_snd_controls[] = { SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL, @@ -67,35 +52,37 @@ SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL, SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT, 1, 0), -SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL, - ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL, - ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL, - ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL, - ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL, - ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL, - ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), - -SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN4L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L, - ARIZONA_IN4L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R, - ARIZONA_IN4R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL, + ARIZONA_IN1R_CONTROL, + ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), +SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL, + ARIZONA_IN2R_CONTROL, + ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), +SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL, + ARIZONA_IN3R_CONTROL, + ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), + +SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L, + ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("IN4 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_4L, + ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L, + ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("IN4 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L, + ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), @@ -276,25 +263,6 @@ SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT, SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), -SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL, - ARIZONA_NGATE_ENA_SHIFT, 1, 0), -SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL, - ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv), -SOC_ENUM("Noise Gate Hold", arizona_ng_hold), - -WM5110_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L), -WM5110_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R), -WM5110_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L), -WM5110_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R), -WM5110_NG_SRC("HPOUT3L", ARIZONA_NOISE_GATE_SELECT_3L), -WM5110_NG_SRC("HPOUT3R", ARIZONA_NOISE_GATE_SELECT_3R), -WM5110_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L), -WM5110_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R), -WM5110_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L), -WM5110_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R), -WM5110_NG_SRC("SPKDAT2L", ARIZONA_NOISE_GATE_SELECT_6L), -WM5110_NG_SRC("SPKDAT2R", ARIZONA_NOISE_GATE_SELECT_6R), - ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), diff --git a/trunk/sound/soc/codecs/wm8350.c b/trunk/sound/soc/codecs/wm8350.c index ec0efc1443ba..fb92fb47d636 100644 --- a/trunk/sound/soc/codecs/wm8350.c +++ b/trunk/sound/soc/codecs/wm8350.c @@ -283,16 +283,18 @@ static int pga_event(struct snd_soc_dapm_widget *w, out->ramp = WM8350_RAMP_UP; out->active = 1; - schedule_delayed_work(&codec->dapm.delayed_work, - msecs_to_jiffies(1)); + if (!delayed_work_pending(&codec->dapm.delayed_work)) + schedule_delayed_work(&codec->dapm.delayed_work, + msecs_to_jiffies(1)); break; case SND_SOC_DAPM_PRE_PMD: out->ramp = WM8350_RAMP_DOWN; out->active = 0; - schedule_delayed_work(&codec->dapm.delayed_work, - msecs_to_jiffies(1)); + if (!delayed_work_pending(&codec->dapm.delayed_work)) + schedule_delayed_work(&codec->dapm.delayed_work, + msecs_to_jiffies(1)); break; } diff --git a/trunk/sound/soc/codecs/wm8804.c b/trunk/sound/soc/codecs/wm8804.c index 1704b1e119cb..d321a875b029 100644 --- a/trunk/sound/soc/codecs/wm8804.c +++ b/trunk/sound/soc/codecs/wm8804.c @@ -395,6 +395,9 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id, /* power down the PLL before reprogramming it */ snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1); + if (!freq_in || !freq_out) + return 0; + /* set PLLN and PRESCALE */ snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10, pll_div.n | (pll_div.prescale << 4)); diff --git a/trunk/sound/soc/codecs/wm8962.c b/trunk/sound/soc/codecs/wm8962.c index e9710280e5e1..bd4b0db4cdaa 100644 --- a/trunk/sound/soc/codecs/wm8962.c +++ b/trunk/sound/soc/codecs/wm8962.c @@ -2873,20 +2873,22 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, ret = 0; - /* This should be a massive overestimate but go even - * higher if we'll error out - */ - if (wm8962->irq) - timeout = msecs_to_jiffies(5); - else - timeout = msecs_to_jiffies(1); + if (fll1 & WM8962_FLL_ENA) { + /* This should be a massive overestimate but go even + * higher if we'll error out + */ + if (wm8962->irq) + timeout = msecs_to_jiffies(5); + else + timeout = msecs_to_jiffies(1); - timeout = wait_for_completion_timeout(&wm8962->fll_lock, - timeout); + timeout = wait_for_completion_timeout(&wm8962->fll_lock, + timeout); - if (timeout == 0 && wm8962->irq) { - dev_err(codec->dev, "FLL lock timed out"); - ret = -ETIMEDOUT; + if (timeout == 0 && wm8962->irq) { + dev_err(codec->dev, "FLL lock timed out"); + ret = -ETIMEDOUT; + } } wm8962->fll_fref = Fref; @@ -3187,7 +3189,7 @@ static void wm8962_init_beep(struct snd_soc_codec *codec) struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); int ret; - wm8962->beep = devm_input_allocate_device(codec->dev); + wm8962->beep = input_allocate_device(); if (!wm8962->beep) { dev_err(codec->dev, "Failed to allocate beep device\n"); return; @@ -3208,6 +3210,7 @@ static void wm8962_init_beep(struct snd_soc_codec *codec) ret = input_register_device(wm8962->beep); if (ret != 0) { + input_free_device(wm8962->beep); wm8962->beep = NULL; dev_err(codec->dev, "Failed to register beep device\n"); } @@ -3224,6 +3227,7 @@ static void wm8962_free_beep(struct snd_soc_codec *codec) struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); device_remove_file(codec->dev, &dev_attr_beep); + input_unregister_device(wm8962->beep); cancel_work_sync(&wm8962->beep_work); wm8962->beep = NULL; @@ -3754,17 +3758,10 @@ static const struct i2c_device_id wm8962_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id); -static const struct of_device_id wm8962_of_match[] = { - { .compatible = "wlf,wm8962", }, - { } -}; -MODULE_DEVICE_TABLE(of, wm8962_of_match); - static struct i2c_driver wm8962_i2c_driver = { .driver = { .name = "wm8962", .owner = THIS_MODULE, - .of_match_table = wm8962_of_match, .pm = &wm8962_pm, }, .probe = wm8962_i2c_probe, diff --git a/trunk/sound/soc/codecs/wm8983.c b/trunk/sound/soc/codecs/wm8983.c index c9c707b8698f..9fe1e041da49 100644 --- a/trunk/sound/soc/codecs/wm8983.c +++ b/trunk/sound/soc/codecs/wm8983.c @@ -851,33 +851,30 @@ static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id, struct pll_div pll_div; codec = dai->codec; - if (!freq_in || !freq_out) { - /* disable the PLL */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_PLLEN_MASK, 0); - return 0; - } else { + if (freq_in && freq_out) { ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in); if (ret) return ret; - - /* disable the PLL before re-programming it */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_PLLEN_MASK, 0); - - /* set PLLN and PRESCALE */ - snd_soc_write(codec, WM8983_PLL_N, - (pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT) - | pll_div.n); - /* set PLLK */ - snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18)); - /* enable the PLL */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_PLLEN_MASK, WM8983_PLLEN); } + /* disable the PLL before re-programming it */ + snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, + WM8983_PLLEN_MASK, 0); + + if (!freq_in || !freq_out) + return 0; + + /* set PLLN and PRESCALE */ + snd_soc_write(codec, WM8983_PLL_N, + (pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT) + | pll_div.n); + /* set PLLK */ + snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff); + snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff); + snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18)); + /* enable the PLL */ + snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, + WM8983_PLLEN_MASK, WM8983_PLLEN); return 0; } diff --git a/trunk/sound/soc/codecs/wm8985.c b/trunk/sound/soc/codecs/wm8985.c index dd6ce3bc01cf..ab3782657ac8 100644 --- a/trunk/sound/soc/codecs/wm8985.c +++ b/trunk/sound/soc/codecs/wm8985.c @@ -830,30 +830,33 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id, struct pll_div pll_div; codec = dai->codec; - if (!freq_in || !freq_out) { - /* disable the PLL */ - snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1, - WM8985_PLLEN_MASK, 0); - } else { + if (freq_in && freq_out) { ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in); if (ret) return ret; - - /* set PLLN and PRESCALE */ - snd_soc_write(codec, WM8985_PLL_N, - (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT) - | pll_div.n); - /* set PLLK */ - snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18)); - /* set the source of the clock to be the PLL */ - snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL, - WM8985_CLKSEL_MASK, WM8985_CLKSEL); - /* enable the PLL */ - snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1, - WM8985_PLLEN_MASK, WM8985_PLLEN); } + + /* disable the PLL before reprogramming it */ + snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1, + WM8985_PLLEN_MASK, 0); + + if (!freq_in || !freq_out) + return 0; + + /* set PLLN and PRESCALE */ + snd_soc_write(codec, WM8985_PLL_N, + (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT) + | pll_div.n); + /* set PLLK */ + snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff); + snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff); + snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18)); + /* set the source of the clock to be the PLL */ + snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL, + WM8985_CLKSEL_MASK, WM8985_CLKSEL); + /* enable the PLL */ + snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1, + WM8985_PLLEN_MASK, WM8985_PLLEN); return 0; } diff --git a/trunk/sound/soc/codecs/wm8994.c b/trunk/sound/soc/codecs/wm8994.c index c9bd445c4976..3b269fa226bd 100644 --- a/trunk/sound/soc/codecs/wm8994.c +++ b/trunk/sound/soc/codecs/wm8994.c @@ -3737,7 +3737,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; struct snd_soc_codec *codec = wm8994->hubs.codec; - int reg, count, ret; + int reg, count; /* * Jack detection may have detected a removal simulataneously @@ -3783,11 +3783,11 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) /* Avoid a transient report when the accessory is being removed */ if (wm8994->jackdet) { - ret = snd_soc_read(codec, WM1811_JACKDET_CTRL); - if (ret < 0) { + reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); + if (reg < 0) { dev_err(codec->dev, "Failed to read jack status: %d\n", - ret); - } else if (!(ret & WM1811_JACKDET_LVL)) { + reg); + } else if (!(reg & WM1811_JACKDET_LVL)) { dev_dbg(codec->dev, "Ignoring removed jack\n"); return IRQ_HANDLED; } diff --git a/trunk/sound/soc/codecs/wm_adsp.c b/trunk/sound/soc/codecs/wm_adsp.c index f3f7e75f8628..b6b654837585 100644 --- a/trunk/sound/soc/codecs/wm_adsp.c +++ b/trunk/sound/soc/codecs/wm_adsp.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -104,19 +103,9 @@ #define ADSP1_START_SHIFT 0 /* DSP1_START */ #define ADSP1_START_WIDTH 1 /* DSP1_START */ -/* - * ADSP1 Control 31 - */ -#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ -#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ -#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ - -#define ADSP2_CONTROL 0x0 -#define ADSP2_CLOCKING 0x1 -#define ADSP2_STATUS1 0x4 -#define ADSP2_WDMA_CONFIG_1 0x30 -#define ADSP2_WDMA_CONFIG_2 0x31 -#define ADSP2_RDMA_CONFIG_1 0x34 +#define ADSP2_CONTROL 0 +#define ADSP2_CLOCKING 1 +#define ADSP2_STATUS1 4 /* * ADSP2 Control @@ -154,109 +143,6 @@ #define ADSP2_RAM_RDY_SHIFT 0 #define ADSP2_RAM_RDY_WIDTH 1 -struct wm_adsp_buf { - struct list_head list; - void *buf; -}; - -static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, - struct list_head *list) -{ - struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); - - if (buf == NULL) - return NULL; - - buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA); - if (!buf->buf) { - kfree(buf); - return NULL; - } - - if (list) - list_add_tail(&buf->list, list); - - return buf; -} - -static void wm_adsp_buf_free(struct list_head *list) -{ - while (!list_empty(list)) { - struct wm_adsp_buf *buf = list_first_entry(list, - struct wm_adsp_buf, - list); - list_del(&buf->list); - kfree(buf->buf); - kfree(buf); - } -} - -#define WM_ADSP_NUM_FW 4 - -static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { - "MBC/VSS", "Tx", "Tx Speaker", "Rx ANC" -}; - -static struct { - const char *file; -} wm_adsp_fw[WM_ADSP_NUM_FW] = { - { .file = "mbc-vss" }, - { .file = "tx" }, - { .file = "tx-spk" }, - { .file = "rx-anc" }, -}; - -static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = adsp[e->shift_l].fw; - - return 0; -} - -static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); - - if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw) - return 0; - - if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) - return -EINVAL; - - if (adsp[e->shift_l].running) - return -EBUSY; - - adsp[e->shift_l].fw = ucontrol->value.integer.value[0]; - - return 0; -} - -static const struct soc_enum wm_adsp_fw_enum[] = { - SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), - SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), - SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), - SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), -}; - -const struct snd_kcontrol_new wm_adsp_fw_controls[] = { - SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], - wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], - wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], - wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], - wm_adsp_fw_get, wm_adsp_fw_put), -}; -EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, int type) @@ -270,29 +156,8 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, return NULL; } -static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, - unsigned int offset) -{ - switch (region->type) { - case WMFW_ADSP1_PM: - return region->base + (offset * 3); - case WMFW_ADSP1_DM: - return region->base + (offset * 2); - case WMFW_ADSP2_XM: - return region->base + (offset * 2); - case WMFW_ADSP2_YM: - return region->base + (offset * 2); - case WMFW_ADSP1_ZM: - return region->base + (offset * 2); - default: - WARN_ON(NULL != "Unknown memory region type"); - return offset; - } -} - static int wm_adsp_load(struct wm_adsp *dsp) { - LIST_HEAD(buf_list); const struct firmware *firmware; struct regmap *regmap = dsp->regmap; unsigned int pos = 0; @@ -304,7 +169,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) const struct wm_adsp_region *mem; const char *region_name; char *file, *text; - struct wm_adsp_buf *buf; + void *buf; unsigned int reg; int regions = 0; int ret, offset, type, sizes; @@ -313,8 +178,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) if (file == NULL) return -ENOMEM; - snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num, - wm_adsp_fw[dsp->fw].file); + snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num); file[PAGE_SIZE - 1] = '\0'; ret = request_firmware(&firmware, file, dsp->dev); @@ -419,27 +283,27 @@ static int wm_adsp_load(struct wm_adsp *dsp) case WMFW_ADSP1_PM: BUG_ON(!mem); region_name = "PM"; - reg = wm_adsp_region_to_reg(mem, offset); + reg = mem->base + (offset * 3); break; case WMFW_ADSP1_DM: BUG_ON(!mem); region_name = "DM"; - reg = wm_adsp_region_to_reg(mem, offset); + reg = mem->base + (offset * 2); break; case WMFW_ADSP2_XM: BUG_ON(!mem); region_name = "XM"; - reg = wm_adsp_region_to_reg(mem, offset); + reg = mem->base + (offset * 2); break; case WMFW_ADSP2_YM: BUG_ON(!mem); region_name = "YM"; - reg = wm_adsp_region_to_reg(mem, offset); + reg = mem->base + (offset * 2); break; case WMFW_ADSP1_ZM: BUG_ON(!mem); region_name = "ZM"; - reg = wm_adsp_region_to_reg(mem, offset); + reg = mem->base + (offset * 2); break; default: adsp_warn(dsp, @@ -459,16 +323,18 @@ static int wm_adsp_load(struct wm_adsp *dsp) } if (reg) { - buf = wm_adsp_buf_alloc(region->data, - le32_to_cpu(region->len), - &buf_list); + buf = kmemdup(region->data, le32_to_cpu(region->len), + GFP_KERNEL | GFP_DMA); if (!buf) { adsp_err(dsp, "Out of memory\n"); return -ENOMEM; } - ret = regmap_raw_write_async(regmap, reg, buf->buf, - le32_to_cpu(region->len)); + ret = regmap_raw_write(regmap, reg, buf, + le32_to_cpu(region->len)); + + kfree(buf); + if (ret != 0) { adsp_err(dsp, "%s.%d: Failed to write %d bytes at %d in %s: %d\n", @@ -482,20 +348,12 @@ static int wm_adsp_load(struct wm_adsp *dsp) pos += le32_to_cpu(region->len) + sizeof(*region); regions++; } - - ret = regmap_async_complete(regmap); - if (ret != 0) { - adsp_err(dsp, "Failed to complete async write: %d\n", ret); - goto out_fw; - } - + if (pos > firmware->size) adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", file, regions, pos - firmware->size); out_fw: - regmap_async_complete(regmap); - wm_adsp_buf_free(&buf_list); release_firmware(firmware); out: kfree(file); @@ -503,222 +361,22 @@ static int wm_adsp_load(struct wm_adsp *dsp) return ret; } -static int wm_adsp_setup_algs(struct wm_adsp *dsp) -{ - struct regmap *regmap = dsp->regmap; - struct wmfw_adsp1_id_hdr adsp1_id; - struct wmfw_adsp2_id_hdr adsp2_id; - struct wmfw_adsp1_alg_hdr *adsp1_alg; - struct wmfw_adsp2_alg_hdr *adsp2_alg; - void *alg, *buf; - struct wm_adsp_alg_region *region; - const struct wm_adsp_region *mem; - unsigned int pos, term; - size_t algs, buf_size; - __be32 val; - int i, ret; - - switch (dsp->type) { - case WMFW_ADSP1: - mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); - break; - case WMFW_ADSP2: - mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); - break; - default: - mem = NULL; - break; - } - - if (mem == NULL) { - BUG_ON(mem != NULL); - return -EINVAL; - } - - switch (dsp->type) { - case WMFW_ADSP1: - ret = regmap_raw_read(regmap, mem->base, &adsp1_id, - sizeof(adsp1_id)); - if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm info: %d\n", - ret); - return ret; - } - - buf = &adsp1_id; - buf_size = sizeof(adsp1_id); - - algs = be32_to_cpu(adsp1_id.algs); - adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", - be32_to_cpu(adsp1_id.fw.id), - (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, - be32_to_cpu(adsp1_id.fw.ver) & 0xff, - algs); - - pos = sizeof(adsp1_id) / 2; - term = pos + ((sizeof(*adsp1_alg) * algs) / 2); - break; - - case WMFW_ADSP2: - ret = regmap_raw_read(regmap, mem->base, &adsp2_id, - sizeof(adsp2_id)); - if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm info: %d\n", - ret); - return ret; - } - - buf = &adsp2_id; - buf_size = sizeof(adsp2_id); - - algs = be32_to_cpu(adsp2_id.algs); - adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", - be32_to_cpu(adsp2_id.fw.id), - (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, - be32_to_cpu(adsp2_id.fw.ver) & 0xff, - algs); - - pos = sizeof(adsp2_id) / 2; - term = pos + ((sizeof(*adsp2_alg) * algs) / 2); - break; - - default: - BUG_ON(NULL == "Unknown DSP type"); - return -EINVAL; - } - - if (algs == 0) { - adsp_err(dsp, "No algorithms\n"); - return -EINVAL; - } - - if (algs > 1024) { - adsp_err(dsp, "Algorithm count %zx excessive\n", algs); - print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET, - buf, buf_size); - return -EINVAL; - } - - /* Read the terminator first to validate the length */ - ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val)); - if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm list end: %d\n", - ret); - return ret; - } - - if (be32_to_cpu(val) != 0xbedead) - adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", - term, be32_to_cpu(val)); - - alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA); - if (!alg) - return -ENOMEM; - - ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); - if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm list: %d\n", - ret); - goto out; - } - - adsp1_alg = alg; - adsp2_alg = alg; - - for (i = 0; i < algs; i++) { - switch (dsp->type) { - case WMFW_ADSP1: - adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", - i, be32_to_cpu(adsp1_alg[i].alg.id), - (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, - be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, - be32_to_cpu(adsp1_alg[i].dm), - be32_to_cpu(adsp1_alg[i].zm)); - - region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; - region->type = WMFW_ADSP1_DM; - region->alg = be32_to_cpu(adsp1_alg[i].alg.id); - region->base = be32_to_cpu(adsp1_alg[i].dm); - list_add_tail(®ion->list, &dsp->alg_regions); - - region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; - region->type = WMFW_ADSP1_ZM; - region->alg = be32_to_cpu(adsp1_alg[i].alg.id); - region->base = be32_to_cpu(adsp1_alg[i].zm); - list_add_tail(®ion->list, &dsp->alg_regions); - break; - - case WMFW_ADSP2: - adsp_info(dsp, - "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", - i, be32_to_cpu(adsp2_alg[i].alg.id), - (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, - be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, - be32_to_cpu(adsp2_alg[i].xm), - be32_to_cpu(adsp2_alg[i].ym), - be32_to_cpu(adsp2_alg[i].zm)); - - region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; - region->type = WMFW_ADSP2_XM; - region->alg = be32_to_cpu(adsp2_alg[i].alg.id); - region->base = be32_to_cpu(adsp2_alg[i].xm); - list_add_tail(®ion->list, &dsp->alg_regions); - - region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; - region->type = WMFW_ADSP2_YM; - region->alg = be32_to_cpu(adsp2_alg[i].alg.id); - region->base = be32_to_cpu(adsp2_alg[i].ym); - list_add_tail(®ion->list, &dsp->alg_regions); - - region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; - region->type = WMFW_ADSP2_ZM; - region->alg = be32_to_cpu(adsp2_alg[i].alg.id); - region->base = be32_to_cpu(adsp2_alg[i].zm); - list_add_tail(®ion->list, &dsp->alg_regions); - break; - } - } - -out: - kfree(alg); - return ret; -} - static int wm_adsp_load_coeff(struct wm_adsp *dsp) { - LIST_HEAD(buf_list); struct regmap *regmap = dsp->regmap; struct wmfw_coeff_hdr *hdr; struct wmfw_coeff_item *blk; const struct firmware *firmware; - const struct wm_adsp_region *mem; - struct wm_adsp_alg_region *alg_region; const char *region_name; int ret, pos, blocks, type, offset, reg; char *file; - struct wm_adsp_buf *buf; - int tmp; + void *buf; file = kzalloc(PAGE_SIZE, GFP_KERNEL); if (file == NULL) return -ENOMEM; - snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num, - wm_adsp_fw[dsp->fw].file); + snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num); file[PAGE_SIZE - 1] = '\0'; ret = request_firmware(&firmware, file, dsp->dev); @@ -741,16 +399,6 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) goto out_fw; } - switch (be32_to_cpu(hdr->rev) & 0xff) { - case 1: - break; - default: - adsp_err(dsp, "%s: Unsupported coefficient file format %d\n", - file, be32_to_cpu(hdr->rev) & 0xff); - ret = -EINVAL; - goto out_fw; - } - adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, (le32_to_cpu(hdr->ver) >> 16) & 0xff, (le32_to_cpu(hdr->ver) >> 8) & 0xff, @@ -763,8 +411,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) pos - firmware->size > sizeof(*blk)) { blk = (void*)(&firmware->data[pos]); - type = le16_to_cpu(blk->type); - offset = le16_to_cpu(blk->offset); + type = be32_to_cpu(blk->type) & 0xff; + offset = le32_to_cpu(blk->offset) & 0xffffff; adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", file, blocks, le32_to_cpu(blk->id), @@ -777,105 +425,52 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) reg = 0; region_name = "Unknown"; switch (type) { - case (WMFW_NAME_TEXT << 8): - case (WMFW_INFO_TEXT << 8): + case WMFW_NAME_TEXT: + case WMFW_INFO_TEXT: break; - case (WMFW_ABSOLUTE << 8): + case WMFW_ABSOLUTE: region_name = "register"; reg = offset; break; - - case WMFW_ADSP1_DM: - case WMFW_ADSP1_ZM: - case WMFW_ADSP2_XM: - case WMFW_ADSP2_YM: - adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", - file, blocks, le32_to_cpu(blk->len), - type, le32_to_cpu(blk->id)); - - mem = wm_adsp_find_region(dsp, type); - if (!mem) { - adsp_err(dsp, "No base for region %x\n", type); - break; - } - - reg = 0; - list_for_each_entry(alg_region, - &dsp->alg_regions, list) { - if (le32_to_cpu(blk->id) == alg_region->alg && - type == alg_region->type) { - reg = alg_region->base; - reg = wm_adsp_region_to_reg(mem, - reg); - reg += offset; - } - } - - if (reg == 0) - adsp_err(dsp, "No %x for algorithm %x\n", - type, le32_to_cpu(blk->id)); - break; - default: - adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", - file, blocks, type, pos); + adsp_err(dsp, "Unknown region type %x\n", type); break; } if (reg) { - buf = wm_adsp_buf_alloc(blk->data, - le32_to_cpu(blk->len), - &buf_list); + buf = kmemdup(blk->data, le32_to_cpu(blk->len), + GFP_KERNEL | GFP_DMA); if (!buf) { adsp_err(dsp, "Out of memory\n"); return -ENOMEM; } - adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", - file, blocks, le32_to_cpu(blk->len), - reg); - ret = regmap_raw_write_async(regmap, reg, buf->buf, - le32_to_cpu(blk->len)); + ret = regmap_raw_write(regmap, reg, blk->data, + le32_to_cpu(blk->len)); if (ret != 0) { adsp_err(dsp, "%s.%d: Failed to write to %x in %s\n", file, blocks, reg, region_name); } - } - tmp = le32_to_cpu(blk->len) % 4; - if (tmp) - pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk); - else - pos += le32_to_cpu(blk->len) + sizeof(*blk); + kfree(buf); + } + pos += le32_to_cpu(blk->len) + sizeof(*blk); blocks++; } - ret = regmap_async_complete(regmap); - if (ret != 0) - adsp_err(dsp, "Failed to complete async write: %d\n", ret); - if (pos > firmware->size) adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", file, blocks, pos - firmware->size); out_fw: release_firmware(firmware); - wm_adsp_buf_free(&buf_list); out: kfree(file); return 0; } -int wm_adsp1_init(struct wm_adsp *adsp) -{ - INIT_LIST_HEAD(&adsp->alg_regions); - - return 0; -} -EXPORT_SYMBOL_GPL(wm_adsp1_init); - int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -884,46 +479,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; int ret; - int val; switch (event) { case SND_SOC_DAPM_POST_PMU: regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_SYS_ENA, ADSP1_SYS_ENA); - /* - * For simplicity set the DSP clock rate to be the - * SYSCLK rate rather than making it configurable. - */ - if(dsp->sysclk_reg) { - ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); - if (ret != 0) { - adsp_err(dsp, "Failed to read SYSCLK state: %d\n", - ret); - return ret; - } - - val = (val & dsp->sysclk_mask) - >> dsp->sysclk_shift; - - ret = regmap_update_bits(dsp->regmap, - dsp->base + ADSP1_CONTROL_31, - ADSP1_CLK_SEL_MASK, val); - if (ret != 0) { - adsp_err(dsp, "Failed to set clock rate: %d\n", - ret); - return ret; - } - } - ret = wm_adsp_load(dsp); if (ret != 0) goto err; - ret = wm_adsp_setup_algs(dsp); - if (ret != 0) - goto err; - ret = wm_adsp_load_coeff(dsp); if (ret != 0) goto err; @@ -995,7 +560,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = w->codec; struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; - struct wm_adsp_alg_region *alg_region; unsigned int val; int ret; @@ -1061,10 +625,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, if (ret != 0) goto err; - ret = wm_adsp_setup_algs(dsp); - if (ret != 0) - goto err; - ret = wm_adsp_load_coeff(dsp); if (ret != 0) goto err; @@ -1075,22 +635,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ADSP2_CORE_ENA | ADSP2_START); if (ret != 0) goto err; - - dsp->running = true; break; case SND_SOC_DAPM_PRE_PMD: - dsp->running = false; - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); - /* Make sure DMAs are quiesced */ - regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); - regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); - regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); - if (dsp->dvfs) { ret = regulator_set_voltage(dsp->dvfs, 1200000, 1800000); @@ -1105,14 +656,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, "Failed to enable supply: %d\n", ret); } - - while (!list_empty(&dsp->alg_regions)) { - alg_region = list_first_entry(&dsp->alg_regions, - struct wm_adsp_alg_region, - list); - list_del(&alg_region->list); - kfree(alg_region); - } break; default: @@ -1142,8 +685,6 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) return ret; } - INIT_LIST_HEAD(&adsp->alg_regions); - if (dvfs) { adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); if (IS_ERR(adsp->dvfs)) { diff --git a/trunk/sound/soc/codecs/wm_adsp.h b/trunk/sound/soc/codecs/wm_adsp.h index cb8871a3ec00..ffd29a4609e2 100644 --- a/trunk/sound/soc/codecs/wm_adsp.h +++ b/trunk/sound/soc/codecs/wm_adsp.h @@ -25,13 +25,6 @@ struct wm_adsp_region { unsigned int base; }; -struct wm_adsp_alg_region { - struct list_head list; - unsigned int alg; - int type; - unsigned int base; -}; - struct wm_adsp { const char *part; int num; @@ -40,18 +33,10 @@ struct wm_adsp { struct regmap *regmap; int base; - int sysclk_reg; - int sysclk_mask; - int sysclk_shift; - - struct list_head alg_regions; const struct wm_adsp_region *mem; int num_mems; - int fw; - bool running; - struct regulator *dvfs; }; @@ -65,9 +50,6 @@ struct wm_adsp { .shift = num, .event = wm_adsp2_event, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } -extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; - -int wm_adsp1_init(struct wm_adsp *adsp); int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); diff --git a/trunk/sound/soc/codecs/wmfw.h b/trunk/sound/soc/codecs/wmfw.h index ef163360a745..5632ded67fdd 100644 --- a/trunk/sound/soc/codecs/wmfw.h +++ b/trunk/sound/soc/codecs/wmfw.h @@ -93,20 +93,15 @@ struct wmfw_adsp2_alg_hdr { struct wmfw_coeff_hdr { u8 magic[4]; __le32 len; - union { - __be32 rev; - __le32 ver; - }; - union { - __be32 core; - __le32 core_ver; - }; + __le32 ver; u8 data[]; } __packed; struct wmfw_coeff_item { - __le16 offset; - __le16 type; + union { + __be32 type; + __le32 offset; + }; __le32 id; __le32 ver; __le32 sr; diff --git a/trunk/sound/soc/davinci/davinci-evm.c b/trunk/sound/soc/davinci/davinci-evm.c index 484b22c5df5d..d55e6477bff0 100644 --- a/trunk/sound/soc/davinci/davinci-evm.c +++ b/trunk/sound/soc/davinci/davinci-evm.c @@ -116,9 +116,9 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Line Out", NULL, "RLOUT"}, /* Mic connected to (MIC3L | MIC3R) */ - {"MIC3L", NULL, "Mic Bias"}, - {"MIC3R", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Mic Jack"}, + {"MIC3L", NULL, "Mic Bias 2V"}, + {"MIC3R", NULL, "Mic Bias 2V"}, + {"Mic Bias 2V", NULL, "Mic Jack"}, /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ {"LINE1L", NULL, "Line In"}, diff --git a/trunk/sound/soc/davinci/davinci-mcasp.c b/trunk/sound/soc/davinci/davinci-mcasp.c index 9321e5c9d8c1..55e2bf652bef 100644 --- a/trunk/sound/soc/davinci/davinci-mcasp.c +++ b/trunk/sound/soc/davinci/davinci-mcasp.c @@ -626,7 +626,7 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, int word_length) { u32 fmt; - u32 rotate = (word_length / 4) & 0x7; + u32 rotate = (32 - word_length) / 4; u32 mask = (1ULL << word_length) - 1; /* diff --git a/trunk/sound/soc/dwc/designware_i2s.c b/trunk/sound/soc/dwc/designware_i2s.c index deb30d59965e..1aa51300c564 100644 --- a/trunk/sound/soc/dwc/designware_i2s.c +++ b/trunk/sound/soc/dwc/designware_i2s.c @@ -210,19 +210,15 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, switch (config->chan_nr) { case EIGHT_CHANNEL_SUPPORT: ch_reg = 3; - break; case SIX_CHANNEL_SUPPORT: ch_reg = 2; - break; case FOUR_CHANNEL_SUPPORT: ch_reg = 1; - break; case TWO_CHANNEL_SUPPORT: ch_reg = 0; break; default: dev_err(dev->dev, "channel not supported\n"); - return -EINVAL; } i2s_disable_channels(dev, substream->stream); diff --git a/trunk/sound/soc/fsl/imx-audmux.c b/trunk/sound/soc/fsl/imx-audmux.c index fab912ea7a50..251f4d981e0c 100644 --- a/trunk/sound/soc/fsl/imx-audmux.c +++ b/trunk/sound/soc/fsl/imx-audmux.c @@ -176,7 +176,7 @@ static inline void audmux_debugfs_remove(void) } #endif -static enum imx_audmux_type { +enum imx_audmux_type { IMX21_AUDMUX, IMX31_AUDMUX, } audmux_type; diff --git a/trunk/sound/soc/generic/simple-card.c b/trunk/sound/soc/generic/simple-card.c index 6cf8355a8542..b4b4cab30232 100644 --- a/trunk/sound/soc/generic/simple-card.c +++ b/trunk/sound/soc/generic/simple-card.c @@ -16,38 +16,33 @@ #define asoc_simple_get_card_info(p) \ container_of(p->dai_link, struct asoc_simple_card_info, snd_link) -static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, - struct asoc_simple_dai *set, - unsigned int daifmt) -{ - int ret = 0; - - daifmt |= set->fmt; - - if (!ret && daifmt) - ret = snd_soc_dai_set_fmt(dai, daifmt); - - if (!ret && set->sysclk) - ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); - - return ret; -} - static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct asoc_simple_card_info *info = asoc_simple_get_card_info(rtd); + struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd); + struct asoc_simple_dai_init_info *iinfo = cinfo->init; struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; - unsigned int daifmt = info->daifmt; + unsigned int cpu_daifmt = iinfo->fmt | iinfo->cpu_daifmt; + unsigned int codec_daifmt = iinfo->fmt | iinfo->codec_daifmt; int ret; - ret = __asoc_simple_card_dai_init(codec, &info->codec_dai, daifmt); - if (ret < 0) - return ret; + if (codec_daifmt) { + ret = snd_soc_dai_set_fmt(codec, codec_daifmt); + if (ret < 0) + return ret; + } + + if (iinfo->sysclk) { + ret = snd_soc_dai_set_sysclk(codec, 0, iinfo->sysclk, 0); + if (ret < 0) + return ret; + } - ret = __asoc_simple_card_dai_init(cpu, &info->cpu_dai, daifmt); - if (ret < 0) - return ret; + if (cpu_daifmt) { + ret = snd_soc_dai_set_fmt(cpu, cpu_daifmt); + if (ret < 0) + return ret; + } return 0; } @@ -55,20 +50,19 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_probe(struct platform_device *pdev) { struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; - struct device *dev = &pdev->dev; if (!cinfo) { - dev_err(dev, "no info for asoc-simple-card\n"); + dev_err(&pdev->dev, "no info for asoc-simple-card\n"); return -EINVAL; } if (!cinfo->name || !cinfo->card || + !cinfo->cpu_dai || !cinfo->codec || !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { - dev_err(dev, "insufficient asoc_simple_card_info settings\n"); + !cinfo->codec_dai) { + dev_err(&pdev->dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -77,11 +71,14 @@ static int asoc_simple_card_probe(struct platform_device *pdev) */ cinfo->snd_link.name = cinfo->name; cinfo->snd_link.stream_name = cinfo->name; - cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai.name; + cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai; cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; - cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; - cinfo->snd_link.init = asoc_simple_card_dai_init; + cinfo->snd_link.codec_dai_name = cinfo->codec_dai; + + /* enable snd_link.init if cinfo has settings */ + if (cinfo->init) + cinfo->snd_link.init = asoc_simple_card_dai_init; /* * init snd_soc_card diff --git a/trunk/sound/soc/mxs/mxs-saif.c b/trunk/sound/soc/mxs/mxs-saif.c index e70e6c844f96..365d9d27a321 100644 --- a/trunk/sound/soc/mxs/mxs-saif.c +++ b/trunk/sound/soc/mxs/mxs-saif.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -661,40 +662,46 @@ static int mxs_saif_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct resource *iores, *dmares; struct mxs_saif *saif; + struct mxs_saif_platform_data *pdata; struct pinctrl *pinctrl; int ret = 0; - struct device_node *master; - if (!np) + + if (!np && pdev->id >= ARRAY_SIZE(mxs_saif)) return -EINVAL; saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL); if (!saif) return -ENOMEM; - ret = of_alias_get_id(np, "saif"); - if (ret < 0) - return ret; - else - saif->id = ret; - - /* - * If there is no "fsl,saif-master" phandle, it's a saif - * master. Otherwise, it's a slave and its phandle points - * to the master. - */ - master = of_parse_phandle(np, "fsl,saif-master", 0); - if (!master) { - saif->master_id = saif->id; + if (np) { + struct device_node *master; + saif->id = of_alias_get_id(np, "saif"); + if (saif->id < 0) + return saif->id; + /* + * If there is no "fsl,saif-master" phandle, it's a saif + * master. Otherwise, it's a slave and its phandle points + * to the master. + */ + master = of_parse_phandle(np, "fsl,saif-master", 0); + if (!master) { + saif->master_id = saif->id; + } else { + saif->master_id = of_alias_get_id(master, "saif"); + if (saif->master_id < 0) + return saif->master_id; + } } else { - ret = of_alias_get_id(master, "saif"); - if (ret < 0) - return ret; + saif->id = pdev->id; + pdata = pdev->dev.platform_data; + if (pdata && !pdata->master_mode) + saif->master_id = pdata->master_id; else - saif->master_id = ret; + saif->master_id = saif->id; } - if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { + if (saif->master_id < 0 || saif->master_id >= ARRAY_SIZE(mxs_saif)) { dev_err(&pdev->dev, "get wrong master id\n"); return -EINVAL; } diff --git a/trunk/sound/soc/omap/Kconfig b/trunk/sound/soc/omap/Kconfig index 60259f2f3f2c..7048137f9a33 100644 --- a/trunk/sound/soc/omap/Kconfig +++ b/trunk/sound/soc/omap/Kconfig @@ -70,6 +70,15 @@ config SND_OMAP_SOC_AM3517EVM Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 EVM. +config SND_OMAP_SOC_SDP3430 + tristate "SoC Audio support for Texas Instruments SDP3430" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on Texas Instruments + SDP3430. + config SND_OMAP_SOC_OMAP_TWL4030 tristate "SoC Audio support for TI SoC based boards with twl4030 codec" depends on TWL4030_CORE && SND_OMAP_SOC @@ -82,8 +91,6 @@ config SND_OMAP_SOC_OMAP_TWL4030 - Gumstix Overo or CompuLab CM-T35/CM-T3730 - IGEP v2 - OMAP3EVM - - SDP3430 - - Zoom2 config SND_OMAP_SOC_OMAP_ABE_TWL6040 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" @@ -116,3 +123,11 @@ config SND_OMAP_SOC_OMAP3_PANDORA select SND_SOC_TWL4030 help Say Y if you want to add support for SoC audio on the OMAP3 Pandora. + +config SND_OMAP_SOC_ZOOM2 + tristate "SoC Audio support for Zoom2" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2 + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for Soc audio on Zoom2 board. diff --git a/trunk/sound/soc/omap/Makefile b/trunk/sound/soc/omap/Makefile index 2b225945359b..19637e55ea48 100644 --- a/trunk/sound/soc/omap/Makefile +++ b/trunk/sound/soc/omap/Makefile @@ -17,9 +17,11 @@ snd-soc-rx51-objs := rx51.o snd-soc-ams-delta-objs := ams-delta.o snd-soc-osk5912-objs := osk5912.o snd-soc-am3517evm-objs := am3517evm.o +snd-soc-sdp3430-objs := sdp3430.o snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o snd-soc-omap-twl4030-objs := omap-twl4030.o snd-soc-omap3pandora-objs := omap3pandora.o +snd-soc-zoom2-objs := zoom2.o snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o @@ -28,7 +30,9 @@ obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o +obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o +obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o diff --git a/trunk/sound/soc/omap/n810.c b/trunk/sound/soc/omap/n810.c index ee7cd53aa3ee..230b8c144848 100644 --- a/trunk/sound/soc/omap/n810.c +++ b/trunk/sound/soc/omap/n810.c @@ -230,8 +230,8 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Ext Spk", NULL, "LLOUT"}, {"Ext Spk", NULL, "RLOUT"}, - {"DMic Rate 64", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "DMic"}, + {"DMic Rate 64", NULL, "Mic Bias 2V"}, + {"Mic Bias 2V", NULL, "DMic"}, }; static const char *spk_function[] = {"Off", "On"}; diff --git a/trunk/sound/soc/omap/omap-hdmi.c b/trunk/sound/soc/omap/omap-hdmi.c index 32fa840c493e..7ea24819d570 100644 --- a/trunk/sound/soc/omap/omap-hdmi.c +++ b/trunk/sound/soc/omap/omap-hdmi.c @@ -110,8 +110,6 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, /* * fill the IEC-60958 channel status word */ - /* initialize the word bytes */ - memset(iec->status, 0, sizeof(iec->status)); /* specify IEC-60958-3 (commercial use) */ iec->status[0] &= ~IEC958_AES0_PROFESSIONAL; diff --git a/trunk/sound/soc/omap/omap-mcpdm.c b/trunk/sound/soc/omap/omap-mcpdm.c index 5ca11bdac21e..2fe8be209452 100644 --- a/trunk/sound/soc/omap/omap-mcpdm.c +++ b/trunk/sound/soc/omap/omap-mcpdm.c @@ -449,6 +449,10 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA; omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -ENOMEM; + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link"); if (!res) return -ENODEV; diff --git a/trunk/sound/soc/omap/omap-pcm.c b/trunk/sound/soc/omap/omap-pcm.c index c722c2ef9665..47bdbd415ad8 100644 --- a/trunk/sound/soc/omap/omap-pcm.c +++ b/trunk/sound/soc/omap/omap-pcm.c @@ -174,15 +174,23 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream) static int omap_pcm_open(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct omap_pcm_dma_data *dma_data; + int ret; snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware); - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + /* 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) + return ret; - return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn, - &dma_data->dma_req); + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + ret = snd_dmaengine_pcm_open(substream, omap_dma_filter_fn, + &dma_data->dma_req); + return ret; } static int omap_pcm_close(struct snd_pcm_substream *substream) diff --git a/trunk/sound/soc/omap/omap-twl4030.c b/trunk/sound/soc/omap/omap-twl4030.c index fd98509d0f49..4541d28b5314 100644 --- a/trunk/sound/soc/omap/omap-twl4030.c +++ b/trunk/sound/soc/omap/omap-twl4030.c @@ -11,8 +11,6 @@ * omap3evm (Author: Anuj Aggarwal ) * overo (Author: Steve Sakoman ) * igep0020 (Author: Enric Balletbo i Serra ) - * zoom2 (Author: Misael Lopez Cruz ) - * sdp3430 (Author: Misael Lopez Cruz ) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,22 +32,14 @@ #include #include #include -#include -#include #include #include #include -#include #include "omap-mcbsp.h" #include "omap-pcm.h" -struct omap_twl4030 { - int jack_detect; /* board can detect jack events */ - struct snd_soc_jack hs_jack; -}; - static int omap_twl4030_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -97,164 +87,17 @@ static struct snd_soc_ops omap_twl4030_ops = { .hw_params = omap_twl4030_hw_params, }; -static const struct snd_soc_dapm_widget dapm_widgets[] = { - SND_SOC_DAPM_SPK("Earpiece Spk", NULL), - SND_SOC_DAPM_SPK("Handsfree Spk", NULL), - SND_SOC_DAPM_HP("Headset Stereophone", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), - SND_SOC_DAPM_SPK("Carkit Spk", NULL), - - SND_SOC_DAPM_MIC("Main Mic", NULL), - SND_SOC_DAPM_MIC("Sub Mic", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Carkit Mic", NULL), - SND_SOC_DAPM_MIC("Digital0 Mic", NULL), - SND_SOC_DAPM_MIC("Digital1 Mic", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Headset Stereophone: HSOL, HSOR */ - {"Headset Stereophone", NULL, "HSOL"}, - {"Headset Stereophone", NULL, "HSOR"}, - /* External Speakers: HFL, HFR */ - {"Handsfree Spk", NULL, "HFL"}, - {"Handsfree Spk", NULL, "HFR"}, - /* External Speakers: PredrivL, PredrivR */ - {"Ext Spk", NULL, "PREDRIVEL"}, - {"Ext Spk", NULL, "PREDRIVER"}, - /* Carkit speakers: CARKITL, CARKITR */ - {"Carkit Spk", NULL, "CARKITL"}, - {"Carkit Spk", NULL, "CARKITR"}, - /* Earpiece */ - {"Earpiece Spk", NULL, "EARPIECE"}, - - /* External Mics: MAINMIC, SUBMIC with bias */ - {"MAINMIC", NULL, "Main Mic"}, - {"Main Mic", NULL, "Mic Bias 1"}, - {"SUBMIC", NULL, "Sub Mic"}, - {"Sub Mic", NULL, "Mic Bias 2"}, - /* Headset Mic: HSMIC with bias */ - {"HSMIC", NULL, "Headset Mic"}, - {"Headset Mic", NULL, "Headset Mic Bias"}, - /* Digital Mics: DIGIMIC0, DIGIMIC1 with bias */ - {"DIGIMIC0", NULL, "Digital0 Mic"}, - {"Digital0 Mic", NULL, "Mic Bias 1"}, - {"DIGIMIC1", NULL, "Digital1 Mic"}, - {"Digital1 Mic", NULL, "Mic Bias 2"}, - /* Carkit In: CARKITMIC */ - {"CARKITMIC", NULL, "Carkit Mic"}, - /* Aux In: AUXL, AUXR */ - {"AUXL", NULL, "Line In"}, - {"AUXR", NULL, "Line In"}, -}; - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin hs_jack_pins[] = { - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headset Stereophone", - .mask = SND_JACK_HEADPHONE, - }, -}; - -/* Headset jack detection gpios */ -static struct snd_soc_jack_gpio hs_jack_gpios[] = { - { - .name = "hsdet-gpio", - .report = SND_JACK_HEADSET, - .debounce_time = 200, - }, -}; - -static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm, - int connected, char *pin) -{ - if (!connected) - snd_soc_dapm_disable_pin(dapm, pin); -} - -static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_card *card = codec->card; - struct snd_soc_dapm_context *dapm = &codec->dapm; - struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev); - struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* Headset jack detection only if it is supported */ - if (priv->jack_detect > 0) { - hs_jack_gpios[0].gpio = priv->jack_detect; - - ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, - &priv->hs_jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&priv->hs_jack, - ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); - if (ret) - return ret; - - ret = snd_soc_jack_add_gpios(&priv->hs_jack, - ARRAY_SIZE(hs_jack_gpios), - hs_jack_gpios); - if (ret) - return ret; - } - - /* - * NULL pdata means we booted with DT. In this case the routing is - * provided and the card is fully routed, no need to mark pins. - */ - if (!pdata || !pdata->custom_routing) - return ret; - - /* Disable not connected paths if not used */ - twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk"); - twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk"); - twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); - twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk"); - twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk"); - - twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic"); - twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic"); - twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); - twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic"); - twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic"); - twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic"); - twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In"); - - return ret; -} - /* Digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link omap_twl4030_dai_links[] = { { - .name = "TWL4030 HiFi", - .stream_name = "TWL4030 HiFi", + .name = "TWL4030", + .stream_name = "TWL4030", .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", - .init = omap_twl4030_init, .ops = &omap_twl4030_ops, }, - { - .name = "TWL4030 Voice", - .stream_name = "TWL4030 Voice", - .cpu_dai_name = "omap-mcbsp.3", - .codec_dai_name = "twl4030-voice", - .platform_name = "omap-pcm-audio", - .codec_name = "twl4030-codec", - .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM, - }, }; /* Audio machine driver */ @@ -262,11 +105,6 @@ static struct snd_soc_card omap_twl4030_card = { .owner = THIS_MODULE, .dai_link = omap_twl4030_dai_links, .num_links = ARRAY_SIZE(omap_twl4030_dai_links), - - .dapm_widgets = dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), }; static int omap_twl4030_probe(struct platform_device *pdev) @@ -274,18 +112,12 @@ static int omap_twl4030_probe(struct platform_device *pdev) struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct snd_soc_card *card = &omap_twl4030_card; - struct omap_twl4030 *priv; int ret = 0; card->dev = &pdev->dev; - priv = devm_kzalloc(&pdev->dev, sizeof(struct omap_twl4030), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - if (node) { struct device_node *dai_node; - struct property *prop; if (snd_soc_of_parse_card_name(card, "ti,model")) { dev_err(&pdev->dev, "Card name is not provided\n"); @@ -300,27 +132,6 @@ static int omap_twl4030_probe(struct platform_device *pdev) omap_twl4030_dai_links[0].cpu_dai_name = NULL; omap_twl4030_dai_links[0].cpu_of_node = dai_node; - dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0); - if (!dai_node) { - card->num_links = 1; - } else { - omap_twl4030_dai_links[1].cpu_dai_name = NULL; - omap_twl4030_dai_links[1].cpu_of_node = dai_node; - } - - priv->jack_detect = of_get_named_gpio(node, - "ti,jack-det-gpio", 0); - - /* Optional: audio routing can be provided */ - prop = of_find_property(node, "ti,audio-routing", NULL); - if (prop) { - ret = snd_soc_of_parse_audio_routing(card, - "ti,audio-routing"); - if (ret) - return ret; - - card->fully_routed = 1; - } } else if (pdata) { if (pdata->card_name) { card->name = pdata->card_name; @@ -328,17 +139,11 @@ static int omap_twl4030_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Card name is not provided\n"); return -ENODEV; } - - if (!pdata->voice_connected) - card->num_links = 1; - - priv->jack_detect = pdata->jack_detect; } else { dev_err(&pdev->dev, "Missing pdata\n"); return -ENODEV; } - snd_soc_card_set_drvdata(card, priv); ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", @@ -352,12 +157,7 @@ static int omap_twl4030_probe(struct platform_device *pdev) static int omap_twl4030_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); - if (priv->jack_detect > 0) - snd_soc_jack_free_gpios(&priv->hs_jack, - ARRAY_SIZE(hs_jack_gpios), - hs_jack_gpios); snd_soc_unregister_card(card); return 0; diff --git a/trunk/sound/soc/omap/omap3pandora.c b/trunk/sound/soc/omap/omap3pandora.c index 805512f2555a..43d950a79ff9 100644 --- a/trunk/sound/soc/omap/omap3pandora.c +++ b/trunk/sound/soc/omap/omap3pandora.c @@ -144,11 +144,11 @@ static const struct snd_soc_dapm_route omap3pandora_in_map[] = { {"AUXL", NULL, "Line In"}, {"AUXR", NULL, "Line In"}, - {"MAINMIC", NULL, "Mic (internal)"}, - {"Mic (internal)", NULL, "Mic Bias 1"}, + {"MAINMIC", NULL, "Mic Bias 1"}, + {"Mic Bias 1", NULL, "Mic (internal)"}, - {"SUBMIC", NULL, "Mic (external)"}, - {"Mic (external)", NULL, "Mic Bias 2"}, + {"SUBMIC", NULL, "Mic Bias 2"}, + {"Mic Bias 2", NULL, "Mic (external)"}, }; static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) diff --git a/trunk/sound/soc/omap/rx51.c b/trunk/sound/soc/omap/rx51.c index 3cd525748975..d921ddbe3ecb 100644 --- a/trunk/sound/soc/omap/rx51.c +++ b/trunk/sound/soc/omap/rx51.c @@ -248,16 +248,16 @@ static const struct snd_soc_dapm_route audio_map[] = { {"FM Transmitter", NULL, "LLOUT"}, {"FM Transmitter", NULL, "RLOUT"}, - {"DMic Rate 64", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "DMic"}, + {"DMic Rate 64", NULL, "Mic Bias 2V"}, + {"Mic Bias 2V", NULL, "DMic"}, }; static const struct snd_soc_dapm_route audio_mapb[] = { {"b LINE2R", NULL, "MONO_LOUT"}, {"Earphone", NULL, "b HPLOUT"}, - {"LINE1L", NULL, "b Mic Bias"}, - {"b Mic Bias", NULL, "HS Mic"} + {"LINE1L", NULL, "b Mic Bias 2.5V"}, + {"b Mic Bias 2.5V", NULL, "HS Mic"} }; static const char *spk_function[] = {"Off", "On"}; diff --git a/trunk/sound/soc/omap/sdp3430.c b/trunk/sound/soc/omap/sdp3430.c new file mode 100644 index 000000000000..b462a2c9385f --- /dev/null +++ b/trunk/sound/soc/omap/sdp3430.c @@ -0,0 +1,278 @@ +/* + * sdp3430.c -- SoC audio for TI OMAP3430 SDP + * + * Author: Misael Lopez Cruz + * + * Based on: + * Author: Steve Sakoman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Register descriptions for twl4030 codec part */ +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" + +/* TWL4030 PMBR1 Register */ +#define TWL4030_INTBR_PMBR1 0x0D +/* TWL4030 PMBR1 Register GPIO6 mux bit */ +#define TWL4030_GPIO6_PWM0_MUTE(value) (value << 2) + +static struct snd_soc_card snd_soc_sdp3430; + +static int sdp3430_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops sdp3430_ops = { + .hw_params = sdp3430_hw_params, +}; + +/* Headset jack */ +static struct snd_soc_jack hs_jack; + +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin hs_jack_pins[] = { + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headset Stereophone", + .mask = SND_JACK_HEADPHONE, + }, +}; + +/* Headset jack detection gpios */ +static struct snd_soc_jack_gpio hs_jack_gpios[] = { + { + .gpio = (OMAP_MAX_GPIO_LINES + 2), + .name = "hsdet-gpio", + .report = SND_JACK_HEADSET, + .debounce_time = 200, + }, +}; + +/* SDP3430 machine DAPM */ +static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Ext Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_HP("Headset Stereophone", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* External Mics: MAINMIC, SUBMIC with bias*/ + {"MAINMIC", NULL, "Mic Bias 1"}, + {"SUBMIC", NULL, "Mic Bias 2"}, + {"Mic Bias 1", NULL, "Ext Mic"}, + {"Mic Bias 2", NULL, "Ext Mic"}, + + /* External Speakers: HFL, HFR */ + {"Ext Spk", NULL, "HFL"}, + {"Ext Spk", NULL, "HFR"}, + + /* Headset Mic: HSMIC with bias */ + {"HSMIC", NULL, "Headset Mic Bias"}, + {"Headset Mic Bias", NULL, "Headset Mic"}, + + /* Headset Stereophone (Headphone): HSOL, HSOR */ + {"Headset Stereophone", NULL, "HSOL"}, + {"Headset Stereophone", NULL, "HSOR"}, +}; + +static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret; + + /* SDP3430 connected pins */ + snd_soc_dapm_enable_pin(dapm, "Ext Mic"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk"); + snd_soc_dapm_disable_pin(dapm, "Headset Mic"); + snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); + + /* TWL4030 not connected pins */ + snd_soc_dapm_nc_pin(dapm, "AUXL"); + snd_soc_dapm_nc_pin(dapm, "AUXR"); + snd_soc_dapm_nc_pin(dapm, "CARKITMIC"); + snd_soc_dapm_nc_pin(dapm, "DIGIMIC0"); + snd_soc_dapm_nc_pin(dapm, "DIGIMIC1"); + + snd_soc_dapm_nc_pin(dapm, "OUTL"); + snd_soc_dapm_nc_pin(dapm, "OUTR"); + snd_soc_dapm_nc_pin(dapm, "EARPIECE"); + snd_soc_dapm_nc_pin(dapm, "PREDRIVEL"); + snd_soc_dapm_nc_pin(dapm, "PREDRIVER"); + snd_soc_dapm_nc_pin(dapm, "CARKITL"); + snd_soc_dapm_nc_pin(dapm, "CARKITR"); + + /* Headset jack detection */ + ret = snd_soc_jack_new(codec, "Headset Jack", + SND_JACK_HEADSET, &hs_jack); + if (ret) + return ret; + + ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), + hs_jack_pins); + if (ret) + return ret; + + ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + + return ret; +} + +static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + unsigned short reg; + + /* Enable voice interface */ + reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF); + reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; + codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg); + + return 0; +} + + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sdp3430_dai[] = { + { + .name = "TWL4030 I2S", + .stream_name = "TWL4030 Audio", + .cpu_dai_name = "omap-mcbsp.2", + .codec_dai_name = "twl4030-hifi", + .platform_name = "omap-pcm-audio", + .codec_name = "twl4030-codec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .init = sdp3430_twl4030_init, + .ops = &sdp3430_ops, + }, + { + .name = "TWL4030 PCM", + .stream_name = "TWL4030 Voice", + .cpu_dai_name = "omap-mcbsp.3", + .codec_dai_name = "twl4030-voice", + .platform_name = "omap-pcm-audio", + .codec_name = "twl4030-codec", + .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .init = sdp3430_twl4030_voice_init, + .ops = &sdp3430_ops, + }, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_sdp3430 = { + .name = "SDP3430", + .owner = THIS_MODULE, + .dai_link = sdp3430_dai, + .num_links = ARRAY_SIZE(sdp3430_dai), + + .dapm_widgets = sdp3430_twl4030_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sdp3430_twl4030_dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), +}; + +static struct platform_device *sdp3430_snd_device; + +static int __init sdp3430_soc_init(void) +{ + int ret; + u8 pin_mux; + + if (!machine_is_omap_3430sdp()) + return -ENODEV; + printk(KERN_INFO "SDP3430 SoC init\n"); + + sdp3430_snd_device = platform_device_alloc("soc-audio", -1); + if (!sdp3430_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430); + + /* Set TWL4030 GPIO6 as EXTMUTE signal */ + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, + TWL4030_INTBR_PMBR1); + pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03); + pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02); + twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, + TWL4030_INTBR_PMBR1); + + ret = platform_device_add(sdp3430_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(sdp3430_snd_device); + + return ret; +} +module_init(sdp3430_soc_init); + +static void __exit sdp3430_soc_exit(void) +{ + snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + + platform_device_unregister(sdp3430_snd_device); +} +module_exit(sdp3430_soc_exit); + +MODULE_AUTHOR("Misael Lopez Cruz "); +MODULE_DESCRIPTION("ALSA SoC SDP3430"); +MODULE_LICENSE("GPL"); + diff --git a/trunk/sound/soc/omap/zoom2.c b/trunk/sound/soc/omap/zoom2.c new file mode 100644 index 000000000000..771bff27ac3e --- /dev/null +++ b/trunk/sound/soc/omap/zoom2.c @@ -0,0 +1,207 @@ +/* + * zoom2.c -- SoC audio for Zoom2 + * + * Author: Misael Lopez Cruz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Register descriptions for twl4030 codec part */ +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" + +static int zoom2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops zoom2_ops = { + .hw_params = zoom2_hw_params, +}; + +/* Zoom2 machine DAPM */ +static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Ext Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_HP("Headset Stereophone", NULL), + SND_SOC_DAPM_LINE("Aux In", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* External Mics: MAINMIC, SUBMIC with bias*/ + {"MAINMIC", NULL, "Mic Bias 1"}, + {"SUBMIC", NULL, "Mic Bias 2"}, + {"Mic Bias 1", NULL, "Ext Mic"}, + {"Mic Bias 2", NULL, "Ext Mic"}, + + /* External Speakers: HFL, HFR */ + {"Ext Spk", NULL, "HFL"}, + {"Ext Spk", NULL, "HFR"}, + + /* Headset Stereophone: HSOL, HSOR */ + {"Headset Stereophone", NULL, "HSOL"}, + {"Headset Stereophone", NULL, "HSOR"}, + + /* Headset Mic: HSMIC with bias */ + {"HSMIC", NULL, "Headset Mic Bias"}, + {"Headset Mic Bias", NULL, "Headset Mic"}, + + /* Aux In: AUXL, AUXR */ + {"Aux In", NULL, "AUXL"}, + {"Aux In", NULL, "AUXR"}, +}; + +static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + + /* TWL4030 not connected pins */ + snd_soc_dapm_nc_pin(dapm, "CARKITMIC"); + snd_soc_dapm_nc_pin(dapm, "DIGIMIC0"); + snd_soc_dapm_nc_pin(dapm, "DIGIMIC1"); + snd_soc_dapm_nc_pin(dapm, "EARPIECE"); + snd_soc_dapm_nc_pin(dapm, "PREDRIVEL"); + snd_soc_dapm_nc_pin(dapm, "PREDRIVER"); + snd_soc_dapm_nc_pin(dapm, "CARKITL"); + snd_soc_dapm_nc_pin(dapm, "CARKITR"); + + return 0; +} + +static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + unsigned short reg; + + /* Enable voice interface */ + reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF); + reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; + codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg); + + return 0; +} + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link zoom2_dai[] = { + { + .name = "TWL4030 I2S", + .stream_name = "TWL4030 Audio", + .cpu_dai_name = "omap-mcbsp.2", + .codec_dai_name = "twl4030-hifi", + .platform_name = "omap-pcm-audio", + .codec_name = "twl4030-codec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .init = zoom2_twl4030_init, + .ops = &zoom2_ops, + }, + { + .name = "TWL4030 PCM", + .stream_name = "TWL4030 Voice", + .cpu_dai_name = "omap-mcbsp.3", + .codec_dai_name = "twl4030-voice", + .platform_name = "omap-pcm-audio", + .codec_name = "twl4030-codec", + .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .init = zoom2_twl4030_voice_init, + .ops = &zoom2_ops, + }, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_zoom2 = { + .name = "Zoom2", + .owner = THIS_MODULE, + .dai_link = zoom2_dai, + .num_links = ARRAY_SIZE(zoom2_dai), + + .dapm_widgets = zoom2_twl4030_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(zoom2_twl4030_dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), +}; + +static struct platform_device *zoom2_snd_device; + +static int __init zoom2_soc_init(void) +{ + int ret; + + if (!machine_is_omap_zoom2()) + return -ENODEV; + printk(KERN_INFO "Zoom2 SoC init\n"); + + zoom2_snd_device = platform_device_alloc("soc-audio", -1); + if (!zoom2_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(zoom2_snd_device, &snd_soc_zoom2); + ret = platform_device_add(zoom2_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(zoom2_snd_device); + + return ret; +} +module_init(zoom2_soc_init); + +static void __exit zoom2_soc_exit(void) +{ + platform_device_unregister(zoom2_snd_device); +} +module_exit(zoom2_soc_exit); + +MODULE_AUTHOR("Misael Lopez Cruz "); +MODULE_DESCRIPTION("ALSA SoC Zoom2"); +MODULE_LICENSE("GPL"); + diff --git a/trunk/sound/soc/pxa/palm27x.c b/trunk/sound/soc/pxa/palm27x.c index e1ffcdd9a649..2074e2daf9c6 100644 --- a/trunk/sound/soc/pxa/palm27x.c +++ b/trunk/sound/soc/pxa/palm27x.c @@ -79,6 +79,17 @@ static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; int err; + /* add palm27x specific widgets */ + err = snd_soc_dapm_new_controls(dapm, palm27x_dapm_widgets, + ARRAY_SIZE(palm27x_dapm_widgets)); + if (err) + return err; + + /* set up palm27x specific audio path audio_map */ + err = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + if (err) + return err; + /* connected pins */ if (machine_is_palmld()) snd_soc_dapm_enable_pin(dapm, "MIC1"); @@ -138,12 +149,10 @@ static struct snd_soc_card palm27x_asoc = { .owner = THIS_MODULE, .dai_link = palm27x_dai, .num_links = ARRAY_SIZE(palm27x_dai), - .dapm_widgets = palm27x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(palm27x_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map) }; +static struct platform_device *palm27x_snd_device; + static int palm27x_asoc_probe(struct platform_device *pdev) { int ret; @@ -160,18 +169,27 @@ static int palm27x_asoc_probe(struct platform_device *pdev) hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *) (pdev->dev.platform_data))->jack_gpio; - palm27x_asoc.dev = &pdev->dev; + palm27x_snd_device = platform_device_alloc("soc-audio", -1); + if (!palm27x_snd_device) + return -ENOMEM; + + platform_set_drvdata(palm27x_snd_device, &palm27x_asoc); + ret = platform_device_add(palm27x_snd_device); + + if (ret != 0) + goto put_device; + + return 0; + +put_device: + platform_device_put(palm27x_snd_device); - ret = snd_soc_register_card(&palm27x_asoc); - if (ret) - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", - ret); return ret; } static int palm27x_asoc_remove(struct platform_device *pdev) { - snd_soc_unregister_card(&palm27x_asoc); + platform_device_unregister(palm27x_snd_device); return 0; } diff --git a/trunk/sound/soc/samsung/Kconfig b/trunk/sound/soc/samsung/Kconfig index 90e7e6653233..3c7c3a59ed39 100644 --- a/trunk/sound/soc/samsung/Kconfig +++ b/trunk/sound/soc/samsung/Kconfig @@ -63,7 +63,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8580 config SND_SOC_SAMSUNG_SMDK_WM8994 tristate "SoC I2S Audio support for WM8994 on SMDK" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210 || MACH_SMDK4212) depends on I2C=y && GENERIC_HARDIRQS select MFD_WM8994 select SND_SOC_WM8994 @@ -162,7 +162,7 @@ config SND_SOC_GONI_AQUILA_WM8994 config SND_SOC_SAMSUNG_SMDK_SPDIF tristate "SoC S/PDIF Audio support for SMDK" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310 || MACH_SMDK4212) select SND_SAMSUNG_SPDIF help Say Y if you want to add support for SoC S/PDIF audio on the SMDK. @@ -177,7 +177,7 @@ config SND_SOC_SMDK_WM8580_PCM config SND_SOC_SMDK_WM8994_PCM tristate "SoC PCM Audio support for WM8994 on SMDK" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310 || MACH_SMDK4212) depends on I2C=y && GENERIC_HARDIRQS select MFD_WM8994 select SND_SOC_WM8994 diff --git a/trunk/sound/soc/samsung/dma.c b/trunk/sound/soc/samsung/dma.c index 21b79262010e..db87628d7630 100644 --- a/trunk/sound/soc/samsung/dma.c +++ b/trunk/sound/soc/samsung/dma.c @@ -174,8 +174,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream, config.width = prtd->params->dma_size; config.fifo = prtd->params->dma_addr; prtd->params->ch = prtd->params->ops->request( - prtd->params->channel, &req, rtd->cpu_dai->dev, - prtd->params->ch_name); + prtd->params->channel, &req); prtd->params->ops->config(prtd->params->ch, &config); } diff --git a/trunk/sound/soc/samsung/dma.h b/trunk/sound/soc/samsung/dma.h index 189a7a6d5020..73d8c7c8a1e8 100644 --- a/trunk/sound/soc/samsung/dma.h +++ b/trunk/sound/soc/samsung/dma.h @@ -19,7 +19,6 @@ struct s3c_dma_params { int dma_size; /* Size of the DMA transfer */ unsigned ch; struct samsung_dma_ops *ops; - char *ch_name; }; int asoc_dma_platform_register(struct device *dev); diff --git a/trunk/sound/soc/samsung/i2s.c b/trunk/sound/soc/samsung/i2s.c index d7231e336a7c..d2d124f1dd1b 100644 --- a/trunk/sound/soc/samsung/i2s.c +++ b/trunk/sound/soc/samsung/i2s.c @@ -15,15 +15,11 @@ #include #include #include -#include -#include #include #include #include -#include - #include #include "dma.h" @@ -33,15 +29,6 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) -enum samsung_dai_type { - TYPE_PRI, - TYPE_SEC, -}; - -struct samsung_i2s_dai_data { - int dai_type; -}; - struct i2s_dai { /* Platform device for this DAI */ struct platform_device *pdev; @@ -79,7 +66,6 @@ struct i2s_dai { u32 suspend_i2smod; u32 suspend_i2scon; u32 suspend_i2spsr; - unsigned long gpios[7]; /* i2s gpio line numbers */ }; /* Lock for cross i/f checks */ @@ -665,9 +651,6 @@ static int i2s_startup(struct snd_pcm_substream *substream, /* Enforce set_sysclk in Master mode */ i2s->rclk_srcrate = 0; - if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR)) - writel(CON_RSTCLR, i2s->addr + I2SCON); - spin_unlock_irqrestore(&lock, flags); return 0; @@ -998,7 +981,8 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; } else { /* Create a new platform_device for Secondary */ i2s->pdev = platform_device_register_resndata(NULL, - "samsung-i2s-sec", -1, NULL, 0, NULL, 0); + pdev->name, pdev->id + SAMSUNG_I2S_SECOFF, + NULL, 0, NULL, 0); if (IS_ERR(i2s->pdev)) return NULL; } @@ -1009,103 +993,18 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) return i2s; } -#ifdef CONFIG_OF -static int samsung_i2s_parse_dt_gpio(struct i2s_dai *i2s) -{ - struct device *dev = &i2s->pdev->dev; - int index, gpio, ret; - - for (index = 0; index < 7; index++) { - gpio = of_get_gpio(dev->of_node, index); - if (!gpio_is_valid(gpio)) { - dev_err(dev, "invalid gpio[%d]: %d\n", index, gpio); - goto free_gpio; - } - - ret = gpio_request(gpio, dev_name(dev)); - if (ret) { - dev_err(dev, "gpio [%d] request failed\n", gpio); - goto free_gpio; - } - i2s->gpios[index] = gpio; - } - return 0; - -free_gpio: - while (--index >= 0) - gpio_free(i2s->gpios[index]); - return -EINVAL; -} - -static void samsung_i2s_dt_gpio_free(struct i2s_dai *i2s) -{ - unsigned int index; - for (index = 0; index < 7; index++) - gpio_free(i2s->gpios[index]); -} -#else -static int samsung_i2s_parse_dt_gpio(struct i2s_dai *dai) -{ - return -EINVAL; -} - -static void samsung_i2s_dt_gpio_free(struct i2s_dai *dai) -{ -} - -#endif - -static const struct of_device_id exynos_i2s_match[]; - -static inline int samsung_i2s_get_driver_data(struct platform_device *pdev) -{ -#ifdef CONFIG_OF - struct samsung_i2s_dai_data *data; - if (pdev->dev.of_node) { - const struct of_device_id *match; - match = of_match_node(exynos_i2s_match, pdev->dev.of_node); - data = (struct samsung_i2s_dai_data *) match->data; - return data->dai_type; - } else -#endif - return platform_get_device_id(pdev)->driver_data; -} - -#ifdef CONFIG_PM_RUNTIME -static int i2s_runtime_suspend(struct device *dev) -{ - struct i2s_dai *i2s = dev_get_drvdata(dev); - - clk_disable_unprepare(i2s->clk); - - return 0; -} - -static int i2s_runtime_resume(struct device *dev) -{ - struct i2s_dai *i2s = dev_get_drvdata(dev); - - clk_prepare_enable(i2s->clk); - - return 0; -} -#endif /* CONFIG_PM_RUNTIME */ - static int samsung_i2s_probe(struct platform_device *pdev) { + u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan; struct i2s_dai *pri_dai, *sec_dai = NULL; - struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; - struct samsung_i2s *i2s_cfg = NULL; + struct s3c_audio_pdata *i2s_pdata; + struct samsung_i2s *i2s_cfg; struct resource *res; - u32 regs_base, quirks = 0, idma_addr = 0; - struct device_node *np = pdev->dev.of_node; - enum samsung_dai_type samsung_dai_type; + u32 regs_base, quirks; int ret = 0; /* Call during Seconday interface registration */ - samsung_dai_type = samsung_i2s_get_driver_data(pdev); - - if (samsung_dai_type == TYPE_SEC) { + if (pdev->id >= SAMSUNG_I2S_SECOFF) { sec_dai = dev_get_drvdata(&pdev->dev); snd_soc_register_dai(&sec_dai->pdev->dev, &sec_dai->i2s_dai_drv); @@ -1113,60 +1012,31 @@ static int samsung_i2s_probe(struct platform_device *pdev) return 0; } - pri_dai = i2s_alloc_dai(pdev, false); - if (!pri_dai) { - dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); - return -ENOMEM; + i2s_pdata = pdev->dev.platform_data; + if (i2s_pdata == NULL) { + dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); + return -EINVAL; } - if (!np) { - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, - "Unable to get I2S-TX dma resource\n"); - return -ENXIO; - } - pri_dai->dma_playback.channel = res->start; - - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(&pdev->dev, - "Unable to get I2S-RX dma resource\n"); - return -ENXIO; - } - pri_dai->dma_capture.channel = res->start; - - if (i2s_pdata == NULL) { - dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); - return -EINVAL; - } - - if (&i2s_pdata->type) - i2s_cfg = &i2s_pdata->type.i2s; - - if (i2s_cfg) { - quirks = i2s_cfg->quirks; - idma_addr = i2s_cfg->idma_addr; - } - } else { - if (of_find_property(np, "samsung,supports-6ch", NULL)) - quirks |= QUIRK_PRI_6CHAN; - - if (of_find_property(np, "samsung,supports-secdai", NULL)) - quirks |= QUIRK_SEC_DAI; - - if (of_find_property(np, "samsung,supports-rstclr", NULL)) - quirks |= QUIRK_NEED_RSTCLR; + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n"); + return -ENXIO; + } + dma_pl_chan = res->start; - if (of_property_read_u32(np, "samsung,idma-addr", - &idma_addr)) { - if (quirks & QUIRK_SEC_DAI) { - dev_err(&pdev->dev, "idma address is not"\ - "specified"); - return -EINVAL; - } - } + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!res) { + dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n"); + return -ENXIO; } + dma_cp_chan = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 2); + if (res) + dma_pl_sec_chan = res->start; + else + dma_pl_sec_chan = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -1181,14 +1051,24 @@ static int samsung_i2s_probe(struct platform_device *pdev) } regs_base = res->start; + i2s_cfg = &i2s_pdata->type.i2s; + quirks = i2s_cfg->quirks; + + pri_dai = i2s_alloc_dai(pdev, false); + if (!pri_dai) { + dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); + ret = -ENOMEM; + goto err; + } + pri_dai->dma_playback.dma_addr = regs_base + I2STXD; pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; pri_dai->dma_playback.client = (struct s3c2410_dma_client *)&pri_dai->dma_playback; - pri_dai->dma_playback.ch_name = "tx"; pri_dai->dma_capture.client = (struct s3c2410_dma_client *)&pri_dai->dma_capture; - pri_dai->dma_capture.ch_name = "rx"; + pri_dai->dma_playback.channel = dma_pl_chan; + pri_dai->dma_capture.channel = dma_cp_chan; pri_dai->dma_playback.dma_size = 4; pri_dai->dma_capture.dma_size = 4; pri_dai->base = regs_base; @@ -1207,34 +1087,20 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; sec_dai->dma_playback.client = (struct s3c2410_dma_client *)&sec_dai->dma_playback; - sec_dai->dma_playback.ch_name = "tx-sec"; - - if (!np) { - res = platform_get_resource(pdev, IORESOURCE_DMA, 2); - if (res) - sec_dai->dma_playback.channel = res->start; - } - + /* Use iDMA always if SysDMA not provided */ + sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1; sec_dai->dma_playback.dma_size = 4; sec_dai->base = regs_base; sec_dai->quirks = quirks; - sec_dai->idma_playback.dma_addr = idma_addr; + sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr; sec_dai->pri_dai = pri_dai; pri_dai->sec_dai = sec_dai; } - if (np) { - if (samsung_i2s_parse_dt_gpio(pri_dai)) { - dev_err(&pdev->dev, "Unable to configure gpio\n"); - ret = -EINVAL; - goto err; - } - } else { - if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { - dev_err(&pdev->dev, "Unable to configure gpio\n"); - ret = -EINVAL; - goto err; - } + if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { + dev_err(&pdev->dev, "Unable to configure gpio\n"); + ret = -EINVAL; + goto err; } snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv); @@ -1254,14 +1120,10 @@ static int samsung_i2s_remove(struct platform_device *pdev) { struct i2s_dai *i2s, *other; struct resource *res; - struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; i2s = dev_get_drvdata(&pdev->dev); other = i2s->pri_dai ? : i2s->sec_dai; - if (!i2s_pdata->cfg_gpio && pdev->dev.of_node) - samsung_i2s_dt_gpio_free(i2s->pri_dai); - if (other) { other->pri_dai = NULL; other->sec_dai = NULL; @@ -1281,47 +1143,12 @@ static int samsung_i2s_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id samsung_i2s_driver_ids[] = { - { - .name = "samsung-i2s", - .driver_data = TYPE_PRI, - }, { - .name = "samsung-i2s-sec", - .driver_data = TYPE_SEC, - }, - {}, -}; -MODULE_DEVICE_TABLE(platform, samsung-i2s-driver-ids); - -#ifdef CONFIG_OF -static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = { - [TYPE_PRI] = { TYPE_PRI }, - [TYPE_SEC] = { TYPE_SEC }, -}; - -static const struct of_device_id exynos_i2s_match[] = { - { .compatible = "samsung,i2s-v5", - .data = &samsung_i2s_dai_data_array[TYPE_PRI], - }, - {}, -}; -MODULE_DEVICE_TABLE(of, exynos_i2s_match); -#endif - -static const struct dev_pm_ops samsung_i2s_pm = { - SET_RUNTIME_PM_OPS(i2s_runtime_suspend, - i2s_runtime_resume, NULL) -}; - static struct platform_driver samsung_i2s_driver = { .probe = samsung_i2s_probe, .remove = samsung_i2s_remove, - .id_table = samsung_i2s_driver_ids, .driver = { .name = "samsung-i2s", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(exynos_i2s_match), - .pm = &samsung_i2s_pm, }, }; diff --git a/trunk/sound/soc/samsung/i2s.h b/trunk/sound/soc/samsung/i2s.h index 7966afc934db..d420a7ca56ca 100644 --- a/trunk/sound/soc/samsung/i2s.h +++ b/trunk/sound/soc/samsung/i2s.h @@ -13,6 +13,13 @@ #ifndef __SND_SOC_SAMSUNG_I2S_H #define __SND_SOC_SAMSUNG_I2S_H +/* + * Maximum number of I2S blocks that any SoC can have. + * The secondary interface of a CPU dai(if there exists any), + * is indexed at [cpu-dai's ID + SAMSUNG_I2S_SECOFF] + */ +#define SAMSUNG_I2S_SECOFF 4 + #define SAMSUNG_I2S_DIV_BCLK 1 #define SAMSUNG_I2S_RCLKSRC_0 0 diff --git a/trunk/sound/soc/samsung/s3c24xx-i2s.c b/trunk/sound/soc/samsung/s3c24xx-i2s.c index 13f6dd1ceb00..ee10e8704e97 100644 --- a/trunk/sound/soc/samsung/s3c24xx-i2s.c +++ b/trunk/sound/soc/samsung/s3c24xx-i2s.c @@ -469,7 +469,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { int ret = 0; - ret = snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai); + ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); if (ret) { pr_err("failed to register the dai\n"); return ret; diff --git a/trunk/sound/soc/samsung/smdk_wm8580.c b/trunk/sound/soc/samsung/smdk_wm8580.c index 7a16b32ed673..7e2b710763be 100644 --- a/trunk/sound/soc/samsung/smdk_wm8580.c +++ b/trunk/sound/soc/samsung/smdk_wm8580.c @@ -193,9 +193,9 @@ static struct snd_soc_dai_link smdk_dai[] = { [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ .name = "Sec_FIFO TX", .stream_name = "Playback", - .cpu_dai_name = "samsung-i2s-sec", + .cpu_dai_name = "samsung-i2s.x", .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-i2s-sec", + .platform_name = "samsung-i2s.x", .codec_name = "wm8580.0-001b", .ops = &smdk_ops, }, @@ -223,6 +223,9 @@ static int __init smdk_audio_init(void) if (machine_is_smdkc100() || machine_is_smdkv210() || machine_is_smdkc110()) { smdk.num_links = 3; + /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ + str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name; + str[strlen(str) - 1] = '0' + SAMSUNG_I2S_SECOFF; } else if (machine_is_smdk6410()) { str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; str[strlen(str) - 1] = '2'; diff --git a/trunk/sound/soc/samsung/smdk_wm8994.c b/trunk/sound/soc/samsung/smdk_wm8994.c index 581ea4a06fc6..b0d0ab8bff5a 100644 --- a/trunk/sound/soc/samsung/smdk_wm8994.c +++ b/trunk/sound/soc/samsung/smdk_wm8994.c @@ -10,7 +10,6 @@ #include "../codecs/wm8994.h" #include #include -#include /* * Default CFG switch settings to use this driver: @@ -135,9 +134,9 @@ static struct snd_soc_dai_link smdk_dai[] = { }, { /* Sec_Fifo Playback i/f */ .name = "Sec_FIFO TX", .stream_name = "Sec_Dai", - .cpu_dai_name = "samsung-i2s-sec", + .cpu_dai_name = "samsung-i2s.4", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-i2s-sec", + .platform_name = "samsung-i2s.4", .codec_name = "wm8994-codec", .ops = &smdk_ops, }, @@ -154,25 +153,9 @@ static struct snd_soc_card smdk = { static int smdk_audio_probe(struct platform_device *pdev) { int ret; - struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &smdk; card->dev = &pdev->dev; - - if (np) { - smdk_dai[0].cpu_dai_name = NULL; - smdk_dai[0].cpu_of_node = of_parse_phandle(np, - "samsung,i2s-controller", 0); - if (!smdk_dai[0].cpu_of_node) { - dev_err(&pdev->dev, - "Property 'samsung,i2s-controller' missing or invalid\n"); - ret = -EINVAL; - } - - smdk_dai[0].platform_name = NULL; - smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; - } - ret = snd_soc_register_card(card); if (ret) @@ -190,19 +173,10 @@ static int smdk_audio_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF -static const struct of_device_id samsung_wm8994_of_match[] = { - { .compatible = "samsung,smdk-wm8994", }, - {}, -}; -MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); -#endif /* CONFIG_OF */ - static struct platform_driver smdk_audio_driver = { .driver = { .name = "smdk-audio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(samsung_wm8994_of_match), }, .probe = smdk_audio_probe, .remove = smdk_audio_remove, diff --git a/trunk/sound/soc/sh/fsi.c b/trunk/sound/soc/sh/fsi.c index c724026a246f..a606d0f93d1c 100644 --- a/trunk/sound/soc/sh/fsi.c +++ b/trunk/sound/soc/sh/fsi.c @@ -16,8 +16,6 @@ #include #include #include -#include -#include #include #include #include @@ -133,6 +131,8 @@ #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) +typedef int (*set_rate_func)(struct device *dev, int rate, int enable); + /* * bus options * @@ -244,7 +244,8 @@ struct fsi_clk { struct clk *ick; struct clk *div; int (*set_rate)(struct device *dev, - struct fsi_priv *fsi); + struct fsi_priv *fsi, + unsigned long rate); unsigned long rate; unsigned int count; @@ -253,6 +254,7 @@ struct fsi_clk { struct fsi_priv { void __iomem *base; struct fsi_master *master; + struct sh_fsi_port_info *info; struct fsi_stream playback; struct fsi_stream capture; @@ -268,6 +270,8 @@ struct fsi_priv { int enable_stream:1; int bit_clk_inv:1; int lr_clk_inv:1; + + long rate; }; struct fsi_stream_handler { @@ -299,7 +303,7 @@ struct fsi_master { int irq; struct fsi_priv fsia; struct fsi_priv fsib; - const struct fsi_core *core; + struct fsi_core *core; spinlock_t lock; }; @@ -427,6 +431,22 @@ static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) return fsi_get_priv_frm_dai(fsi_get_dai(substream)); } +static set_rate_func fsi_get_info_set_rate(struct fsi_priv *fsi) +{ + if (!fsi->info) + return NULL; + + return fsi->info->set_rate; +} + +static u32 fsi_get_info_flags(struct fsi_priv *fsi) +{ + if (!fsi->info) + return 0; + + return fsi->info->flags; +} + static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io) { int is_play = fsi_stream_is_play(fsi, io); @@ -737,7 +757,8 @@ static int fsi_clk_init(struct device *dev, int ick, int div, int (*set_rate)(struct device *dev, - struct fsi_priv *fsi)) + struct fsi_priv *fsi, + unsigned long rate)) { struct fsi_clk *clock = &fsi->clock; int is_porta = fsi_is_port_a(fsi); @@ -808,7 +829,8 @@ static int fsi_clk_is_valid(struct fsi_priv *fsi) } static int fsi_clk_enable(struct device *dev, - struct fsi_priv *fsi) + struct fsi_priv *fsi, + unsigned long rate) { struct fsi_clk *clock = &fsi->clock; int ret = -EINVAL; @@ -817,7 +839,7 @@ static int fsi_clk_enable(struct device *dev, return ret; if (0 == clock->count) { - ret = clock->set_rate(dev, fsi); + ret = clock->set_rate(dev, fsi, rate); if (ret < 0) { fsi_clk_invalid(fsi); return ret; @@ -924,11 +946,11 @@ static int fsi_clk_set_ackbpf(struct device *dev, } static int fsi_clk_set_rate_external(struct device *dev, - struct fsi_priv *fsi) + struct fsi_priv *fsi, + unsigned long rate) { struct clk *xck = fsi->clock.xck; struct clk *ick = fsi->clock.ick; - unsigned long rate = fsi->clock.rate; unsigned long xrate; int ackmd, bpfmd; int ret = 0; @@ -956,11 +978,11 @@ static int fsi_clk_set_rate_external(struct device *dev, } static int fsi_clk_set_rate_cpg(struct device *dev, - struct fsi_priv *fsi) + struct fsi_priv *fsi, + unsigned long rate) { struct clk *ick = fsi->clock.ick; struct clk *div = fsi->clock.div; - unsigned long rate = fsi->clock.rate; unsigned long target = 0; /* 12288000 or 11289600 */ unsigned long actual, cout; unsigned long diff, min; @@ -1041,6 +1063,85 @@ static int fsi_clk_set_rate_cpg(struct device *dev, return ret; } +static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, + long rate, int enable) +{ + set_rate_func set_rate = fsi_get_info_set_rate(fsi); + int ret; + + /* + * CAUTION + * + * set_rate will be deleted + */ + if (!set_rate) { + if (enable) + return fsi_clk_enable(dev, fsi, rate); + else + return fsi_clk_disable(dev, fsi); + } + + ret = set_rate(dev, rate, enable); + if (ret < 0) /* error */ + return ret; + + if (!enable) + return 0; + + if (ret > 0) { + u32 data = 0; + + switch (ret & SH_FSI_ACKMD_MASK) { + default: + /* FALL THROUGH */ + case SH_FSI_ACKMD_512: + data |= (0x0 << 12); + break; + case SH_FSI_ACKMD_256: + data |= (0x1 << 12); + break; + case SH_FSI_ACKMD_128: + data |= (0x2 << 12); + break; + case SH_FSI_ACKMD_64: + data |= (0x3 << 12); + break; + case SH_FSI_ACKMD_32: + data |= (0x4 << 12); + break; + } + + switch (ret & SH_FSI_BPFMD_MASK) { + default: + /* FALL THROUGH */ + case SH_FSI_BPFMD_32: + data |= (0x0 << 8); + break; + case SH_FSI_BPFMD_64: + data |= (0x1 << 8); + break; + case SH_FSI_BPFMD_128: + data |= (0x2 << 8); + break; + case SH_FSI_BPFMD_256: + data |= (0x3 << 8); + break; + case SH_FSI_BPFMD_512: + data |= (0x4 << 8); + break; + case SH_FSI_BPFMD_16: + data |= (0x7 << 8); + break; + } + + fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); + udelay(10); + ret = 0; + } + + return ret; +} + /* * pio data transfer handler */ @@ -1536,6 +1637,7 @@ static int fsi_hw_startup(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) { + u32 flags = fsi_get_info_flags(fsi); u32 data = 0; /* clock setting */ @@ -1552,6 +1654,19 @@ static int fsi_hw_startup(struct fsi_priv *fsi, data |= (1 << 4); if (fsi_is_clk_master(fsi)) data <<= 8; + /* FIXME + * + * SH_FSI_xxx_INV style will be removed + */ + if (SH_FSI_LRM_INV & flags) + data |= 1 << 12; + if (SH_FSI_BRM_INV & flags) + data |= 1 << 8; + if (SH_FSI_LRS_INV & flags) + data |= 1 << 4; + if (SH_FSI_BRS_INV & flags) + data |= 1 << 0; + fsi_reg_write(fsi, CKG2, data); /* spdif ? */ @@ -1583,7 +1698,7 @@ static int fsi_hw_startup(struct fsi_priv *fsi, /* start master clock */ if (fsi_is_clk_master(fsi)) - return fsi_clk_enable(dev, fsi); + return fsi_set_master_clk(dev, fsi, fsi->rate, 1); return 0; } @@ -1593,7 +1708,7 @@ static int fsi_hw_shutdown(struct fsi_priv *fsi, { /* stop master clock */ if (fsi_is_clk_master(fsi)) - return fsi_clk_disable(dev, fsi); + return fsi_set_master_clk(dev, fsi, fsi->rate, 0); return 0; } @@ -1604,6 +1719,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, struct fsi_priv *fsi = fsi_get_priv(substream); fsi_clk_invalid(fsi); + fsi->rate = 0; return 0; } @@ -1614,6 +1730,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, struct fsi_priv *fsi = fsi_get_priv(substream); fsi_clk_invalid(fsi); + fsi->rate = 0; } static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, @@ -1678,6 +1795,7 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); + set_rate_func set_rate = fsi_get_info_set_rate(fsi); int ret; /* set master/slave audio interface */ @@ -1713,6 +1831,14 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } if (fsi_is_clk_master(fsi)) { + /* + * CAUTION + * + * set_rate will be deleted + */ + if (set_rate) + dev_warn(dai->dev, "set_rate will be removed soon\n"); + if (fsi->clk_cpg) fsi_clk_init(dai->dev, fsi, 0, 1, 1, fsi_clk_set_rate_cpg); @@ -1736,8 +1862,10 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); - if (fsi_is_clk_master(fsi)) - fsi_clk_valid(fsi, params_rate(params)); + if (fsi_is_clk_master(fsi)) { + fsi->rate = params_rate(params); + fsi_clk_valid(fsi, fsi->rate); + } return 0; } @@ -1889,33 +2017,6 @@ static struct snd_soc_platform_driver fsi_soc_platform = { /* * platform function */ -static void fsi_of_parse(char *name, - struct device_node *np, - struct sh_fsi_port_info *info, - struct device *dev) -{ - int i; - char prop[128]; - unsigned long flags = 0; - struct { - char *name; - unsigned int val; - } of_parse_property[] = { - { "spdif-connection", SH_FSI_FMT_SPDIF }, - { "stream-mode-support", SH_FSI_ENABLE_STREAM_MODE }, - { "use-internal-clock", SH_FSI_CLK_CPG }, - }; - - for (i = 0; i < ARRAY_SIZE(of_parse_property); i++) { - sprintf(prop, "%s,%s", name, of_parse_property[i].name); - if (of_get_property(np, prop, NULL)) - flags |= of_parse_property[i].val; - } - info->flags = flags; - - dev_dbg(dev, "%s flags : %lx\n", name, info->flags); -} - static void fsi_port_info_init(struct fsi_priv *fsi, struct sh_fsi_port_info *info) { @@ -1943,40 +2044,23 @@ static void fsi_handler_init(struct fsi_priv *fsi, } } -static struct of_device_id fsi_of_match[]; static int fsi_probe(struct platform_device *pdev) { struct fsi_master *master; - struct device_node *np = pdev->dev.of_node; - struct sh_fsi_platform_info info; - const struct fsi_core *core; + const struct platform_device_id *id_entry; + struct sh_fsi_platform_info *info = pdev->dev.platform_data; + struct sh_fsi_port_info nul_info, *pinfo; struct fsi_priv *fsi; struct resource *res; unsigned int irq; int ret; - memset(&info, 0, sizeof(info)); - - core = NULL; - if (np) { - const struct of_device_id *of_id; + nul_info.flags = 0; + nul_info.tx_id = 0; + nul_info.rx_id = 0; - of_id = of_match_device(fsi_of_match, &pdev->dev); - if (of_id) { - core = of_id->data; - fsi_of_parse("fsia", np, &info.port_a, &pdev->dev); - fsi_of_parse("fsib", np, &info.port_b, &pdev->dev); - } - } else { - const struct platform_device_id *id_entry = pdev->id_entry; - if (id_entry) - core = (struct fsi_core *)id_entry->driver_data; - - if (pdev->dev.platform_data) - memcpy(&info, pdev->dev.platform_data, sizeof(info)); - } - - if (!core) { + id_entry = pdev->id_entry; + if (!id_entry) { dev_err(&pdev->dev, "unknown fsi device\n"); return -ENODEV; } @@ -2003,15 +2087,17 @@ static int fsi_probe(struct platform_device *pdev) /* master setting */ master->irq = irq; - master->core = core; + master->core = (struct fsi_core *)id_entry->driver_data; spin_lock_init(&master->lock); /* FSI A setting */ + pinfo = (info) ? &info->port_a : &nul_info; fsi = &master->fsia; fsi->base = master->base; fsi->master = master; - fsi_port_info_init(fsi, &info.port_a); - fsi_handler_init(fsi, &info.port_a); + fsi->info = pinfo; + fsi_port_info_init(fsi, pinfo); + fsi_handler_init(fsi, pinfo); ret = fsi_stream_probe(fsi, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "FSIA stream probe failed\n"); @@ -2019,11 +2105,13 @@ static int fsi_probe(struct platform_device *pdev) } /* FSI B setting */ + pinfo = (info) ? &info->port_b : &nul_info; fsi = &master->fsib; fsi->base = master->base + 0x40; fsi->master = master; - fsi_port_info_init(fsi, &info.port_b); - fsi_handler_init(fsi, &info.port_b); + fsi->info = pinfo; + fsi_port_info_init(fsi, pinfo); + fsi_handler_init(fsi, pinfo); ret = fsi_stream_probe(fsi, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "FSIB stream probe failed\n"); @@ -2034,7 +2122,7 @@ static int fsi_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, master); ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0, - dev_name(&pdev->dev), master); + id_entry->name, master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); goto exit_fsib; @@ -2160,13 +2248,6 @@ static struct fsi_core fsi2_core = { .b_mclk = B_MST_CTLR, }; -static struct of_device_id fsi_of_match[] = { - { .compatible = "renesas,sh_fsi", .data = &fsi1_core}, - { .compatible = "renesas,sh_fsi2", .data = &fsi2_core}, - {}, -}; -MODULE_DEVICE_TABLE(of, fsi_of_match); - static struct platform_device_id fsi_id_table[] = { { "sh_fsi", (kernel_ulong_t)&fsi1_core }, { "sh_fsi2", (kernel_ulong_t)&fsi2_core }, @@ -2178,7 +2259,6 @@ static struct platform_driver fsi_driver = { .driver = { .name = "fsi-pcm-audio", .pm = &fsi_pm_ops, - .of_match_table = fsi_of_match, }, .probe = fsi_probe, .remove = fsi_remove, diff --git a/trunk/sound/soc/soc-compress.c b/trunk/sound/soc/soc-compress.c index b5b3db71e253..5fbfb06e8083 100644 --- a/trunk/sound/soc/soc-compress.c +++ b/trunk/sound/soc/soc-compress.c @@ -33,8 +33,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream) struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (platform->driver->compr_ops && platform->driver->compr_ops->open) { ret = platform->driver->compr_ops->open(cstream); if (ret < 0) { @@ -63,46 +61,15 @@ static int soc_compr_open(struct snd_compr_stream *cstream) codec_dai->active++; rtd->codec->active++; - mutex_unlock(&rtd->pcm_mutex); - return 0; machine_err: if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); out: - mutex_unlock(&rtd->pcm_mutex); return ret; } -/* - * Power down the audio subsystem pmdown_time msecs after close is called. - * This is to ensure there are no pops or clicks in between any music tracks - * due to DAPM power cycling. - */ -static void close_delayed_work(struct work_struct *work) -{ - struct snd_soc_pcm_runtime *rtd = - container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - - dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", - codec_dai->driver->playback.stream_name, - codec_dai->playback_active ? "active" : "inactive", - rtd->pop_wait ? "yes" : "no"); - - /* are we waiting on this codec DAI stream */ - if (rtd->pop_wait == 1) { - rtd->pop_wait = 0; - snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, - SND_SOC_DAPM_STREAM_STOP); - } - - mutex_unlock(&rtd->pcm_mutex); -} - static int soc_compr_free(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -111,8 +78,6 @@ static int soc_compr_free(struct snd_compr_stream *cstream) struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (cstream->direction == SND_COMPRESS_PLAYBACK) { cpu_dai->playback_active--; codec_dai->playback_active--; @@ -121,7 +86,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) codec_dai->capture_active--; } - snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); + snd_soc_dai_digital_mute(codec_dai, 1); cpu_dai->active--; codec_dai->active--; @@ -147,11 +112,10 @@ static int soc_compr_free(struct snd_compr_stream *cstream) snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); - } else { + } else rtd->pop_wait = 1; schedule_delayed_work(&rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); - } } else { /* capture streams can be powered down now */ snd_soc_dapm_stream_event(rtd, @@ -159,7 +123,6 @@ static int soc_compr_free(struct snd_compr_stream *cstream) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); return 0; } @@ -171,25 +134,17 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { ret = platform->driver->compr_ops->trigger(cstream, cmd); if (ret < 0) - goto out; + return ret; } - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction); - break; - case SNDRV_PCM_TRIGGER_STOP: - snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); - break; - } + if (cmd == SNDRV_PCM_TRIGGER_START) + snd_soc_dai_digital_mute(codec_dai, 0); + else if (cmd == SNDRV_PCM_TRIGGER_STOP) + snd_soc_dai_digital_mute(codec_dai, 1); -out: - mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -200,8 +155,6 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_soc_platform *platform = rtd->platform; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - /* first we call set_params for the platform driver * this should configure the soc side * if the machine has compressed ops then we call that as well @@ -211,20 +164,18 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) - goto out; + return ret; } if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); if (ret < 0) - goto out; + return ret; } snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_START); -out: - mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -235,12 +186,9 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_soc_platform *platform = rtd->platform; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) ret = platform->driver->compr_ops->get_params(cstream, params); - mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -251,12 +199,9 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, struct snd_soc_platform *platform = rtd->platform; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps) ret = platform->driver->compr_ops->get_caps(cstream, caps); - mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -267,12 +212,9 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_soc_platform *platform = rtd->platform; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) ret = platform->driver->compr_ops->get_codec_caps(cstream, codec); - mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -282,12 +224,9 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) struct snd_soc_platform *platform = rtd->platform; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (platform->driver->compr_ops && platform->driver->compr_ops->ack) ret = platform->driver->compr_ops->ack(cstream, bytes); - mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -297,31 +236,12 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) platform->driver->compr_ops->pointer(cstream, tstamp); - mutex_unlock(&rtd->pcm_mutex); return 0; } -static int soc_compr_copy(struct snd_compr_stream *cstream, - const char __user *buf, size_t count) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_platform *platform = rtd->platform; - int ret = 0; - - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - - if (platform->driver->compr_ops && platform->driver->compr_ops->copy) - ret = platform->driver->compr_ops->copy(cstream, buf, count); - - mutex_unlock(&rtd->pcm_mutex); - return ret; -} - /* ASoC Compress operations */ static struct snd_compr_ops soc_compr_ops = { .open = soc_compr_open, @@ -339,7 +259,6 @@ static struct snd_compr_ops soc_compr_ops = { int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) { struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_compr *compr; @@ -356,38 +275,20 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) return -ENOMEM; } - compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops), - GFP_KERNEL); - if (compr->ops == NULL) { - dev_err(rtd->card->dev, "Cannot allocate compressed ops\n"); - ret = -ENOMEM; - goto compr_err; - } - memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); - - /* Add copy callback for not memory mapped DSPs */ - if (platform->driver->compr_ops && platform->driver->compr_ops->copy) - compr->ops->copy = soc_compr_copy; - + compr->ops = &soc_compr_ops; mutex_init(&compr->lock); ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); if (ret < 0) { pr_err("compress asoc: can't create compress for codec %s\n", codec->name); - goto compr_err; + kfree(compr); + return ret; } - /* DAPM dai link stream work */ - INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); - rtd->compr = compr; compr->private_data = rtd; printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; - -compr_err: - kfree(compr); - return ret; } diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index 8df1b3feaf2b..2370063b5824 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -1107,10 +1107,6 @@ static int soc_probe_codec(struct snd_soc_card *card, "ASoC: failed to probe CODEC %d\n", ret); goto err_probe; } - WARN(codec->dapm.idle_bias_off && - codec->dapm.bias_level != SND_SOC_BIAS_OFF, - "codec %s can not start from non-off bias" - " with idle_bias_off==1\n", codec->name); } /* If the driver didn't set I/O up try regmap */ @@ -3126,12 +3122,9 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, if (!codec->using_regmap) return -EINVAL; + data = ucontrol->value.bytes.data; len = params->num_regs * codec->val_bytes; - data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); - if (!data) - return -ENOMEM; - /* * If we've got a mask then we need to preserve the register * bits. We shouldn't modify the incoming data so take a @@ -3144,6 +3137,10 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, val &= params->mask; + data = kmemdup(data, len, GFP_KERNEL); + if (!data) + return -ENOMEM; + switch (codec->val_bytes) { case 1: ((u8 *)data)[0] &= ~params->mask; @@ -3165,7 +3162,8 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, ret = regmap_raw_write(codec->control_data, params->base, data, len); - kfree(data); + if (params->mask) + kfree(data); return ret; } @@ -3542,20 +3540,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); * snd_soc_dai_digital_mute - configure DAI system or master clock. * @dai: DAI * @mute: mute enable - * @direction: stream to mute * * Mutes the DAI DAC. */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, - int direction) +int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (!dai->driver) - return -ENOTSUPP; - - if (dai->driver->ops->mute_stream) - return dai->driver->ops->mute_stream(dai, mute, direction); - else if (direction == SNDRV_PCM_STREAM_PLAYBACK && - dai->driver->ops->digital_mute) + if (dai->driver && dai->driver->ops->digital_mute) return dai->driver->ops->digital_mute(dai, mute); else return -ENOTSUPP; @@ -4218,113 +4208,6 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); -unsigned int snd_soc_of_parse_daifmt(struct device_node *np, - const char *prefix) -{ - int ret, i; - char prop[128]; - unsigned int format = 0; - int bit, frame; - const char *str; - struct { - char *name; - unsigned int val; - } of_fmt_table[] = { - { "i2s", SND_SOC_DAIFMT_I2S }, - { "right_j", SND_SOC_DAIFMT_RIGHT_J }, - { "left_j", SND_SOC_DAIFMT_LEFT_J }, - { "dsp_a", SND_SOC_DAIFMT_DSP_A }, - { "dsp_b", SND_SOC_DAIFMT_DSP_B }, - { "ac97", SND_SOC_DAIFMT_AC97 }, - { "pdm", SND_SOC_DAIFMT_PDM}, - { "msb", SND_SOC_DAIFMT_MSB }, - { "lsb", SND_SOC_DAIFMT_LSB }, - }; - - if (!prefix) - prefix = ""; - - /* - * check "[prefix]format = xxx" - * SND_SOC_DAIFMT_FORMAT_MASK area - */ - snprintf(prop, sizeof(prop), "%sformat", prefix); - ret = of_property_read_string(np, prop, &str); - if (ret == 0) { - for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { - if (strcmp(str, of_fmt_table[i].name) == 0) { - format |= of_fmt_table[i].val; - break; - } - } - } - - /* - * check "[prefix]continuous-clock" - * SND_SOC_DAIFMT_CLOCK_MASK area - */ - snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix); - if (of_get_property(np, prop, NULL)) - format |= SND_SOC_DAIFMT_CONT; - else - format |= SND_SOC_DAIFMT_GATED; - - /* - * check "[prefix]bitclock-inversion" - * check "[prefix]frame-inversion" - * SND_SOC_DAIFMT_INV_MASK area - */ - snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix); - bit = !!of_get_property(np, prop, NULL); - - snprintf(prop, sizeof(prop), "%sframe-inversion", prefix); - frame = !!of_get_property(np, prop, NULL); - - switch ((bit << 4) + frame) { - case 0x11: - format |= SND_SOC_DAIFMT_IB_IF; - break; - case 0x10: - format |= SND_SOC_DAIFMT_IB_NF; - break; - case 0x01: - format |= SND_SOC_DAIFMT_NB_IF; - break; - default: - /* SND_SOC_DAIFMT_NB_NF is default */ - break; - } - - /* - * check "[prefix]bitclock-master" - * check "[prefix]frame-master" - * SND_SOC_DAIFMT_MASTER_MASK area - */ - snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); - bit = !!of_get_property(np, prop, NULL); - - snprintf(prop, sizeof(prop), "%sframe-master", prefix); - frame = !!of_get_property(np, prop, NULL); - - switch ((bit << 4) + frame) { - case 0x11: - format |= SND_SOC_DAIFMT_CBM_CFM; - break; - case 0x10: - format |= SND_SOC_DAIFMT_CBM_CFS; - break; - case 0x01: - format |= SND_SOC_DAIFMT_CBS_CFM; - break; - default: - format |= SND_SOC_DAIFMT_CBS_CFS; - break; - } - - return format; -} -EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); - static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index 1d6a9b3ceb27..258acadb9e7d 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -3255,16 +3255,14 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_dai_digital_mute(sink, 0, - SNDRV_PCM_STREAM_PLAYBACK); + ret = snd_soc_dai_digital_mute(sink, 0); if (ret != 0 && ret != -ENOTSUPP) dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret); ret = 0; break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_dai_digital_mute(sink, 1, - SNDRV_PCM_STREAM_PLAYBACK); + ret = snd_soc_dai_digital_mute(sink, 1); if (ret != 0 && ret != -ENOTSUPP) dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret); ret = 0; diff --git a/trunk/sound/soc/soc-pcm.c b/trunk/sound/soc/soc-pcm.c index 73bb8eefa491..cf191e6aebbe 100644 --- a/trunk/sound/soc/soc-pcm.c +++ b/trunk/sound/soc/soc-pcm.c @@ -383,7 +383,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) /* Muting the DAC suppresses artifacts caused during digital * shutdown, for example from stopping clocks. */ - snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_digital_mute(codec_dai, 1); if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); @@ -487,7 +488,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dapm_stream_event(rtd, substream->stream, SND_SOC_DAPM_STREAM_START); - snd_soc_dai_digital_mute(codec_dai, 0, substream->stream); + snd_soc_dai_digital_mute(codec_dai, 0); out: mutex_unlock(&rtd->pcm_mutex); @@ -585,7 +586,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) /* apply codec digital mute */ if (!codec->active) - snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); + snd_soc_dai_digital_mute(codec_dai, 1); /* free any machine hw params */ if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) @@ -1728,16 +1729,20 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) /* startup must always be called for new BEs */ ret = dpcm_be_dai_startup(fe, stream); - if (ret < 0) + if (ret < 0) { goto disconnect; + return ret; + } /* keep going if FE state is > open */ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN) return 0; ret = dpcm_be_dai_hw_params(fe, stream); - if (ret < 0) + if (ret < 0) { goto close; + return ret; + } /* keep going if FE state is > hw_params */ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS) @@ -1745,8 +1750,10 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) ret = dpcm_be_dai_prepare(fe, stream); - if (ret < 0) + if (ret < 0) { goto hw_free; + return ret; + } /* run the stream event for each BE */ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); diff --git a/trunk/sound/soc/tegra/Kconfig b/trunk/sound/soc/tegra/Kconfig index dbc27ce1d4de..19e5fe7cc403 100644 --- a/trunk/sound/soc/tegra/Kconfig +++ b/trunk/sound/soc/tegra/Kconfig @@ -6,16 +6,6 @@ config SND_SOC_TEGRA help Say Y or M here if you want support for SoC audio on Tegra. -config SND_SOC_TEGRA20_AC97 - tristate - depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC - select SND_SOC_AC97_BUS - select SND_SOC_TEGRA20_DAS - help - Say Y or M if you want to add support for codecs attached to the - Tegra20 AC97 interface. You will also need to select the individual - machine drivers to support below. - config SND_SOC_TEGRA20_DAS tristate depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC @@ -80,15 +70,6 @@ config SND_SOC_TEGRA_WM8903 boards using the WM8093 codec. Currently, the supported boards are Harmony, Ventana, Seaboard, Kaen, and Aebl. -config SND_SOC_TEGRA_WM9712 - tristate "SoC Audio support for Tegra boards using a WM9712 codec" - depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA20_AC97 - select SND_SOC_WM9712 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the WM9712 (or compatible) codec. - config SND_SOC_TEGRA_TRIMSLICE tristate "SoC Audio support for TrimSlice board" depends on SND_SOC_TEGRA && I2C diff --git a/trunk/sound/soc/tegra/Makefile b/trunk/sound/soc/tegra/Makefile index 416a14bde41b..391e78a34c06 100644 --- a/trunk/sound/soc/tegra/Makefile +++ b/trunk/sound/soc/tegra/Makefile @@ -1,7 +1,6 @@ # Tegra platform Support snd-soc-tegra-pcm-objs := tegra_pcm.o snd-soc-tegra-utils-objs += tegra_asoc_utils.o -snd-soc-tegra20-ac97-objs := tegra20_ac97.o snd-soc-tegra20-das-objs := tegra20_das.o snd-soc-tegra20-i2s-objs := tegra20_i2s.o snd-soc-tegra20-spdif-objs := tegra20_spdif.o @@ -10,7 +9,6 @@ snd-soc-tegra30-i2s-objs := tegra30_i2s.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o -obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o @@ -20,12 +18,10 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o # Tegra machine Support snd-soc-tegra-wm8753-objs := tegra_wm8753.o snd-soc-tegra-wm8903-objs := tegra_wm8903.o -snd-soc-tegra-wm9712-objs := tegra_wm9712.o snd-soc-tegra-trimslice-objs := trimslice.o snd-soc-tegra-alc5632-objs := tegra_alc5632.o obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o -obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o diff --git a/trunk/sound/soc/tegra/tegra20_ac97.c b/trunk/sound/soc/tegra/tegra20_ac97.c deleted file mode 100644 index 336dcdd3e8a4..000000000000 --- a/trunk/sound/soc/tegra/tegra20_ac97.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * tegra20_ac97.c - Tegra20 AC97 platform driver - * - * Copyright (c) 2012 Lucas Stach - * - * Partly based on code copyright/by: - * - * Copyright (c) 2011,2012 Toradex Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tegra_asoc_utils.h" -#include "tegra20_ac97.h" - -#define DRV_NAME "tegra20-ac97" - -static struct tegra20_ac97 *workdata; - -static void tegra20_ac97_codec_reset(struct snd_ac97 *ac97) -{ - u32 readback; - unsigned long timeout; - - /* reset line is not driven by DAC pad group, have to toggle GPIO */ - gpio_set_value(workdata->reset_gpio, 0); - udelay(2); - - gpio_set_value(workdata->reset_gpio, 1); - udelay(2); - - timeout = jiffies + msecs_to_jiffies(100); - - do { - regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback); - if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY) - break; - usleep_range(1000, 2000); - } while (!time_after(jiffies, timeout)); -} - -static void tegra20_ac97_codec_warm_reset(struct snd_ac97 *ac97) -{ - u32 readback; - unsigned long timeout; - - /* - * although sync line is driven by the DAC pad group warm reset using - * the controller cmd is not working, have to toggle sync line - * manually. - */ - gpio_request(workdata->sync_gpio, "codec-sync"); - - gpio_direction_output(workdata->sync_gpio, 1); - - udelay(2); - gpio_set_value(workdata->sync_gpio, 0); - udelay(2); - gpio_free(workdata->sync_gpio); - - timeout = jiffies + msecs_to_jiffies(100); - - do { - regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback); - if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY) - break; - usleep_range(1000, 2000); - } while (!time_after(jiffies, timeout)); -} - -static unsigned short tegra20_ac97_codec_read(struct snd_ac97 *ac97_snd, - unsigned short reg) -{ - u32 readback; - unsigned long timeout; - - regmap_write(workdata->regmap, TEGRA20_AC97_CMD, - (((reg | 0x80) << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) & - TEGRA20_AC97_CMD_CMD_ADDR_MASK) | - TEGRA20_AC97_CMD_BUSY); - - timeout = jiffies + msecs_to_jiffies(100); - - do { - regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback); - if (readback & TEGRA20_AC97_STATUS1_STA_VALID1) - break; - usleep_range(1000, 2000); - } while (!time_after(jiffies, timeout)); - - return ((readback & TEGRA20_AC97_STATUS1_STA_DATA1_MASK) >> - TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT); -} - -static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd, - unsigned short reg, unsigned short val) -{ - u32 readback; - unsigned long timeout; - - regmap_write(workdata->regmap, TEGRA20_AC97_CMD, - ((reg << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) & - TEGRA20_AC97_CMD_CMD_ADDR_MASK) | - ((val << TEGRA20_AC97_CMD_CMD_DATA_SHIFT) & - TEGRA20_AC97_CMD_CMD_DATA_MASK) | - TEGRA20_AC97_CMD_BUSY); - - timeout = jiffies + msecs_to_jiffies(100); - - do { - regmap_read(workdata->regmap, TEGRA20_AC97_CMD, &readback); - if (!(readback & TEGRA20_AC97_CMD_BUSY)) - break; - usleep_range(1000, 2000); - } while (!time_after(jiffies, timeout)); -} - -struct snd_ac97_bus_ops soc_ac97_ops = { - .read = tegra20_ac97_codec_read, - .write = tegra20_ac97_codec_write, - .reset = tegra20_ac97_codec_reset, - .warm_reset = tegra20_ac97_codec_warm_reset, -}; -EXPORT_SYMBOL_GPL(soc_ac97_ops); - -static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97) -{ - regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, - TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN, - TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN); - - regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL, - TEGRA20_AC97_CTRL_PCM_DAC_EN | - TEGRA20_AC97_CTRL_STM_EN, - TEGRA20_AC97_CTRL_PCM_DAC_EN | - TEGRA20_AC97_CTRL_STM_EN); -} - -static inline void tegra20_ac97_stop_playback(struct tegra20_ac97 *ac97) -{ - regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, - TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN, 0); - - regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL, - TEGRA20_AC97_CTRL_PCM_DAC_EN, 0); -} - -static inline void tegra20_ac97_start_capture(struct tegra20_ac97 *ac97) -{ - regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, - TEGRA20_AC97_FIFO_SCR_REC_FULL_EN, - TEGRA20_AC97_FIFO_SCR_REC_FULL_EN); -} - -static inline void tegra20_ac97_stop_capture(struct tegra20_ac97 *ac97) -{ - regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR, - TEGRA20_AC97_FIFO_SCR_REC_FULL_EN, 0); -} - -static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - tegra20_ac97_start_playback(ac97); - else - tegra20_ac97_start_capture(ac97); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - tegra20_ac97_stop_playback(ac97); - else - tegra20_ac97_stop_capture(ac97); - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { - .trigger = tegra20_ac97_trigger, -}; - -static int tegra20_ac97_probe(struct snd_soc_dai *dai) -{ - struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); - - dai->capture_dma_data = &ac97->capture_dma_data; - dai->playback_dma_data = &ac97->playback_dma_data; - - return 0; -} - -static struct snd_soc_dai_driver tegra20_ac97_dai = { - .name = "tegra-ac97-pcm", - .ac97_control = 1, - .probe = tegra20_ac97_probe, - .playback = { - .stream_name = "PCM Playback", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "PCM Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &tegra20_ac97_dai_ops, -}; - -static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case TEGRA20_AC97_CTRL: - case TEGRA20_AC97_CMD: - case TEGRA20_AC97_STATUS1: - case TEGRA20_AC97_FIFO1_SCR: - case TEGRA20_AC97_FIFO_TX1: - case TEGRA20_AC97_FIFO_RX1: - return true; - default: - break; - } - - return false; -} - -static bool tegra20_ac97_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case TEGRA20_AC97_STATUS1: - case TEGRA20_AC97_FIFO1_SCR: - case TEGRA20_AC97_FIFO_TX1: - case TEGRA20_AC97_FIFO_RX1: - return true; - default: - break; - } - - return false; -} - -static bool tegra20_ac97_precious_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case TEGRA20_AC97_FIFO_TX1: - case TEGRA20_AC97_FIFO_RX1: - return true; - default: - break; - } - - return false; -} - -static const struct regmap_config tegra20_ac97_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = TEGRA20_AC97_FIFO_RX1, - .writeable_reg = tegra20_ac97_wr_rd_reg, - .readable_reg = tegra20_ac97_wr_rd_reg, - .volatile_reg = tegra20_ac97_volatile_reg, - .precious_reg = tegra20_ac97_precious_reg, - .cache_type = REGCACHE_RBTREE, -}; - -static int tegra20_ac97_platform_probe(struct platform_device *pdev) -{ - struct tegra20_ac97 *ac97; - struct resource *mem, *memregion; - u32 of_dma[2]; - void __iomem *regs; - int ret = 0; - - ac97 = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_ac97), - GFP_KERNEL); - if (!ac97) { - dev_err(&pdev->dev, "Can't allocate tegra20_ac97\n"); - ret = -ENOMEM; - goto err; - } - dev_set_drvdata(&pdev->dev, ac97); - - ac97->clk_ac97 = clk_get(&pdev->dev, NULL); - if (IS_ERR(ac97->clk_ac97)) { - dev_err(&pdev->dev, "Can't retrieve ac97 clock\n"); - ret = PTR_ERR(ac97->clk_ac97); - goto err; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), DRV_NAME); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err_clk_put; - } - - regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_clk_put; - } - - ac97->regmap = devm_regmap_init_mmio(&pdev->dev, regs, - &tegra20_ac97_regmap_config); - if (IS_ERR(ac97->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); - ret = PTR_ERR(ac97->regmap); - goto err_clk_put; - } - - if (of_property_read_u32_array(pdev->dev.of_node, - "nvidia,dma-request-selector", - of_dma, 2) < 0) { - dev_err(&pdev->dev, "No DMA resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - - ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node, - "nvidia,codec-reset-gpio", 0); - if (gpio_is_valid(ac97->reset_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, ac97->reset_gpio, - GPIOF_OUT_INIT_HIGH, "codec-reset"); - if (ret) { - dev_err(&pdev->dev, "could not get codec-reset GPIO\n"); - goto err_clk_put; - } - } else { - dev_err(&pdev->dev, "no codec-reset GPIO supplied\n"); - goto err_clk_put; - } - - ac97->sync_gpio = of_get_named_gpio(pdev->dev.of_node, - "nvidia,codec-sync-gpio", 0); - if (!gpio_is_valid(ac97->sync_gpio)) { - dev_err(&pdev->dev, "no codec-sync GPIO supplied\n"); - goto err_clk_put; - } - - ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1; - ac97->capture_dma_data.wrap = 4; - ac97->capture_dma_data.width = 32; - ac97->capture_dma_data.req_sel = of_dma[1]; - - ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1; - ac97->playback_dma_data.wrap = 4; - ac97->playback_dma_data.width = 32; - ac97->playback_dma_data.req_sel = of_dma[1]; - - ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1); - if (ret) { - dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); - ret = -ENOMEM; - goto err_clk_put; - } - - ret = tegra_pcm_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; - } - - ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev); - if (ret) - goto err_unregister_pcm; - - ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data); - if (ret) - goto err_asoc_utils_fini; - - ret = clk_prepare_enable(ac97->clk_ac97); - if (ret) { - dev_err(&pdev->dev, "clk_enable failed: %d\n", ret); - goto err_asoc_utils_fini; - } - - /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */ - workdata = ac97; - - return 0; - -err_asoc_utils_fini: - tegra_asoc_utils_fini(&ac97->util_data); -err_unregister_pcm: - tegra_pcm_platform_unregister(&pdev->dev); -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); -err_clk_put: - clk_put(ac97->clk_ac97); -err: - return ret; -} - -static int tegra20_ac97_platform_remove(struct platform_device *pdev) -{ - struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev); - - tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); - - tegra_asoc_utils_fini(&ac97->util_data); - - clk_disable_unprepare(ac97->clk_ac97); - clk_put(ac97->clk_ac97); - - return 0; -} - -static const struct of_device_id tegra20_ac97_of_match[] = { - { .compatible = "nvidia,tegra20-ac97", }, - {}, -}; - -static struct platform_driver tegra20_ac97_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = tegra20_ac97_of_match, - }, - .probe = tegra20_ac97_platform_probe, - .remove = tegra20_ac97_platform_remove, -}; -module_platform_driver(tegra20_ac97_driver); - -MODULE_AUTHOR("Lucas Stach"); -MODULE_DESCRIPTION("Tegra20 AC97 ASoC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra20_ac97_of_match); diff --git a/trunk/sound/soc/tegra/tegra20_ac97.h b/trunk/sound/soc/tegra/tegra20_ac97.h deleted file mode 100644 index dddc6828004e..000000000000 --- a/trunk/sound/soc/tegra/tegra20_ac97.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * tegra20_ac97.h - Definitions for the Tegra20 AC97 controller driver - * - * Copyright (c) 2012 Lucas Stach - * - * Partly based on code copyright/by: - * - * Copyright (c) 2011,2012 Toradex Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#ifndef __TEGRA20_AC97_H__ -#define __TEGRA20_AC97_H__ - -#include "tegra_pcm.h" - -#define TEGRA20_AC97_CTRL 0x00 -#define TEGRA20_AC97_CMD 0x04 -#define TEGRA20_AC97_STATUS1 0x08 -/* ... */ -#define TEGRA20_AC97_FIFO1_SCR 0x1c -/* ... */ -#define TEGRA20_AC97_FIFO_TX1 0x40 -#define TEGRA20_AC97_FIFO_RX1 0x80 - -/* TEGRA20_AC97_CTRL */ -#define TEGRA20_AC97_CTRL_STM2_EN (1 << 16) -#define TEGRA20_AC97_CTRL_DOUBLE_SAMPLING_EN (1 << 11) -#define TEGRA20_AC97_CTRL_IO_CNTRL_EN (1 << 10) -#define TEGRA20_AC97_CTRL_HSET_DAC_EN (1 << 9) -#define TEGRA20_AC97_CTRL_LINE2_DAC_EN (1 << 8) -#define TEGRA20_AC97_CTRL_PCM_LFE_EN (1 << 7) -#define TEGRA20_AC97_CTRL_PCM_SUR_EN (1 << 6) -#define TEGRA20_AC97_CTRL_PCM_CEN_DAC_EN (1 << 5) -#define TEGRA20_AC97_CTRL_LINE1_DAC_EN (1 << 4) -#define TEGRA20_AC97_CTRL_PCM_DAC_EN (1 << 3) -#define TEGRA20_AC97_CTRL_COLD_RESET (1 << 2) -#define TEGRA20_AC97_CTRL_WARM_RESET (1 << 1) -#define TEGRA20_AC97_CTRL_STM_EN (1 << 0) - -/* TEGRA20_AC97_CMD */ -#define TEGRA20_AC97_CMD_CMD_ADDR_SHIFT 24 -#define TEGRA20_AC97_CMD_CMD_ADDR_MASK (0xff << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) -#define TEGRA20_AC97_CMD_CMD_DATA_SHIFT 8 -#define TEGRA20_AC97_CMD_CMD_DATA_MASK (0xffff << TEGRA20_AC97_CMD_CMD_DATA_SHIFT) -#define TEGRA20_AC97_CMD_CMD_ID_SHIFT 2 -#define TEGRA20_AC97_CMD_CMD_ID_MASK (0x3 << TEGRA20_AC97_CMD_CMD_ID_SHIFT) -#define TEGRA20_AC97_CMD_BUSY (1 << 0) - -/* TEGRA20_AC97_STATUS1 */ -#define TEGRA20_AC97_STATUS1_STA_ADDR1_SHIFT 24 -#define TEGRA20_AC97_STATUS1_STA_ADDR1_MASK (0xff << TEGRA20_AC97_STATUS1_STA_ADDR1_SHIFT) -#define TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT 8 -#define TEGRA20_AC97_STATUS1_STA_DATA1_MASK (0xffff << TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT) -#define TEGRA20_AC97_STATUS1_STA_VALID1 (1 << 2) -#define TEGRA20_AC97_STATUS1_STANDBY1 (1 << 1) -#define TEGRA20_AC97_STATUS1_CODEC1_RDY (1 << 0) - -/* TEGRA20_AC97_FIFO1_SCR */ -#define TEGRA20_AC97_FIFO_SCR_REC_MT_CNT_SHIFT 27 -#define TEGRA20_AC97_FIFO_SCR_REC_MT_CNT_MASK (0x1f << TEGRA20_AC97_FIFO_SCR_REC_MT_CNT_SHIFT) -#define TEGRA20_AC97_FIFO_SCR_PB_MT_CNT_SHIFT 22 -#define TEGRA20_AC97_FIFO_SCR_PB_MT_CNT_MASK (0x1f << TEGRA20_AC97_FIFO_SCR_PB_MT_CNT_SHIFT) -#define TEGRA20_AC97_FIFO_SCR_REC_OVERRUN_INT_STA (1 << 19) -#define TEGRA20_AC97_FIFO_SCR_PB_UNDERRUN_INT_STA (1 << 18) -#define TEGRA20_AC97_FIFO_SCR_REC_FORCE_MT (1 << 17) -#define TEGRA20_AC97_FIFO_SCR_PB_FORCE_MT (1 << 16) -#define TEGRA20_AC97_FIFO_SCR_REC_FULL_EN (1 << 15) -#define TEGRA20_AC97_FIFO_SCR_REC_3QRT_FULL_EN (1 << 14) -#define TEGRA20_AC97_FIFO_SCR_REC_QRT_FULL_EN (1 << 13) -#define TEGRA20_AC97_FIFO_SCR_REC_EMPTY_EN (1 << 12) -#define TEGRA20_AC97_FIFO_SCR_PB_NOT_FULL_EN (1 << 11) -#define TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN (1 << 10) -#define TEGRA20_AC97_FIFO_SCR_PB_3QRT_MT_EN (1 << 9) -#define TEGRA20_AC97_FIFO_SCR_PB_EMPTY_MT_EN (1 << 8) - -struct tegra20_ac97 { - struct clk *clk_ac97; - struct tegra_pcm_dma_params capture_dma_data; - struct tegra_pcm_dma_params playback_dma_data; - struct regmap *regmap; - int reset_gpio; - int sync_gpio; - struct tegra_asoc_utils_data util_data; -}; -#endif /* __TEGRA20_AC97_H__ */ diff --git a/trunk/sound/soc/tegra/tegra20_das.c b/trunk/sound/soc/tegra/tegra20_das.c index e72392927bd2..654318483877 100644 --- a/trunk/sound/soc/tegra/tegra20_das.c +++ b/trunk/sound/soc/tegra/tegra20_das.c @@ -191,19 +191,6 @@ static int tegra20_das_probe(struct platform_device *pdev) goto err; } - ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_3, - TEGRA20_DAS_DAP_SEL_DAC3); - if (ret) { - dev_err(&pdev->dev, "Can't set up DAS DAP connection\n"); - goto err; - } - ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_3, - TEGRA20_DAS_DAC_SEL_DAP3); - if (ret) { - dev_err(&pdev->dev, "Can't set up DAS DAC connection\n"); - goto err; - } - platform_set_drvdata(pdev, das); return 0; diff --git a/trunk/sound/soc/tegra/tegra30_ahub.c b/trunk/sound/soc/tegra/tegra30_ahub.c index dd146f10fef2..f354dc390a0b 100644 --- a/trunk/sound/soc/tegra/tegra30_ahub.c +++ b/trunk/sound/soc/tegra/tegra30_ahub.c @@ -580,7 +580,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) clk_put(ahub->clk_apbif); err_clk_put_d_audio: clk_put(ahub->clk_d_audio); - ahub = NULL; + ahub = 0; err: return ret; } @@ -597,7 +597,7 @@ static int tegra30_ahub_remove(struct platform_device *pdev) clk_put(ahub->clk_apbif); clk_put(ahub->clk_d_audio); - ahub = NULL; + ahub = 0; return 0; } diff --git a/trunk/sound/soc/tegra/tegra30_i2s.c b/trunk/sound/soc/tegra/tegra30_i2s.c index f4e1ce82750a..27e91dd0b91c 100644 --- a/trunk/sound/soc/tegra/tegra30_i2s.c +++ b/trunk/sound/soc/tegra/tegra30_i2s.c @@ -71,7 +71,7 @@ static int tegra30_i2s_runtime_resume(struct device *dev) return 0; } -static int tegra30_i2s_startup(struct snd_pcm_substream *substream, +int tegra30_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -98,7 +98,7 @@ static int tegra30_i2s_startup(struct snd_pcm_substream *substream, return ret; } -static void tegra30_i2s_shutdown(struct snd_pcm_substream *substream, +void tegra30_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); diff --git a/trunk/sound/soc/tegra/tegra_asoc_utils.c b/trunk/sound/soc/tegra/tegra_asoc_utils.c index ba419f86384d..6872c77a1196 100644 --- a/trunk/sound/soc/tegra/tegra_asoc_utils.c +++ b/trunk/sound/soc/tegra/tegra_asoc_utils.c @@ -112,59 +112,6 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, } EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate); -int tegra_asoc_utils_set_ac97_rate(struct tegra_asoc_utils_data *data) -{ - const int pll_rate = 73728000; - const int ac97_rate = 24576000; - int err; - - clk_disable_unprepare(data->clk_cdev1); - clk_disable_unprepare(data->clk_pll_a_out0); - clk_disable_unprepare(data->clk_pll_a); - - /* - * AC97 rate is fixed at 24.576MHz and is used for both the host - * controller and the external codec - */ - err = clk_set_rate(data->clk_pll_a, pll_rate); - if (err) { - dev_err(data->dev, "Can't set pll_a rate: %d\n", err); - return err; - } - - err = clk_set_rate(data->clk_pll_a_out0, ac97_rate); - if (err) { - dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err); - return err; - } - - /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */ - - err = clk_prepare_enable(data->clk_pll_a); - if (err) { - dev_err(data->dev, "Can't enable pll_a: %d\n", err); - return err; - } - - err = clk_prepare_enable(data->clk_pll_a_out0); - if (err) { - dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err); - return err; - } - - err = clk_prepare_enable(data->clk_cdev1); - if (err) { - dev_err(data->dev, "Can't enable cdev1: %d\n", err); - return err; - } - - data->set_baseclock = pll_rate; - data->set_mclk = ac97_rate; - - return 0; -} -EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_ac97_rate); - int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, struct device *dev) { diff --git a/trunk/sound/soc/tegra/tegra_asoc_utils.h b/trunk/sound/soc/tegra/tegra_asoc_utils.h index 974c9f8830f9..44db1dbb8f21 100644 --- a/trunk/sound/soc/tegra/tegra_asoc_utils.h +++ b/trunk/sound/soc/tegra/tegra_asoc_utils.h @@ -43,7 +43,6 @@ struct tegra_asoc_utils_data { int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, int mclk); -int tegra_asoc_utils_set_ac97_rate(struct tegra_asoc_utils_data *data); int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, struct device *dev); void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); diff --git a/trunk/sound/soc/tegra/tegra_wm9712.c b/trunk/sound/soc/tegra/tegra_wm9712.c deleted file mode 100644 index 68d42403d9b5..000000000000 --- a/trunk/sound/soc/tegra/tegra_wm9712.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * tegra20_wm9712.c - Tegra machine ASoC driver for boards using WM9712 codec. - * - * Copyright 2012 Lucas Stach - * - * Partly based on code copyright/by: - * Copyright 2011,2012 Toradex Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define DRV_NAME "tegra-snd-wm9712" - -struct tegra_wm9712 { - struct platform_device *codec; -}; - -static const struct snd_soc_dapm_widget tegra_wm9712_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_LINE("LineIn", NULL), - SND_SOC_DAPM_MIC("Mic", NULL), -}; - -static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); - - return snd_soc_dapm_sync(dapm); -} - -static struct snd_soc_dai_link tegra_wm9712_dai = { - .name = "AC97 HiFi", - .stream_name = "AC97 HiFi", - .cpu_dai_name = "tegra-ac97-pcm", - .codec_dai_name = "wm9712-hifi", - .codec_name = "wm9712-codec", - .init = tegra_wm9712_init, -}; - -static struct snd_soc_card snd_soc_tegra_wm9712 = { - .name = "tegra-wm9712", - .owner = THIS_MODULE, - .dai_link = &tegra_wm9712_dai, - .num_links = 1, - - .dapm_widgets = tegra_wm9712_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_wm9712_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_wm9712_driver_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_wm9712; - struct tegra_wm9712 *machine; - int ret; - - if (!pdev->dev.of_node) { - dev_err(&pdev->dev, "No platform data supplied\n"); - return -EINVAL; - } - - machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712), - GFP_KERNEL); - if (!machine) { - dev_err(&pdev->dev, "Can't allocate tegra_wm9712 struct\n"); - return -ENOMEM; - } - - card->dev = &pdev->dev; - platform_set_drvdata(pdev, card); - snd_soc_card_set_drvdata(card, machine); - - machine->codec = platform_device_alloc("wm9712-codec", -1); - if (!machine->codec) { - dev_err(&pdev->dev, "Can't allocate wm9712 platform device\n"); - return -ENOMEM; - } - - ret = platform_device_add(machine->codec); - if (ret) - goto codec_put; - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - goto codec_unregister; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - goto codec_unregister; - - tegra_wm9712_dai.cpu_of_node = of_parse_phandle(np, - "nvidia,ac97-controller", 0); - if (!tegra_wm9712_dai.cpu_of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,ac97-controller' missing or invalid\n"); - ret = -EINVAL; - goto codec_unregister; - } - - tegra_wm9712_dai.platform_of_node = tegra_wm9712_dai.cpu_of_node; - - ret = snd_soc_register_card(card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - goto codec_unregister; - } - - return 0; - -codec_unregister: - platform_device_del(machine->codec); -codec_put: - platform_device_put(machine->codec); - return ret; -} - -static int tegra_wm9712_driver_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct tegra_wm9712 *machine = snd_soc_card_get_drvdata(card); - - snd_soc_unregister_card(card); - - platform_device_unregister(machine->codec); - - return 0; -} - -static const struct of_device_id tegra_wm9712_of_match[] = { - { .compatible = "nvidia,tegra-audio-wm9712", }, - {}, -}; - -static struct platform_driver tegra_wm9712_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_wm9712_of_match, - }, - .probe = tegra_wm9712_driver_probe, - .remove = tegra_wm9712_driver_remove, -}; -module_platform_driver(tegra_wm9712_driver); - -MODULE_AUTHOR("Lucas Stach"); -MODULE_DESCRIPTION("Tegra+WM9712 machine ASoC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_wm9712_of_match); diff --git a/trunk/sound/soc/ux500/mop500.c b/trunk/sound/soc/ux500/mop500.c index 204b899c2311..ae6990738783 100644 --- a/trunk/sound/soc/ux500/mop500.c +++ b/trunk/sound/soc/ux500/mop500.c @@ -24,7 +24,7 @@ #include "ux500_pcm.h" #include "ux500_msp_dai.h" -#include "mop500_ab8500.h" +#include /* Define the whole MOP500 soundcard, linking platform to the codec-drivers */ struct snd_soc_dai_link mop500_dai_links[] = {