diff options
338 files changed, 7906 insertions, 2749 deletions
@@ -1823,6 +1823,11 @@ S: Kattreinstr 38 S: D-64295 S: Germany +N: Avi Kivity +E: avi.kivity@gmail.com +D: Kernel-based Virtual Machine (KVM) +S: Ra'annana, Israel + N: Andi Kleen E: andi@firstfloor.org U: http://www.halobates.de diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt new file mode 100644 index 000000000000..38e51ad2e07e --- /dev/null +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -0,0 +1,15 @@ +* Atmel SSC driver. + +Required properties: +- compatible: "atmel,at91rm9200-ssc" or "atmel,at91sam9g45-ssc" + - atmel,at91rm9200-ssc: support pdc transfer + - atmel,at91sam9g45-ssc: support dma transfer +- reg: Should contain SSC registers location and length +- interrupts: Should contain SSC interrupt + +Example: +ssc0: ssc@fffbc000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffbc000 0x4000>; + interrupts = <14 4 5>; +}; diff --git a/Documentation/devicetree/bindings/net/mdio-gpio.txt b/Documentation/devicetree/bindings/net/mdio-gpio.txt index bc9549529014..c79bab025369 100644 --- a/Documentation/devicetree/bindings/net/mdio-gpio.txt +++ b/Documentation/devicetree/bindings/net/mdio-gpio.txt @@ -8,9 +8,16 @@ gpios property as described in section VIII.1 in the following order: MDC, MDIO. +Note: Each gpio-mdio bus should have an alias correctly numbered in "aliases" +node. + Example: -mdio { +aliases { + mdio-gpio0 = <&mdio0>; +}; + +mdio0: mdio { compatible = "virtual,mdio-gpio"; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/sound/ak4104.txt b/Documentation/devicetree/bindings/sound/ak4104.txt new file mode 100644 index 000000000000..b902ee39cf89 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ak4104.txt @@ -0,0 +1,22 @@ +AK4104 S/PDIF transmitter + +This device supports SPI mode only. + +Required properties: + + - compatible : "asahi-kasei,ak4104" + + - reg : The chip select number on the SPI bus + +Optional properties: + + - reset-gpio : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the device starts. + +Example: + +spdif: ak4104@0 { + compatible = "asahi-kasei,ak4104"; + reg = <0>; + spi-max-frequency = <5000000>; +}; diff --git a/Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt b/Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt new file mode 100644 index 000000000000..9c5a9947b64d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt @@ -0,0 +1,26 @@ +* Atmel at91sam9g20ek wm8731 audio complex + +Required properties: + - compatible: "atmel,at91sam9g20ek-wm8731-audio" + - atmel,model: The user-visible name of this sound complex. + - atmel,audio-routing: A list of the connections between audio components. + - atmel,ssc-controller: The phandle of the SSC controller + - atmel,audio-codec: The phandle of the WM8731 audio codec +Optional properties: + - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt + +Example: +sound { + compatible = "atmel,at91sam9g20ek-wm8731-audio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_mck>; + + atmel,model = "wm8731 @ AT91SAMG20EK"; + + atmel,audio-routing = + "Ext Spk", "LHPOUT", + "Int MIC", "MICIN"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8731>; +}; diff --git a/Documentation/devicetree/bindings/sound/cs4271.txt b/Documentation/devicetree/bindings/sound/cs4271.txt index c81b5fd5a5bc..a850fb9c88ea 100644 --- a/Documentation/devicetree/bindings/sound/cs4271.txt +++ b/Documentation/devicetree/bindings/sound/cs4271.txt @@ -18,6 +18,8 @@ Optional properties: - reset-gpio: a GPIO spec to define which pin is connected to the chip's !RESET pin + - cirrus,amuteb-eq-bmutec: When given, the Codec's AMUTEB=BMUTEC flag + is enabled. Examples: diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt index 65dec876cb2d..fd40c852d7c7 100644 --- a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt +++ b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt @@ -12,7 +12,7 @@ Required properties: Optional properties: - ti,dmic: phandle for the OMAP dmic node if the machine have it connected -- ti,jack_detection: Need to be set to <1> if the board capable to detect jack +- ti,jack_detection: Need to be present if the board capable to detect jack insertion, removal. Available audio endpoints for the audio-routing table: @@ -59,7 +59,7 @@ sound { compatible = "ti,abe-twl6040"; ti,model = "SDP4430"; - ti,jack-detection = <1>; + ti,jack-detection; ti,mclk-freq = <38400000>; ti,mcpdm = <&mcpdm>; diff --git a/Documentation/networking/vxlan.txt b/Documentation/networking/vxlan.txt index 5b34b762d7d5..6d993510f091 100644 --- a/Documentation/networking/vxlan.txt +++ b/Documentation/networking/vxlan.txt @@ -32,7 +32,7 @@ no entry is in the forwarding table. # ip link delete vxlan0 3. Show vxlan info - # ip -d show vxlan0 + # ip -d link show vxlan0 It is possible to create, destroy and display the vxlan forwarding table using the new bridge command. @@ -41,7 +41,7 @@ forwarding table using the new bridge command. # bridge fdb add to 00:17:42:8a:b4:05 dst 192.19.0.2 dev vxlan0 2. Delete forwarding table entry - # bridge fdb delete 00:17:42:8a:b4:05 + # bridge fdb delete 00:17:42:8a:b4:05 dev vxlan0 3. Show forwarding table # bridge fdb show dev vxlan0 diff --git a/MAINTAINERS b/MAINTAINERS index bb0b27db673f..9386a63ea8f6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -526,17 +526,17 @@ F: drivers/video/geode/ F: arch/x86/include/asm/geode.h AMD IOMMU (AMD-VI) -M: Joerg Roedel <joerg.roedel@amd.com> +M: Joerg Roedel <joro@8bytes.org> L: iommu@lists.linux-foundation.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git -S: Supported +S: Maintained F: drivers/iommu/amd_iommu*.[ch] F: include/linux/amd-iommu.h AMD MICROCODE UPDATE SUPPORT -M: Andreas Herrmann <andreas.herrmann3@amd.com> +M: Andreas Herrmann <herrmann.der.user@googlemail.com> L: amd64-microcode@amd64.org -S: Supported +S: Maintained F: arch/x86/kernel/microcode_amd.c AMS (Apple Motion Sensor) DRIVER @@ -841,6 +841,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git F: arch/arm/mach-sa1100/jornada720.c F: arch/arm/mach-sa1100/include/mach/jornada720.h +ARM/IGEP MACHINE SUPPORT +M: Enric Balletbo i Serra <eballetbo@gmail.com> +M: Javier Martinez Canillas <javier@dowhile0.org> +L: linux-omap@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-omap2/board-igep0020.c + ARM/INCOME PXA270 SUPPORT M: Marek Vasut <marek.vasut@gmail.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2708,10 +2716,10 @@ F: include/linux/edac.h EDAC-AMD64 M: Doug Thompson <dougthompson@xmission.com> -M: Borislav Petkov <borislav.petkov@amd.com> +M: Borislav Petkov <bp@alien8.de> L: linux-edac@vger.kernel.org W: bluesmoke.sourceforge.net -S: Supported +S: Maintained F: drivers/edac/amd64_edac* EDAC-E752X @@ -3753,7 +3761,7 @@ S: Maintained F: drivers/platform/x86/ideapad-laptop.c IDE/ATAPI DRIVERS -M: Borislav Petkov <petkovbb@gmail.com> +M: Borislav Petkov <bp@alien8.de> L: linux-ide@vger.kernel.org S: Maintained F: Documentation/cdrom/ide-cd @@ -4280,8 +4288,8 @@ F: include/linux/lockd/ F: include/linux/sunrpc/ KERNEL VIRTUAL MACHINE (KVM) -M: Avi Kivity <avi@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com> +M: Gleb Natapov <gleb@redhat.com> L: kvm@vger.kernel.org W: http://kvm.qumranet.com S: Supported @@ -5413,7 +5421,7 @@ S: Maintained F: sound/drivers/opl4/ OPROFILE -M: Robert Richter <robert.richter@amd.com> +M: Robert Richter <rric@kernel.org> L: oprofile-list@lists.sf.net S: Maintained F: arch/*/include/asm/oprofile*.h @@ -8198,7 +8206,7 @@ F: drivers/platform/x86 X86 MCE INFRASTRUCTURE M: Tony Luck <tony.luck@intel.com> -M: Borislav Petkov <bp@amd64.org> +M: Borislav Petkov <bp@alien8.de> L: linux-edac@vger.kernel.org S: Maintained F: arch/x86/kernel/cpu/mcheck/* @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 7 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Terrified Chipmunk # *DOCUMENTATION* diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 1e6956a90608..14db93e4c8a8 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -445,7 +445,7 @@ struct procfs_args { * unhappy with OSF UFS. [CHECKME] */ static int -osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) +osf_ufs_mount(const char *dirname, struct ufs_args __user *args, int flags) { int retval; struct cdfs_args tmp; @@ -465,7 +465,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) } static int -osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) +osf_cdfs_mount(const char *dirname, struct cdfs_args __user *args, int flags) { int retval; struct cdfs_args tmp; @@ -485,7 +485,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) } static int -osf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags) +osf_procfs_mount(const char *dirname, struct procfs_args __user *args, int flags) { struct procfs_args tmp; diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index d410581a5a85..aaa42d8d4f88 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -29,6 +29,7 @@ tcb0 = &tcb0; tcb1 = &tcb1; i2c0 = &i2c0; + ssc0 = &ssc0; }; cpus { cpu@0 { @@ -212,6 +213,13 @@ status = "disabled"; }; + ssc0: ssc@fffbc000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffbc000 0x4000>; + interrupts = <14 4 5>; + status = "disable"; + }; + adc0: adc@fffe0000 { compatible = "atmel,at91sam9260-adc"; reg = <0xfffe0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index 3e6e5c1abbf3..3b721ee59b10 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -25,6 +25,8 @@ gpio4 = &pioE; tcb0 = &tcb0; i2c0 = &i2c0; + ssc0 = &ssc0; + ssc1 = &ssc1; }; cpus { cpu@0 { @@ -173,6 +175,20 @@ status = "disabled"; }; + ssc0: ssc@fff98000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfff98000 0x4000>; + interrupts = <16 4 5>; + status = "disable"; + }; + + ssc1: ssc@fff9c000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfff9c000 0x4000>; + interrupts = <17 4 5>; + status = "disable"; + }; + macb0: ethernet@fffbc000 { compatible = "cdns,at32ap7000-macb", "cdns,macb"; reg = <0xfffbc000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi index e6391a4e6649..2dcec8de759f 100644 --- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi @@ -30,6 +30,16 @@ ahb { apb { + pinctrl@fffff400 { + board { + pinctrl_pck0_as_mck: pck0_as_mck { + atmel,pins = + <2 1 0x2 0x0>; /* PC1 periph B */ + }; + + }; + }; + dbgu: serial@fffff200 { status = "okay"; }; @@ -51,6 +61,11 @@ atmel,vbus-gpio = <&pioC 5 0>; status = "okay"; }; + + ssc0: ssc@fffbc000 { + status = "okay"; + pinctrl-0 = <&pinctrl_ssc0_tx>; + }; }; nand0: nand@40000000 { @@ -114,7 +129,7 @@ reg = <0x50>; }; - wm8731@1b { + wm8731: wm8731@1b { compatible = "wm8731"; reg = <0x1b>; }; @@ -139,4 +154,19 @@ gpio-key,wakeup; }; }; + + sound { + compatible = "atmel,at91sam9g20ek-wm8731-audio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_mck>; + + atmel,model = "wm8731 @ AT91SAMG20EK"; + + atmel,audio-routing = + "Ext Spk", "LHPOUT", + "Int Mic", "MICIN"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8731>; + }; }; diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 3add030d61f8..acfa207162ff 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -31,6 +31,8 @@ tcb1 = &tcb1; i2c0 = &i2c0; i2c1 = &i2c1; + ssc0 = &ssc0; + ssc1 = &ssc1; }; cpus { cpu@0 { @@ -226,6 +228,20 @@ status = "disabled"; }; + ssc0: ssc@fff9c000 { + compatible = "atmel,at91sam9g45-ssc"; + reg = <0xfff9c000 0x4000>; + interrupts = <16 4 5>; + status = "disable"; + }; + + ssc1: ssc@fffa0000 { + compatible = "atmel,at91sam9g45-ssc"; + reg = <0xfffa0000 0x4000>; + interrupts = <17 4 5>; + status = "disable"; + }; + adc0: adc@fffb0000 { compatible = "atmel,at91sam9260-adc"; reg = <0xfffb0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 03fc136421c5..69667d0ac347 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -30,6 +30,7 @@ i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; + ssc0 = &ssc0; }; cpus { cpu@0 { @@ -87,6 +88,13 @@ interrupts = <1 4 7>; }; + ssc0: ssc@f0010000 { + compatible = "atmel,at91sam9g45-ssc"; + reg = <0xf0010000 0x4000>; + interrupts = <28 4 5>; + status = "disable"; + }; + tcb0: timer@f8008000 { compatible = "atmel,at91sam9x5-tcb"; reg = <0xf8008000 0x100>; diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 5269825194a8..af47c75db513 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -184,9 +184,12 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "fffd0000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffd4000.ssc", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fffd8000.ssc", &ssc2_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200.0", &twi_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 3cee0e6ea7c3..9e76427aaec2 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -752,7 +752,7 @@ static struct resource ssc0_resources[] = { }; static struct platform_device at91rm9200_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -794,7 +794,7 @@ static struct resource ssc1_resources[] = { }; static struct platform_device at91rm9200_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, @@ -836,7 +836,7 @@ static struct resource ssc2_resources[] = { }; static struct platform_device at91rm9200_ssc2_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 2, .dev = { .dma_mask = &ssc2_dmamask, diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index f8202615f4a8..a41eb3d23f68 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -210,7 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk), + CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi_clk), /* more usart lookup table for DT entries */ diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 414bd855fb0c..e67cfa2acbe0 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -742,7 +742,7 @@ static struct resource ssc_resources[] = { }; static struct platform_device at91sam9260_ssc_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc_dmamask, diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 04295c04b3e0..7fcbe0583342 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -174,9 +174,12 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc2_clk), CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261.0", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi_clk), diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index cd604aad8e96..a27d9dd0faa4 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -706,7 +706,7 @@ static struct resource ssc0_resources[] = { }; static struct platform_device at91sam9261_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -748,7 +748,7 @@ static struct resource ssc1_resources[] = { }; static struct platform_device at91sam9261_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, @@ -790,7 +790,7 @@ static struct resource ssc2_resources[] = { }; static struct platform_device at91sam9261_ssc2_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 2, .dev = { .dma_mask = &ssc2_dmamask, diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index d6f9c23927c4..c0f4c8c1f4ed 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -186,8 +186,10 @@ static struct clk *periph_clocks[] __initdata = { static struct clk_lookup periph_clocks_lookups[] = { /* One additional fake clock for macb_hclk */ CLKDEV_CON_ID("hclk", &macb_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fff98000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc1_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 9c61e59a2104..8215839f2d54 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -1199,7 +1199,7 @@ static struct resource ssc0_resources[] = { }; static struct platform_device at91sam9263_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -1241,7 +1241,7 @@ static struct resource ssc1_resources[] = { }; static struct platform_device at91sam9263_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 84af1b506d92..a4282d3742bf 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -239,8 +239,10 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffa0000.ssc", &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk), CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk), CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk), diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index fcd233cb33d2..d26474a97fec 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -1459,7 +1459,7 @@ static struct resource ssc0_resources[] = { }; static struct platform_device at91sam9g45_ssc0_device = { - .name = "ssc", + .name = "at91sam9g45_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -1501,7 +1501,7 @@ static struct resource ssc1_resources[] = { }; static struct platform_device at91sam9g45_ssc1_device = { - .name = "ssc", + .name = "at91sam9g45_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 72e908412222..b683fdc699f1 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -184,8 +184,10 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index 5047bdc92adf..b656110e8afe 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -832,7 +832,7 @@ static struct resource ssc0_resources[] = { }; static struct platform_device at91sam9rl_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -874,7 +874,7 @@ static struct resource ssc1_resources[] = { }; static struct platform_device at91sam9rl_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index e5035380dcbc..18fbbb27f97f 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -231,6 +231,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk), CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk), CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk), + CLKDEV_CON_DEV_ID("pclk", "f0010000.ssc", &ssc_clk), CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk), CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk), diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 3ab2b86a3762..ebdbf42c02c1 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -353,6 +353,16 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = { }, }; +static struct platform_device sam9g20ek_audio_device = { + .name = "at91sam9g20ek-audio", + .id = -1, +}; + +static void __init ek_add_device_audio(void) +{ + platform_device_register(&sam9g20ek_audio_device); +} + static void __init ek_board_init(void) { @@ -394,6 +404,7 @@ static void __init ek_board_init(void) at91_set_B_periph(AT91_PIN_PC1, 0); /* SSC (for WM8731) */ at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX); + ek_add_device_audio(); } MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK") diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 32ee3f895967..d9bc3fa7bb22 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -762,16 +762,19 @@ static u8 da850_iis_serializer_direction[] = { }; static struct snd_platform_data da850_evm_snd_data = { - .tx_dma_offset = 0x2000, - .rx_dma_offset = 0x2000, - .op_mode = DAVINCI_MCASP_IIS_MODE, - .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction), - .tdm_slots = 2, - .serial_dir = da850_iis_serializer_direction, - .asp_chan_q = EVENTQ_0, - .version = MCASP_VERSION_2, - .txnumevt = 1, - .rxnumevt = 1, + .tx_dma_offset = 0x2000, + .rx_dma_offset = 0x2000, + .op_mode = DAVINCI_MCASP_IIS_MODE, + .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction), + .tdm_slots = 2, + .serial_dir = da850_iis_serializer_direction, + .asp_chan_q = EVENTQ_0, + .ram_chan_q = EVENTQ_1, + .version = MCASP_VERSION_2, + .txnumevt = 1, + .rxnumevt = 1, + .sram_size_playback = SZ_8K, + .sram_size_capture = SZ_8K, }; static const short da850_evm_mcasp_pins[] __initconst = { @@ -1509,6 +1512,7 @@ static __init void da850_evm_init(void) pr_warning("da850_evm_init: mcasp mux setup failed: %d\n", ret); + da850_evm_snd_data.sram_pool = sram_get_gen_pool(); da8xx_register_mcasp(0, &da850_evm_snd_data); ret = davinci_cfg_reg_list(da850_lcdcntl_pins); diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index cd0c8b1e1ecf..14e9947bad6e 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -713,8 +713,7 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, break; case VPBE_ENC_CUSTOM_TIMINGS: if (pclock <= 27000000) { - v |= DM644X_VPSS_MUXSEL_PLL2_MODE | - DM644X_VPSS_DACCLKEN; + v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); } else { /* diff --git a/arch/arm/mach-exynos/dma.c b/arch/arm/mach-exynos/dma.c index 21d568b3b149..87e07d6fc615 100644 --- a/arch/arm/mach-exynos/dma.c +++ b/arch/arm/mach-exynos/dma.c @@ -275,6 +275,9 @@ static int __init exynos_dma_init(void) exynos_pdma1_pdata.nr_valid_peri = ARRAY_SIZE(exynos4210_pdma1_peri); exynos_pdma1_pdata.peri_id = exynos4210_pdma1_peri; + + if (samsung_rev() == EXYNOS4210_REV_0) + exynos_mdma1_device.res.start = EXYNOS4_PA_S_MDMA1; } else if (soc_is_exynos4212() || soc_is_exynos4412()) { exynos_pdma0_pdata.nr_valid_peri = ARRAY_SIZE(exynos4212_pdma0_peri); diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 8480849affb9..ed4da4544cd2 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -90,6 +90,7 @@ #define EXYNOS4_PA_MDMA0 0x10810000 #define EXYNOS4_PA_MDMA1 0x12850000 +#define EXYNOS4_PA_S_MDMA1 0x12840000 #define EXYNOS4_PA_PDMA0 0x12680000 #define EXYNOS4_PA_PDMA1 0x12690000 #define EXYNOS5_PA_MDMA0 0x10800000 diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c index 3f37a5e8a1f4..b938f9fc1dd1 100644 --- a/arch/arm/mach-exynos/mach-armlex4210.c +++ b/arch/arm/mach-exynos/mach-armlex4210.c @@ -147,7 +147,6 @@ static struct platform_device *armlex4210_devices[] __initdata = { &s3c_device_hsmmc3, &s3c_device_rtc, &s3c_device_wdt, - &samsung_asoc_dma, &armlex4210_smsc911x, &exynos4_device_ahci, }; diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index ee4fb1a9cb72..5de9ee28a508 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -311,7 +311,6 @@ static struct platform_device *smdkv310_devices[] __initdata = { &s5p_device_mfc_l, &s5p_device_mfc_r, &exynos4_device_spdif, - &samsung_asoc_dma, &samsung_asoc_idma, &s5p_device_fimd0, &smdkv310_device_audio, diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 48d5e41dfbfa..378590694447 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -580,6 +580,11 @@ static void __init igep_wlan_bt_init(void) } else return; + /* Make sure that the GPIO pins are muxed correctly */ + omap_mux_init_gpio(igep_wlan_bt_gpios[0].gpio, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(igep_wlan_bt_gpios[1].gpio, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(igep_wlan_bt_gpios[2].gpio, OMAP_PIN_OUTPUT); + err = gpio_request_array(igep_wlan_bt_gpios, ARRAY_SIZE(igep_wlan_bt_gpios)); if (err) { diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c index 48daac2581b4..84551f205e46 100644 --- a/arch/arm/mach-omap2/common-board-devices.c +++ b/arch/arm/mach-omap2/common-board-devices.c @@ -64,30 +64,36 @@ void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce, struct spi_board_info *spi_bi = &ads7846_spi_board_info; int err; - err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown"); - if (err) { - pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err); - return; - } + /* + * If a board defines get_pendown_state() function, request the pendown + * GPIO and set the GPIO debounce time. + * If a board does not define the get_pendown_state() function, then + * the ads7846 driver will setup the pendown GPIO itself. + */ + if (board_pdata && board_pdata->get_pendown_state) { + err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown"); + if (err) { + pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err); + return; + } - if (gpio_debounce) - gpio_set_debounce(gpio_pendown, gpio_debounce); + if (gpio_debounce) + gpio_set_debounce(gpio_pendown, gpio_debounce); + + gpio_export(gpio_pendown, 0); + } spi_bi->bus_num = bus_num; spi_bi->irq = gpio_to_irq(gpio_pendown); + ads7846_config.gpio_pendown = gpio_pendown; + if (board_pdata) { board_pdata->gpio_pendown = gpio_pendown; + board_pdata->gpio_pendown_debounce = gpio_debounce; spi_bi->platform_data = board_pdata; - if (board_pdata->get_pendown_state) - gpio_export(gpio_pendown, 0); - } else { - ads7846_config.gpio_pendown = gpio_pendown; } - if (!board_pdata || (board_pdata && !board_pdata->get_pendown_state)) - gpio_free(gpio_pendown); - spi_register_board_info(&ads7846_spi_board_info, 1); } #else diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 44c42057b61c..a256135d8e48 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -73,6 +73,7 @@ void __init omap4_pmic_init(const char *pmic_type, { /* PMIC part*/ omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE); + omap_mux_init_signal("fref_clk0_out.sys_drm_msecure", OMAP_PIN_OUTPUT); omap_pmic_init(1, 400, pmic_type, 7 + OMAP44XX_IRQ_GIC_START, pmic_data); /* Register additional devices on i2c1 bus if needed */ diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index 4a963467b7ee..973b87ca87f4 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -521,7 +521,6 @@ static struct platform_device *gta02_devices[] __initdata = { >a02_nor_flash, &s3c24xx_pwm_device, &s3c_device_iis, - &samsung_asoc_dma, &s3c_device_i2c0, >a02_dfbmcs320_device, >a02_buttons_device, diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c index 63aaf076f611..b23dd1b106e8 100644 --- a/arch/arm/mach-s3c24xx/mach-h1940.c +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@ -632,7 +632,6 @@ static struct platform_device *h1940_devices[] __initdata = { &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, - &samsung_asoc_dma, &s3c_device_usbgadget, &h1940_device_leds, &h1940_device_bluetooth, diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index 393c0f1ac11a..a31d5b83e5f7 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -519,7 +519,6 @@ static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_iis, &uda1340_codec, &mini2440_audio, - &samsung_asoc_dma, }; static void __init mini2440_map_io(void) diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index 379fde521d37..0606f2faaa5c 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -712,7 +712,6 @@ static struct platform_device *rx1950_devices[] __initdata = { &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, - &samsung_asoc_dma, &s3c_device_usbgadget, &s3c_device_rtc, &s3c_device_nand, diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 13b7eaa45fd0..ef2117d7391b 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -357,7 +357,6 @@ static struct platform_device *crag6410_devices[] __initdata = { &s3c_device_timer[0], &s3c64xx_device_iis0, &s3c64xx_device_iis1, - &samsung_asoc_dma, &samsung_device_keypad, &crag6410_gpio_keydev, &crag6410_dm9k_device, diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index da1a771a29e9..574a9eef588d 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -275,7 +275,6 @@ static struct platform_device *smdk6410_devices[] __initdata = { &s3c_device_fb, &s3c_device_ohci, &s3c_device_usb_hsotg, - &samsung_asoc_dma, &s3c64xx_device_iisv4, &samsung_device_keypad, diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c index 96ea1fe0ec94..1af823558c60 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6440.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c @@ -165,7 +165,6 @@ static struct platform_device *smdk6440_devices[] __initdata = { &s3c_device_i2c1, &s3c_device_ts, &s3c_device_wdt, - &samsung_asoc_dma, &s5p6440_device_iis, &s3c_device_fb, &smdk6440_lcd_lte480wv, diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c index 12748b6eaa7b..62526ccf6b70 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6450.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c @@ -183,7 +183,6 @@ static struct platform_device *smdk6450_devices[] __initdata = { &s3c_device_i2c1, &s3c_device_ts, &s3c_device_wdt, - &samsung_asoc_dma, &s5p6450_device_iis0, &s3c_device_fb, &smdk6450_lcd_lte480wv, diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c index dba7384a87bd..9abe95e806ab 100644 --- a/arch/arm/mach-s5pc100/mach-smdkc100.c +++ b/arch/arm/mach-s5pc100/mach-smdkc100.c @@ -197,7 +197,6 @@ static struct platform_device *smdkc100_devices[] __initdata = { &s3c_device_ts, &s3c_device_wdt, &smdkc100_lcd_powerdev, - &samsung_asoc_dma, &s5pc100_device_iis0, &samsung_device_keypad, &s5pc100_device_ac97, diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c index d9c99fcc1aa7..f1f3bd37ecda 100644 --- a/arch/arm/mach-s5pv210/mach-smdkc110.c +++ b/arch/arm/mach-s5pv210/mach-smdkc110.c @@ -85,7 +85,6 @@ static struct s3c_ide_platdata smdkc110_ide_pdata __initdata = { }; static struct platform_device *smdkc110_devices[] __initdata = { - &samsung_asoc_dma, &s5pv210_device_iis0, &s5pv210_device_ac97, &s5pv210_device_spdif, diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index 4cdb5bb7bbcf..6bc8404bf678 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -234,7 +234,6 @@ static struct platform_device *smdkv210_devices[] __initdata = { &s5pv210_device_ac97, &s5pv210_device_iis0, &s5pv210_device_spdif, - &samsung_asoc_dma, &samsung_asoc_idma, &samsung_device_keypad, &smdkv210_dm9000, diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index a5683a84c6ee..6013831a043e 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -26,12 +26,14 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/i2c-omap.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/clk.h> #include <mach/irqs.h> #include <plat/i2c.h> +#include <plat/omap-pm.h> #include <plat/omap_device.h> #define OMAP_I2C_SIZE 0x3f @@ -127,6 +129,16 @@ static inline int omap1_i2c_add_bus(int bus_id) #ifdef CONFIG_ARCH_OMAP2PLUS +/* + * XXX This function is a temporary compatibility wrapper - only + * needed until the I2C driver can be converted to call + * omap_pm_set_max_dev_wakeup_lat() and handle a return code. + */ +static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) +{ + omap_pm_set_max_mpu_wakeup_lat(dev, t); +} + static inline int omap2_i2c_add_bus(int bus_id) { int l; @@ -158,6 +170,15 @@ static inline int omap2_i2c_add_bus(int bus_id) dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; pdata->flags = dev_attr->flags; + /* + * When waiting for completion of a i2c transfer, we need to + * set a wake up latency constraint for the MPU. This is to + * ensure quick enough wakeup from idle, when transfer + * completes. + * Only omap3 has support for constraints + */ + if (cpu_is_omap34xx()) + pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 03f654d55eff..7d27a241f984 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -146,15 +146,6 @@ struct platform_device s3c_device_camif = { /* ASOC DMA */ -struct platform_device samsung_asoc_dma = { - .name = "samsung-audio", - .id = -1, - .dev = { - .dma_mask = &samsung_device_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - } -}; - struct platform_device samsung_asoc_idma = { .name = "samsung-idma", .id = -1, diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index 5da4b4f38f40..c45f70cbbfb7 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -135,7 +135,6 @@ extern struct platform_device exynos4_device_spdif; extern struct platform_device exynos_device_drm; -extern struct platform_device samsung_asoc_dma; extern struct platform_device samsung_asoc_idma; extern struct platform_device samsung_device_keypad; diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h index 67e489d8d1bd..2df26b57c26a 100644 --- a/arch/m68k/include/asm/signal.h +++ b/arch/m68k/include/asm/signal.h @@ -41,7 +41,7 @@ struct k_sigaction { static inline void sigaddset(sigset_t *set, int _sig) { asm ("bfset %0{%1,#1}" - : "+od" (*set) + : "+o" (*set) : "id" ((_sig - 1) ^ 31) : "cc"); } @@ -49,7 +49,7 @@ static inline void sigaddset(sigset_t *set, int _sig) static inline void sigdelset(sigset_t *set, int _sig) { asm ("bfclr %0{%1,#1}" - : "+od" (*set) + : "+o" (*set) : "id" ((_sig - 1) ^ 31) : "cc"); } @@ -65,7 +65,7 @@ static inline int __gen_sigismember(sigset_t *set, int _sig) int ret; asm ("bfextu %1{%2,#1},%0" : "=d" (ret) - : "od" (*set), "id" ((_sig-1) ^ 31) + : "o" (*set), "id" ((_sig-1) ^ 31) : "cc"); return ret; } diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index a53f8ec37aac..290dc6a1d7a3 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -79,7 +79,7 @@ static struct resource data_resource = { .name = "Kernel data", }; void __init add_memory_region(phys_t start, phys_t size, long type) { int x = boot_mem_map.nr_map; - struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1; + int i; /* Sanity check */ if (start + size < start) { @@ -88,15 +88,29 @@ void __init add_memory_region(phys_t start, phys_t size, long type) } /* - * Try to merge with previous entry if any. This is far less than - * perfect but is sufficient for most real world cases. + * Try to merge with existing entry, if any. */ - if (x && prev->addr + prev->size == start && prev->type == type) { - prev->size += size; + for (i = 0; i < boot_mem_map.nr_map; i++) { + struct boot_mem_map_entry *entry = boot_mem_map.map + i; + unsigned long top; + + if (entry->type != type) + continue; + + if (start + size < entry->addr) + continue; /* no overlap */ + + if (entry->addr + entry->size < start) + continue; /* no overlap */ + + top = max(entry->addr + entry->size, start + size); + entry->addr = min(entry->addr, start); + entry->size = top - entry->addr; + return; } - if (x == BOOT_MEM_MAP_MAX) { + if (boot_mem_map.nr_map == BOOT_MEM_MAP_MAX) { pr_err("Ooops! Too many entries in the memory map!\n"); return; } diff --git a/arch/mips/lib/mips-atomic.c b/arch/mips/lib/mips-atomic.c index e091430dbeb1..cd160be3ce4d 100644 --- a/arch/mips/lib/mips-atomic.c +++ b/arch/mips/lib/mips-atomic.c @@ -56,7 +56,7 @@ __asm__( " .set pop \n" " .endm \n"); -void arch_local_irq_disable(void) +notrace void arch_local_irq_disable(void) { preempt_disable(); __asm__ __volatile__( @@ -93,7 +93,7 @@ __asm__( " .set pop \n" " .endm \n"); -unsigned long arch_local_irq_save(void) +notrace unsigned long arch_local_irq_save(void) { unsigned long flags; preempt_disable(); @@ -135,7 +135,7 @@ __asm__( " .set pop \n" " .endm \n"); -void arch_local_irq_restore(unsigned long flags) +notrace void arch_local_irq_restore(unsigned long flags) { unsigned long __tmp1; @@ -159,7 +159,7 @@ void arch_local_irq_restore(unsigned long flags) EXPORT_SYMBOL(arch_local_irq_restore); -void __arch_local_irq_restore(unsigned long flags) +notrace void __arch_local_irq_restore(unsigned long flags) { unsigned long __tmp1; diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index fd49aeda9eb8..5dede04f2f3e 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -65,7 +65,8 @@ put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) { compat_sigset_t s; - if (sz != sizeof *set) panic("put_sigset32()"); + if (sz != sizeof *set) + return -EINVAL; sigset_64to32(&s, set); return copy_to_user(up, &s, sizeof s); @@ -77,7 +78,8 @@ get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) compat_sigset_t s; int r; - if (sz != sizeof *set) panic("put_sigset32()"); + if (sz != sizeof *set) + return -EINVAL; if ((r = copy_from_user(&s, up, sz)) == 0) { sigset_32to64(set, &s); diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 7426e40699bd..f76c10863c62 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -73,6 +73,8 @@ static unsigned long get_shared_area(struct address_space *mapping, struct vm_area_struct *vma; int offset = mapping ? get_offset(mapping) : 0; + offset = (offset + (pgoff << PAGE_SHIFT)) & 0x3FF000; + addr = DCACHE_ALIGN(addr - offset) + offset; for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi index 7ab286ab5300..39ed65a44c5f 100644 --- a/arch/powerpc/boot/dts/mpc5200b.dtsi +++ b/arch/powerpc/boot/dts/mpc5200b.dtsi @@ -231,6 +231,12 @@ interrupts = <2 7 0>; }; + sclpc@3c00 { + compatible = "fsl,mpc5200-lpbfifo"; + reg = <0x3c00 0x60>; + interrupts = <2 23 0>; + }; + i2c@3d00 { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/powerpc/boot/dts/o2d.dtsi b/arch/powerpc/boot/dts/o2d.dtsi index 3444eb8f0ade..24f668039295 100644 --- a/arch/powerpc/boot/dts/o2d.dtsi +++ b/arch/powerpc/boot/dts/o2d.dtsi @@ -86,12 +86,6 @@ reg = <0>; }; }; - - sclpc@3c00 { - compatible = "fsl,mpc5200-lpbfifo"; - reg = <0x3c00 0x60>; - interrupts = <3 23 0>; - }; }; localbus { diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts index 9e354997eb7e..96512c058033 100644 --- a/arch/powerpc/boot/dts/pcm030.dts +++ b/arch/powerpc/boot/dts/pcm030.dts @@ -59,7 +59,7 @@ #gpio-cells = <2>; }; - psc@2000 { /* PSC1 in ac97 mode */ + audioplatform: psc@2000 { /* PSC1 in ac97 mode */ compatible = "mpc5200b-psc-ac97","fsl,mpc5200b-psc-ac97"; cell-index = <0>; }; @@ -134,4 +134,9 @@ localbus { status = "disabled"; }; + + sound { + compatible = "phytec,pcm030-audio-fabric"; + asoc-platform = <&audioplatform>; + }; }; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 8520b58a5e9a..b89ef65392dc 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -372,10 +372,11 @@ static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq, case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break; case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break; case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break; - default: - pr_err("%s: invalid irq: virq=%i, l1=%i, l2=%i\n", - __func__, virq, l1irq, l2irq); - return -EINVAL; + case MPC52xx_IRQ_L1_CRIT: + pr_warn("%s: Critical IRQ #%d is unsupported! Nopping it.\n", + __func__, l2irq); + irq_set_chip(virq, &no_irq_chip); + return 0; } irq_set_chip_and_handler(virq, irqchip, handle_level_irq); diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c index 797cd181dc3f..d16c8ded1084 100644 --- a/arch/powerpc/platforms/pseries/eeh_pe.c +++ b/arch/powerpc/platforms/pseries/eeh_pe.c @@ -449,7 +449,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) if (list_empty(&pe->edevs)) { cnt = 0; list_for_each_entry(child, &pe->child_list, child) { - if (!(pe->type & EEH_PE_INVALID)) { + if (!(child->type & EEH_PE_INVALID)) { cnt++; break; } diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index d19f4977c834..e5b084723131 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -220,7 +220,8 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) /* Get the top level device in the PE */ edev = of_node_to_eeh_dev(dn); - edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); + if (edev->pe) + edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); dn = eeh_dev_to_of_node(edev); if (!dn) return NULL; diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index f93003123bce..67c62578d170 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -63,10 +63,13 @@ extern char *of_console_options; extern void irq_trans_init(struct device_node *dp); extern char *build_path_component(struct device_node *dp); -/* SPARC has a local implementation */ +/* SPARC has local implementations */ extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); #define of_address_to_resource of_address_to_resource +void __iomem *of_iomap(struct device_node *node, int index); +#define of_iomap of_iomap + #endif /* __KERNEL__ */ #endif /* _SPARC_PROM_H */ diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 867de2f8189c..689e1ba62809 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -295,9 +295,7 @@ void do_rt_sigreturn(struct pt_regs *regs) err |= restore_fpu_state(regs, fpu_save); err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); - err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf); - - if (err) + if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT) goto segv; err |= __get_user(rwin_save, &sf->rwin_save); diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index c760e073963e..e87b0cac14b5 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -12,6 +12,8 @@ #include <asm/setup.h> #include <asm/desc.h> +#undef memcpy /* Use memcpy from misc.c */ + #include "eboot.h" static efi_system_table_t *sys_table; diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 2a017441b8b2..8c132a625b94 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -476,6 +476,3 @@ die: setup_corrupt: .byte 7 .string "No setup signature found...\n" - - .data -dummy: .long 0 diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index dcfde52979c3..19f16ebaf4fa 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -205,21 +205,14 @@ static inline bool user_64bit_mode(struct pt_regs *regs) } #endif -/* - * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode - * when it traps. The previous stack will be directly underneath the saved - * registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. - * - * This is valid only for kernel mode traps. - */ -static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) -{ #ifdef CONFIG_X86_32 - return (unsigned long)(®s->sp); +extern unsigned long kernel_stack_pointer(struct pt_regs *regs); #else +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ return regs->sp; -#endif } +#endif #define GET_IP(regs) ((regs)->ip) #define GET_FP(regs) ((regs)->bp) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index f7e98a2c0d12..1b7d1656a042 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -631,6 +631,20 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) } } + /* + * The way access filter has a performance penalty on some workloads. + * Disable it on the affected CPUs. + */ + if ((c->x86 == 0x15) && + (c->x86_model >= 0x02) && (c->x86_model < 0x20)) { + u64 val; + + if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) { + val |= 0x1E; + wrmsrl_safe(0xc0011021, val); + } + } + cpu_detect_cache_sizes(c); /* Multi core CPU? */ diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 698b6ec12e0f..1ac581f38dfa 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -6,7 +6,7 @@ * * Written by Jacob Shin - AMD, Inc. * - * Support: borislav.petkov@amd.com + * Maintained by: Borislav Petkov <bp@alien8.de> * * April 2006 * - added support for AMD Family 0x10 processors diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c index 5f88abf07e9c..4f9a3cbfc4a3 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c @@ -285,34 +285,39 @@ void cmci_clear(void) raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); } +static long cmci_rediscover_work_func(void *arg) +{ + int banks; + + /* Recheck banks in case CPUs don't all have the same */ + if (cmci_supported(&banks)) + cmci_discover(banks); + + return 0; +} + /* * After a CPU went down cycle through all the others and rediscover * Must run in process context. */ void cmci_rediscover(int dying) { - int banks; - int cpu; - cpumask_var_t old; + int cpu, banks; if (!cmci_supported(&banks)) return; - if (!alloc_cpumask_var(&old, GFP_KERNEL)) - return; - cpumask_copy(old, ¤t->cpus_allowed); for_each_online_cpu(cpu) { if (cpu == dying) continue; - if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) + + if (cpu == smp_processor_id()) { + cmci_rediscover_work_func(NULL); continue; - /* Recheck banks in case CPUs don't all have the same */ - if (cmci_supported(&banks)) - cmci_discover(banks); - } + } - set_cpus_allowed_ptr(current, old); - free_cpumask_var(old); + work_on_cpu(cpu, cmci_rediscover_work_func, NULL); + } } /* diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index b51b2c7ee51f..1328fe49a3f1 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -995,8 +995,8 @@ END(interrupt) */ .p2align CONFIG_X86_L1_CACHE_SHIFT common_interrupt: - ASM_CLAC XCPT_FRAME + ASM_CLAC addq $-0x80,(%rsp) /* Adjust vector to [-256,-1] range */ interrupt do_IRQ /* 0(%rsp): old_rsp-ARGOFFSET */ @@ -1135,8 +1135,8 @@ END(common_interrupt) */ .macro apicinterrupt num sym do_sym ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC pushq_cfi $~(\num) .Lcommon_\sym: interrupt \do_sym @@ -1190,8 +1190,8 @@ apicinterrupt IRQ_WORK_VECTOR \ */ .macro zeroentry sym do_sym ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp @@ -1208,8 +1208,8 @@ END(\sym) .macro paranoidzeroentry sym do_sym ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp @@ -1227,8 +1227,8 @@ END(\sym) #define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8) .macro paranoidzeroentry_ist sym do_sym ist ENTRY(\sym) - ASM_CLAC INTR_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp @@ -1247,8 +1247,8 @@ END(\sym) .macro errorentry sym do_sym ENTRY(\sym) - ASM_CLAC XCPT_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME subq $ORIG_RAX-R15, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 @@ -1266,8 +1266,8 @@ END(\sym) /* error code is on the stack already */ .macro paranoiderrorentry sym do_sym ENTRY(\sym) - ASM_CLAC XCPT_FRAME + ASM_CLAC PARAVIRT_ADJUST_EXCEPTION_FRAME subq $ORIG_RAX-R15, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 7720ff5a9ee2..efdec7cd8e01 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -8,8 +8,8 @@ * Tigran Aivazian <tigran@aivazian.fsnet.co.uk> * * Maintainers: - * Andreas Herrmann <andreas.herrmann3@amd.com> - * Borislav Petkov <borislav.petkov@amd.com> + * Andreas Herrmann <herrmann.der.user@googlemail.com> + * Borislav Petkov <bp@alien8.de> * * This driver allows to upgrade microcode on F10h AMD * CPUs and later. @@ -190,6 +190,7 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size, #define F1XH_MPB_MAX_SIZE 2048 #define F14H_MPB_MAX_SIZE 1824 #define F15H_MPB_MAX_SIZE 4096 +#define F16H_MPB_MAX_SIZE 3458 switch (c->x86) { case 0x14: @@ -198,6 +199,9 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size, case 0x15: max_size = F15H_MPB_MAX_SIZE; break; + case 0x16: + max_size = F16H_MPB_MAX_SIZE; + break; default: max_size = F1XH_MPB_MAX_SIZE; break; diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index b00b33a18390..5e0596b0632e 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -22,6 +22,7 @@ #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <linux/rcupdate.h> +#include <linux/module.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -166,6 +167,35 @@ static inline bool invalid_selector(u16 value) #define FLAG_MASK FLAG_MASK_32 +/* + * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode + * when it traps. The previous stack will be directly underneath the saved + * registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. + * + * Now, if the stack is empty, '®s->sp' is out of range. In this + * case we try to take the previous stack. To always return a non-null + * stack pointer we fall back to regs as stack if no previous stack + * exists. + * + * This is valid only for kernel mode traps. + */ +unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1); + unsigned long sp = (unsigned long)®s->sp; + struct thread_info *tinfo; + + if (context == (sp & ~(THREAD_SIZE - 1))) + return sp; + + tinfo = (struct thread_info *)context; + if (tinfo->previous_esp) + return tinfo->previous_esp; + + return (unsigned long)regs; +} +EXPORT_SYMBOL_GPL(kernel_stack_pointer); + static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno) { BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0); diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 0777f042e400..60f926cd8b0e 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -197,7 +197,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, } if (end == TLB_FLUSH_ALL || tlb_flushall_shift == -1 - || vmflag == VM_HUGETLB) { + || vmflag & VM_HUGETLB) { local_flush_tlb(); goto flush_all; } diff --git a/arch/x86/pci/ce4100.c b/arch/x86/pci/ce4100.c index 41bd2a2d2c50..b914e20b5a00 100644 --- a/arch/x86/pci/ce4100.c +++ b/arch/x86/pci/ce4100.c @@ -115,6 +115,16 @@ static void sata_revid_read(struct sim_dev_reg *reg, u32 *value) reg_read(reg, value); } +static void reg_noirq_read(struct sim_dev_reg *reg, u32 *value) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pci_config_lock, flags); + /* force interrupt pin value to 0 */ + *value = reg->sim_reg.value & 0xfff00ff; + raw_spin_unlock_irqrestore(&pci_config_lock, flags); +} + static struct sim_dev_reg bus1_fixups[] = { DEFINE_REG(2, 0, 0x10, (16*MB), reg_init, reg_read, reg_write) DEFINE_REG(2, 0, 0x14, (256), reg_init, reg_read, reg_write) @@ -144,6 +154,7 @@ static struct sim_dev_reg bus1_fixups[] = { DEFINE_REG(11, 5, 0x10, (64*KB), reg_init, reg_read, reg_write) DEFINE_REG(11, 6, 0x10, (256), reg_init, reg_read, reg_write) DEFINE_REG(11, 7, 0x10, (64*KB), reg_init, reg_read, reg_write) + DEFINE_REG(11, 7, 0x3c, 256, reg_init, reg_noirq_read, reg_write) DEFINE_REG(12, 0, 0x10, (128*KB), reg_init, reg_read, reg_write) DEFINE_REG(12, 0, 0x14, (256), reg_init, reg_read, reg_write) DEFINE_REG(12, 1, 0x10, (1024), reg_init, reg_read, reg_write) @@ -161,8 +172,10 @@ static struct sim_dev_reg bus1_fixups[] = { DEFINE_REG(16, 0, 0x10, (64*KB), reg_init, reg_read, reg_write) DEFINE_REG(16, 0, 0x14, (64*MB), reg_init, reg_read, reg_write) DEFINE_REG(16, 0, 0x18, (64*MB), reg_init, reg_read, reg_write) + DEFINE_REG(16, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write) DEFINE_REG(17, 0, 0x10, (128*KB), reg_init, reg_read, reg_write) DEFINE_REG(18, 0, 0x10, (1*KB), reg_init, reg_read, reg_write) + DEFINE_REG(18, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write) }; static void __init init_sim_regs(void) diff --git a/arch/x86/platform/ce4100/ce4100.c b/arch/x86/platform/ce4100/ce4100.c index 4c61b52191eb..92525cb8e54c 100644 --- a/arch/x86/platform/ce4100/ce4100.c +++ b/arch/x86/platform/ce4100/ce4100.c @@ -21,12 +21,25 @@ #include <asm/i8259.h> #include <asm/io.h> #include <asm/io_apic.h> +#include <asm/emergency-restart.h> static int ce4100_i8042_detect(void) { return 0; } +/* + * The CE4100 platform has an internal 8051 Microcontroller which is + * responsible for signaling to the external Power Management Unit the + * intention to reset, reboot or power off the system. This 8051 device has + * its command register mapped at I/O port 0xcf9 and the value 0x4 is used + * to power off the system. + */ +static void ce4100_power_off(void) +{ + outb(0x4, 0xcf9); +} + #ifdef CONFIG_SERIAL_8250 static unsigned int mem_serial_in(struct uart_port *p, int offset) @@ -139,8 +152,19 @@ void __init x86_ce4100_early_setup(void) x86_init.mpparse.find_smp_config = x86_init_noop; x86_init.pci.init = ce4100_pci_init; + /* + * By default, the reboot method is ACPI which is supported by the + * CE4100 bootloader CEFDK using FADT.ResetReg Address and ResetValue + * the bootloader will however issue a system power off instead of + * reboot. By using BOOT_KBD we ensure proper system reboot as + * expected. + */ + reboot_type = BOOT_KBD; + #ifdef CONFIG_X86_IO_APIC x86_init.pci.init_irq = sdv_pci_init; x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc_nocheck; #endif + + pm_power_off = ce4100_power_off; } diff --git a/block/blk-exec.c b/block/blk-exec.c index 8b6dc5bd4dd0..f71eac35c1b9 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -52,11 +52,17 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, rq_end_io_fn *done) { int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; + bool is_pm_resume; WARN_ON(irqs_disabled()); rq->rq_disk = bd_disk; rq->end_io = done; + /* + * need to check this before __blk_run_queue(), because rq can + * be freed before that returns. + */ + is_pm_resume = rq->cmd_type == REQ_TYPE_PM_RESUME; spin_lock_irq(q->queue_lock); @@ -71,7 +77,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, __elv_add_request(q, rq, where); __blk_run_queue(q); /* the queue is stopped so it won't be run */ - if (rq->cmd_type == REQ_TYPE_PM_RESUME) + if (is_pm_resume) q->request_fn(q); spin_unlock_irq(q->queue_lock); } diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index b1ae48054dc5..b7078afddb74 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -238,7 +238,7 @@ static int __devexit ahci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ahci_suspend(struct device *dev) { struct ahci_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index fd9ecf74e631..5b0ba3f20edc 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -1105,10 +1105,15 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, struct acpi_device *acpi_dev; struct acpi_device_power_state *states; - if (ap->flags & ATA_FLAG_ACPI_SATA) - ata_dev = &ap->link.device[sdev->channel]; - else + if (ap->flags & ATA_FLAG_ACPI_SATA) { + if (!sata_pmp_attached(ap)) + ata_dev = &ap->link.device[sdev->id]; + else + ata_dev = &ap->pmp_link[sdev->channel].device[sdev->id]; + } + else { ata_dev = &ap->link.device[sdev->id]; + } *handle = ata_dev_acpi_handle(ata_dev); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3cc7096cfda7..f46fbd3bd3fb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2942,6 +2942,10 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode) if (xfer_mode == t->mode) return t; + + WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n", + __func__, xfer_mode); + return NULL; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e3bda074fa12..a6df6a351d6e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1052,6 +1052,8 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + sdev->no_report_opcodes = 1; + sdev->no_write_same = 1; /* Schedule policy is determined by ->qc_defer() callback and * it needs to see every deferred qc. Set dev_blocked to 1 to diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 26201ebef3ca..371fd2c698b7 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -317,6 +317,12 @@ static int cf_init(struct arasan_cf_dev *acdev) return ret; } + ret = clk_set_rate(acdev->clk, 166000000); + if (ret) { + dev_warn(acdev->host->dev, "clock set rate failed"); + return ret; + } + spin_lock_irqsave(&acdev->host->lock, flags); /* configure CF interface clock */ writel((pdata->cf_if_clk <= CF_IF_CLK_200M) ? pdata->cf_if_clk : @@ -908,7 +914,7 @@ static int __devexit arasan_cf_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int arasan_cf_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 0d7c4c2cd26f..400bf1c3e982 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -260,7 +260,7 @@ static const struct of_device_id ahci_of_match[] = { }; MODULE_DEVICE_TABLE(of, ahci_of_match); -static int __init ahci_highbank_probe(struct platform_device *pdev) +static int __devinit ahci_highbank_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; @@ -378,7 +378,7 @@ static int __devexit ahci_highbank_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ahci_highbank_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 44a4256533e1..08608de87e4e 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -142,6 +142,39 @@ static int k2_sata_scr_write(struct ata_link *link, return 0; } +static int k2_sata_softreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return ata_sff_softreset(link, class, deadline); +} + +static int k2_sata_hardreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return sata_sff_hardreset(link, class, deadline); +} static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { @@ -346,6 +379,8 @@ static struct scsi_host_template k2_sata_sht = { static struct ata_port_operations k2_sata_ops = { .inherits = &ata_bmdma_port_ops, + .softreset = k2_sata_softreset, + .hardreset = k2_sata_hardreset, .sff_tf_load = k2_sata_tf_load, .sff_tf_read = k2_sata_tf_read, .sff_check_status = k2_stat_check_status, diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 74a67e0019a2..fbbd4ed2edf2 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -451,7 +451,7 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, if (ancestor) error = dev_pm_qos_add_request(ancestor, req, value); - if (error) + if (error < 0) req->dev = NULL; return error; diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 80f9ab9c3aa4..ac869d28d5ba 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -120,6 +120,8 @@ int _regmap_write(struct regmap *map, unsigned int reg, struct regmap_range_node { struct rb_node node; + const char *name; + struct regmap *map; unsigned int range_min; unsigned int range_max; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index bb1ff175b962..f4b9dd01c981 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -56,15 +56,15 @@ static const struct file_operations regmap_name_fops = { .llseek = default_llseek, }; -static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, + unsigned int to, char __user *user_buf, + size_t count, loff_t *ppos) { int reg_len, val_len, tot_len; size_t buf_pos = 0; loff_t p = 0; ssize_t ret; int i; - struct regmap *map = file->private_data; char *buf; unsigned int val; @@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, val_len = 2 * map->format.val_bytes; tot_len = reg_len + val_len + 3; /* : \n */ - for (i = 0; i <= map->max_register; i += map->reg_stride) { + for (i = from; i <= to; i += map->reg_stride) { if (!regmap_readable(map, i)) continue; @@ -95,7 +95,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, /* Format the register */ snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", - reg_len, i); + reg_len, i - from); buf_pos += reg_len + 2; /* Format the value, write all X if we can't read */ @@ -126,6 +126,15 @@ out: return ret; } +static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = file->private_data; + + return regmap_read_debugfs(map, 0, map->max_register, user_buf, + count, ppos); +} + #undef REGMAP_ALLOW_WRITE_DEBUGFS #ifdef REGMAP_ALLOW_WRITE_DEBUGFS /* @@ -174,6 +183,22 @@ static const struct file_operations regmap_map_fops = { .llseek = default_llseek, }; +static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap_range_node *range = file->private_data; + struct regmap *map = range->map; + + return regmap_read_debugfs(map, range->range_min, range->range_max, + user_buf, count, ppos); +} + +static const struct file_operations regmap_range_fops = { + .open = simple_open, + .read = regmap_range_read_file, + .llseek = default_llseek, +}; + static ssize_t regmap_access_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -244,6 +269,9 @@ static const struct file_operations regmap_access_fops = { void regmap_debugfs_init(struct regmap *map, const char *name) { + struct rb_node *next; + struct regmap_range_node *range_node; + if (name) { map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(map->dev), name); @@ -276,6 +304,18 @@ void regmap_debugfs_init(struct regmap *map, const char *name) debugfs_create_bool("cache_bypass", 0400, map->debugfs, &map->cache_bypass); } + + next = rb_first(&map->range_tree); + while (next) { + range_node = rb_entry(next, struct regmap_range_node, node); + + if (range_node->name) + debugfs_create_file(range_node->name, 0400, + map->debugfs, range_node, + ®map_range_fops); + + next = rb_next(&range_node->node); + } } void regmap_debugfs_exit(struct regmap *map) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 52069d29ff12..96253cd949e9 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -519,20 +519,38 @@ struct regmap *regmap_init(struct device *dev, } map->range_tree = RB_ROOT; - for (i = 0; i < config->n_ranges; i++) { + for (i = 0; i < config->num_ranges; i++) { const struct regmap_range_cfg *range_cfg = &config->ranges[i]; struct regmap_range_node *new; /* Sanity check */ - if (range_cfg->range_max < range_cfg->range_min || - range_cfg->range_max > map->max_register || - range_cfg->selector_reg > map->max_register || - range_cfg->window_len == 0) + if (range_cfg->range_max < range_cfg->range_min) { + dev_err(map->dev, "Invalid range %d: %d < %d\n", i, + range_cfg->range_max, range_cfg->range_min); goto err_range; + } + + if (range_cfg->range_max > map->max_register) { + dev_err(map->dev, "Invalid range %d: %d > %d\n", i, + range_cfg->range_max, map->max_register); + goto err_range; + } + + if (range_cfg->selector_reg > map->max_register) { + dev_err(map->dev, + "Invalid range %d: selector out of map\n", i); + goto err_range; + } + + if (range_cfg->window_len == 0) { + dev_err(map->dev, "Invalid range %d: window_len 0\n", + i); + goto err_range; + } /* Make sure, that this register range has no selector or data window within its boundary */ - for (j = 0; j < config->n_ranges; j++) { + for (j = 0; j < config->num_ranges; j++) { unsigned sel_reg = config->ranges[j].selector_reg; unsigned win_min = config->ranges[j].window_start; unsigned win_max = win_min + @@ -540,11 +558,17 @@ struct regmap *regmap_init(struct device *dev, if (range_cfg->range_min <= sel_reg && sel_reg <= range_cfg->range_max) { + dev_err(map->dev, + "Range %d: selector for %d in window\n", + i, j); goto err_range; } if (!(win_max < range_cfg->range_min || win_min > range_cfg->range_max)) { + dev_err(map->dev, + "Range %d: window for %d in window\n", + i, j); goto err_range; } } @@ -555,6 +579,8 @@ struct regmap *regmap_init(struct device *dev, goto err_range; } + new->map = map; + new->name = range_cfg->name; new->range_min = range_cfg->range_min; new->range_max = range_cfg->range_max; new->selector_reg = range_cfg->selector_reg; @@ -564,6 +590,7 @@ struct regmap *regmap_init(struct device *dev, new->window_len = range_cfg->window_len; if (_regmap_range_add(map, new) == false) { + dev_err(map->dev, "Failed to add range %d\n", i); kfree(new); goto err_range; } @@ -579,7 +606,7 @@ struct regmap *regmap_init(struct device *dev, } ret = regcache_init(map, config); - if (ret < 0) + if (ret != 0) goto err_range; regmap_debugfs_init(map, config->name); @@ -738,59 +765,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) EXPORT_SYMBOL_GPL(dev_get_regmap); static int _regmap_select_page(struct regmap *map, unsigned int *reg, + struct regmap_range_node *range, unsigned int val_num) { - struct regmap_range_node *range; void *orig_work_buf; unsigned int win_offset; unsigned int win_page; bool page_chg; int ret; - range = _regmap_range_lookup(map, *reg); - if (range) { - win_offset = (*reg - range->range_min) % range->window_len; - win_page = (*reg - range->range_min) / range->window_len; - - if (val_num > 1) { - /* Bulk write shouldn't cross range boundary */ - if (*reg + val_num - 1 > range->range_max) - return -EINVAL; + win_offset = (*reg - range->range_min) % range->window_len; + win_page = (*reg - range->range_min) / range->window_len; - /* ... or single page boundary */ - if (val_num > range->window_len - win_offset) - return -EINVAL; - } + if (val_num > 1) { + /* Bulk write shouldn't cross range boundary */ + if (*reg + val_num - 1 > range->range_max) + return -EINVAL; - /* It is possible to have selector register inside data window. - In that case, selector register is located on every page and - it needs no page switching, when accessed alone. */ - if (val_num > 1 || - range->window_start + win_offset != range->selector_reg) { - /* Use separate work_buf during page switching */ - orig_work_buf = map->work_buf; - map->work_buf = map->selector_work_buf; + /* ... or single page boundary */ + if (val_num > range->window_len - win_offset) + return -EINVAL; + } - ret = _regmap_update_bits(map, range->selector_reg, - range->selector_mask, - win_page << range->selector_shift, - &page_chg); + /* It is possible to have selector register inside data window. + In that case, selector register is located on every page and + it needs no page switching, when accessed alone. */ + if (val_num > 1 || + range->window_start + win_offset != range->selector_reg) { + /* Use separate work_buf during page switching */ + orig_work_buf = map->work_buf; + map->work_buf = map->selector_work_buf; - map->work_buf = orig_work_buf; + ret = _regmap_update_bits(map, range->selector_reg, + range->selector_mask, + win_page << range->selector_shift, + &page_chg); - if (ret < 0) - return ret; - } + map->work_buf = orig_work_buf; - *reg = range->window_start + win_offset; + if (ret != 0) + return ret; } + *reg = range->window_start + win_offset; + return 0; } static int _regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { + struct regmap_range_node *range; u8 *u8 = map->work_buf; void *buf; int ret = -ENOTSUPP; @@ -825,9 +850,35 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, } } - ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); - if (ret < 0) - return ret; + range = _regmap_range_lookup(map, reg); + if (range) { + int val_num = val_len / map->format.val_bytes; + int win_offset = (reg - range->range_min) % range->window_len; + int win_residue = range->window_len - win_offset; + + /* If the write goes beyond the end of the window split it */ + while (val_num > win_residue) { + dev_dbg(map->dev, "Writing window %d/%d\n", + win_residue, val_len / map->format.val_bytes); + ret = _regmap_raw_write(map, reg, val, win_residue * + map->format.val_bytes); + if (ret != 0) + return ret; + + reg += win_residue; + val_num -= win_residue; + val += win_residue * map->format.val_bytes; + val_len -= win_residue * map->format.val_bytes; + + win_offset = (reg - range->range_min) % + range->window_len; + win_residue = range->window_len - win_offset; + } + + ret = _regmap_select_page(map, ®, range, val_num); + if (ret != 0) + return ret; + } map->format.format_reg(map->work_buf, reg, map->reg_shift); @@ -876,6 +927,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, int _regmap_write(struct regmap *map, unsigned int reg, unsigned int val) { + struct regmap_range_node *range; int ret; BUG_ON(!map->format.format_write && !map->format.format_val); @@ -897,9 +949,12 @@ int _regmap_write(struct regmap *map, unsigned int reg, trace_regmap_reg_write(map->dev, reg, val); if (map->format.format_write) { - ret = _regmap_select_page(map, ®, 1); - if (ret < 0) - return ret; + 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); @@ -1055,12 +1110,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, unsigned int val_len) { + struct regmap_range_node *range; u8 *u8 = map->work_buf; int ret; - ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); - if (ret < 0) - return ret; + range = _regmap_range_lookup(map, reg); + if (range) { + ret = _regmap_select_page(map, ®, range, + val_len / map->format.val_bytes); + if (ret != 0) + return ret; + } map->format.format_reg(map->work_buf, reg, map->reg_shift); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 3804a0af3ef1..9fe4f1865558 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -935,7 +935,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) /* cf. http://lkml.org/lkml/2006/10/31/28 */ if (!fastfail) - q->request_fn(q); + __blk_run_queue(q); } static void diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 1c49d7173966..2ddd64a9ffde 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4330,6 +4330,7 @@ out_unreg_region: out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: + destroy_workqueue(floppy_wq); for (drive = 0; drive < N_DRIVE; drive++) { if (!disks[drive]) break; @@ -4340,7 +4341,6 @@ out_put_disk: } put_disk(disks[drive]); } - destroy_workqueue(floppy_wq); return err; } @@ -4555,6 +4555,8 @@ static void __exit floppy_module_exit(void) unregister_blkdev(FLOPPY_MAJOR, "fd"); platform_driver_unregister(&floppy_driver); + destroy_workqueue(floppy_wq); + for (drive = 0; drive < N_DRIVE; drive++) { del_timer_sync(&motor_off_timer[drive]); @@ -4578,7 +4580,6 @@ static void __exit floppy_module_exit(void) cancel_delayed_work_sync(&fd_timeout); cancel_delayed_work_sync(&fd_timer); - destroy_workqueue(floppy_wq); if (atomic_read(&usage_count)) floppy_release_irq_and_dma(); diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index adc6f36564cf..9694dd99bbbc 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -559,7 +559,7 @@ static void mtip_timeout_function(unsigned long int data) struct mtip_cmd *command; int tag, cmdto_cnt = 0; unsigned int bit, group; - unsigned int num_command_slots = port->dd->slot_groups * 32; + unsigned int num_command_slots; unsigned long to, tagaccum[SLOTBITS_IN_LONGS]; if (unlikely(!port)) @@ -572,6 +572,7 @@ static void mtip_timeout_function(unsigned long int data) } /* clear the tag accumulator */ memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + num_command_slots = port->dd->slot_groups * 32; for (tag = 0; tag < num_command_slots; tag++) { /* @@ -2218,8 +2219,8 @@ static int exec_drive_taskfile(struct driver_data *dd, fis.device); /* check for erase mode support during secure erase.*/ - if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) - && (outbuf[0] & MTIP_SEC_ERASE_MODE)) { + if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) && outbuf && + (outbuf[0] & MTIP_SEC_ERASE_MODE)) { erasemode = 1; } @@ -2439,7 +2440,7 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, * return value * None */ -static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, +static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, int nsect, int nents, int tag, void *callback, void *data, int dir) { @@ -2447,6 +2448,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, struct mtip_port *port = dd->port; struct mtip_cmd *command = &port->commands[tag]; int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + u64 start = sector; /* Map the scatter list for DMA access */ nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir); @@ -2465,8 +2467,12 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, fis->opts = 1 << 7; fis->command = (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE); - *((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF); - *((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF); + fis->lba_low = start & 0xFF; + fis->lba_mid = (start >> 8) & 0xFF; + fis->lba_hi = (start >> 16) & 0xFF; + fis->lba_low_ex = (start >> 24) & 0xFF; + fis->lba_mid_ex = (start >> 32) & 0xFF; + fis->lba_hi_ex = (start >> 40) & 0xFF; fis->device = 1 << 6; fis->features = nsect & 0xFF; fis->features_ex = (nsect >> 8) & 0xFF; diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 5f4a917bd8bb..b1742640556a 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -34,7 +34,7 @@ #define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 /* check for erase mode support during secure erase */ -#define MTIP_SEC_ERASE_MODE 0x3 +#define MTIP_SEC_ERASE_MODE 0x2 /* # of times to retry timed out/failed IOs */ #define MTIP_MAX_RETRIES 2 @@ -155,14 +155,14 @@ enum { MTIP_DDF_REBUILD_FAILED_BIT = 8, }; -__packed struct smart_attr{ +struct smart_attr { u8 attr_id; u16 flags; u8 cur; u8 worst; u32 data; u8 res[3]; -}; +} __packed; /* Register Frame Information Structure (FIS), host to device. */ struct host_to_dev_fis { diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 8d4804732bac..8c4139647efc 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -33,7 +33,7 @@ * detection. The mods to Rev F required more family * information detection. * - * Changes/Fixes by Borislav Petkov <borislav.petkov@amd.com>: + * Changes/Fixes by Borislav Petkov <bp@alien8.de>: * - misc fixes and code cleanups * * This module is based on the following documents diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index 6c86f6e54558..351945fa2ecd 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c @@ -5,7 +5,7 @@ * * 2007 (c) MontaVista Software, Inc. * 2010 (c) Advanced Micro Devices Inc. - * Borislav Petkov <borislav.petkov@amd.com> + * Borislav Petkov <bp@alien8.de> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 66b5151c1080..2ae78f20cc28 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -6,7 +6,7 @@ * This file may be distributed under the terms of the GNU General Public * License version 2. * - * Copyright (c) 2010: Borislav Petkov <borislav.petkov@amd.com> + * Copyright (c) 2010: Borislav Petkov <bp@alien8.de> * Advanced Micro Devices Inc. */ @@ -168,6 +168,6 @@ module_init(edac_init_mce_inject); module_exit(edac_exit_mce_inject); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Borislav Petkov <borislav.petkov@amd.com>"); +MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>"); MODULE_AUTHOR("AMD Inc."); MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding"); diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 1162d6b3bf85..bb1b392f5cda 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -1546,6 +1546,8 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) struct sbp2_logical_unit *lu = sdev->hostdata; sdev->use_10_for_rw = 1; + sdev->no_report_opcodes = 1; + sdev->no_write_same = 1; if (sbp2_param_exclusive_login) sdev->manage_start_stop = 1; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f11d8e3b4041..47150f5ded04 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -466,7 +466,7 @@ config GPIO_ADP5588_IRQ config GPIO_ADNP tristate "Avionic Design N-bit GPIO expander" - depends on I2C && OF + depends on I2C && OF_GPIO help This option enables support for N GPIOs found on Avionic Design I2C GPIO expanders. The register space will be extended by powers diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 0f425189de11..ce1c84760076 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -77,7 +77,7 @@ struct mcp23s08_driver_data { /*----------------------------------------------------------------------*/ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg) { @@ -399,7 +399,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, break; #endif /* CONFIG_SPI_MASTER */ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) case MCP_TYPE_008: mcp->ops = &mcp23008_ops; mcp->chip.ngpio = 8; @@ -473,7 +473,7 @@ fail: /*----------------------------------------------------------------------*/ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) static int __devinit mcp230xx_probe(struct i2c_client *client, const struct i2c_device_id *id) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index cf7afb9eb61a..be65c0451ad5 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -92,6 +92,11 @@ static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_OUT_OFF; } +static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) +{ + return mvchip->membase + GPIO_BLINK_EN_OFF; +} + static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; @@ -206,6 +211,23 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin) return (u >> pin) & 1; } +static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value) +{ + struct mvebu_gpio_chip *mvchip = + container_of(chip, struct mvebu_gpio_chip, chip); + unsigned long flags; + u32 u; + + spin_lock_irqsave(&mvchip->lock, flags); + u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); + if (value) + u |= 1 << pin; + else + u &= ~(1 << pin); + writel_relaxed(u, mvebu_gpioreg_blink(mvchip)); + spin_unlock_irqrestore(&mvchip->lock, flags); +} + static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin) { struct mvebu_gpio_chip *mvchip = @@ -244,6 +266,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, if (ret) return ret; + mvebu_gpio_blink(chip, pin, 0); mvebu_gpio_set(chip, pin, value); spin_lock_irqsave(&mvchip->lock, flags); diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 05a909a17cee..15b182c84ce8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -49,13 +49,7 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) if (chan->vblank.crtc != crtc) continue; - if (nv_device(priv)->chipset == 0x50) { - nv_wr32(priv, 0x001704, chan->vblank.channel); - nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); - bar->flush(bar); - nv_wr32(priv, 0x001570, chan->vblank.offset); - nv_wr32(priv, 0x001574, chan->vblank.value); - } else { + if (nv_device(priv)->chipset >= 0xc0) { nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); bar->flush(bar); nv_wr32(priv, 0x06000c, @@ -63,6 +57,17 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); nv_wr32(priv, 0x060014, chan->vblank.value); + } else { + nv_wr32(priv, 0x001704, chan->vblank.channel); + nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); + bar->flush(bar); + if (nv_device(priv)->chipset == 0x50) { + nv_wr32(priv, 0x001570, chan->vblank.offset); + nv_wr32(priv, 0x001574, chan->vblank.value); + } else { + nv_wr32(priv, 0x060010, chan->vblank.offset); + nv_wr32(priv, 0x060014, chan->vblank.value); + } } list_del(&chan->vblank.head); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c index e45035efb8ca..7bbb1e1b7a8d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c @@ -669,21 +669,27 @@ nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem) }); } -void +int nv40_grctx_init(struct nouveau_device *device, u32 *size) { - u32 ctxprog[256], i; + u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i; struct nouveau_grctx ctx = { .device = device, .mode = NOUVEAU_GRCTX_PROG, .data = ctxprog, - .ctxprog_max = ARRAY_SIZE(ctxprog) + .ctxprog_max = 256, }; + if (!ctxprog) + return -ENOMEM; + nv40_grctx_generate(&ctx); nv_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) nv_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; + + kfree(ctxprog); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 425001204a89..cc6574eeb80e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -346,7 +346,9 @@ nv40_graph_init(struct nouveau_object *object) return ret; /* generate and upload context program */ - nv40_grctx_init(nv_device(priv), &priv->size); + ret = nv40_grctx_init(nv_device(priv), &priv->size); + if (ret) + return ret; /* No context present currently */ nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h index d2ac975afc2e..7da35a4e7970 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h @@ -15,7 +15,7 @@ nv44_graph_class(void *priv) return !(0x0baf & (1 << (device->chipset & 0x0f))); } -void nv40_grctx_init(struct nouveau_device *, u32 *size); +int nv40_grctx_init(struct nouveau_device *, u32 *size); void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index 818feabbf4a0..486f1a9217fd 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h @@ -175,14 +175,18 @@ nv_mo32(void *obj, u32 addr, u32 mask, u32 data) return temp; } -static inline bool -nv_strncmp(void *obj, u32 addr, u32 len, const char *str) +static inline int +nv_memcmp(void *obj, u32 addr, const char *str, u32 len) { + unsigned char c1, c2; + while (len--) { - if (nv_ro08(obj, addr++) != *(str++)) - return false; + c1 = nv_ro08(obj, addr++); + c2 = *(str++); + if (c1 != c2) + return c1 - c2; } - return true; + return 0; } #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index 39e73b91d360..41b7a6a76f19 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -54,6 +54,7 @@ int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, int clk, struct nouveau_pll_vals *); int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1, struct nouveau_pll_vals *); - +int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, + int clk, struct nouveau_pll_vals *); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 7d750382a833..c51197157749 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -64,7 +64,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } } else if (*ver >= 0x15) { - if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) { + if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) { u16 i2c = nv_ro16(bios, dcb + 2); *hdr = 4; *cnt = (i2c - dcb) / 10; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index cc8d7d162d7c..9068c98b96f6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -66,6 +66,24 @@ nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) return ret; } +int +nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, + int clk, struct nouveau_pll_vals *pv) +{ + int ret, N, M, P; + + ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P); + + if (ret > 0) { + pv->refclk = info->refclk; + pv->N1 = N; + pv->M1 = M; + pv->log2P = P; + } + return ret; +} + + static int nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -80,6 +98,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.pll_set = nva3_clock_pll_set; + priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index 5ccce0b17bf3..f6962c9b6c36 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -79,6 +79,7 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.pll_set = nvc0_clock_pll_set; + priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index cc79c796afee..cbf1fc60a386 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -241,6 +241,10 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (unlikely(!abi16)) return -ENOMEM; + + if (!drm->channel) + return nouveau_abi16_put(abi16, -ENODEV); + client = nv_client(abi16->client); if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 0910125cbbc3..8503b2ea570a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -129,7 +129,8 @@ nouveau_accel_init(struct nouveau_drm *drm) /* initialise synchronisation routines */ if (device->card_type < NV_10) ret = nv04_fence_create(drm); - else if (device->chipset < 0x84) ret = nv10_fence_create(drm); + else if (device->card_type < NV_50) ret = nv10_fence_create(drm); + else if (device->chipset < 0x84) ret = nv50_fence_create(drm); else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); else ret = nvc0_fence_create(drm); if (ret) { diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index af31f829f4a8..219942c660d7 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1330,6 +1330,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav break; udelay(1); } + } else { + save->crtc_enabled[i] = false; } } diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index 10ea17a6b2a6..42433344cb1b 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -69,9 +69,12 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/ { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59, PCI_VENDOR_ID_DELL, 0x00e3, 2}, - /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */ + /* Intel 82852/82855 host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 (lp #296617) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66, PCI_VENDOR_ID_DELL, 0x0149, 1}, + /* Intel 82855PM host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 for suspend/resume */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_IBM, 0x0531, 1}, /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, 0x1025, 0x0061, 1}, diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index aa59a254be2c..c02bf208084f 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -39,6 +39,7 @@ #define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ #define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ #define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ +#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */ #define AT91_TWI_SWRST 0x0080 /* Software Reset */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ @@ -212,7 +213,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) INIT_COMPLETION(dev->cmd_complete); dev->transfer_status = 0; - if (dev->msg->flags & I2C_M_RD) { + + if (!dev->buf_len) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 286ca1917820..0670da79ee5e 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -287,12 +287,14 @@ read_init_dma_fail: select_init_dma_fail: dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); select_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; /* Write failpath. */ write_init_dma_fail: dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); write_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; } diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index db31eaed6ea5..3525c9e62cb0 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,7 +43,6 @@ #include <linux/slab.h> #include <linux/i2c-omap.h> #include <linux/pm_runtime.h> -#include <linux/pm_qos.h> /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -187,8 +186,9 @@ struct omap_i2c_dev { int reg_shift; /* bit shift for I2C register addresses */ struct completion cmd_complete; struct resource *ioarea; - u32 latency; /* maximum MPU wkup latency */ - struct pm_qos_request pm_qos_request; + u32 latency; /* maximum mpu wkup latency */ + void (*set_mpu_wkup_lat)(struct device *dev, + long latency); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -494,7 +494,9 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->threshold) / + (1000 * dev->speed / 8); } /* @@ -522,6 +524,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev->buf = msg->buf; dev->buf_len = msg->len; + /* make sure writes to dev->buf_len are ordered */ + barrier(); + omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); /* Clear the FIFO Buffers */ @@ -579,7 +584,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, */ timeout = wait_for_completion_timeout(&dev->cmd_complete, OMAP_I2C_TIMEOUT); - dev->buf_len = 0; if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); omap_i2c_init(dev); @@ -629,16 +633,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - /* - * When waiting for completion of a i2c transfer, we need to - * set a wake up latency constraint for the MPU. This is to - * ensure quick enough wakeup from idle, when transfer - * completes. - */ - if (dev->latency) - pm_qos_add_request(&dev->pm_qos_request, - PM_QOS_CPU_DMA_LATENCY, - dev->latency); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -646,8 +642,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->latency) - pm_qos_remove_request(&dev->pm_qos_request); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); if (r == 0) r = num; @@ -1104,6 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev) } else if (pdata != NULL) { dev->speed = pdata->clkrate; dev->flags = pdata->flags; + dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; dev->dtrev = pdata->rev; } @@ -1159,8 +1156,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->fifo_size) / + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3e0335f1fc60..9d902725bac9 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -806,6 +806,7 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); goto free_gpio; } + i2c->gpios[idx] = gpio; ret = gpio_request(gpio, "i2c-bus"); if (ret) { diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index c0ec7d42c3be..1abbc170d8b7 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -26,10 +26,14 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src) * input_mt_init_slots() - initialize MT input slots * @dev: input device supporting MT events and finger tracking * @num_slots: number of slots used by the device + * @flags: mt tasks to handle in core * * This function allocates all necessary memory for MT slot handling * in the input device, prepares the ABS_MT_SLOT and * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers. + * Depending on the flags set, it also performs pointer emulation and + * frame synchronization. + * * May be called repeatedly. Returns -EINVAL if attempting to * reinitialize with a different number of slots. */ diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7c0f1ecfdd7a..104a7c3153c0 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -72,6 +72,16 @@ config INPUT_AD714X_SPI To compile this driver as a module, choose M here: the module will be called ad714x-spi. +config INPUT_ARIZONA_HAPTICS + tristate "Arizona haptics support" + depends on MFD_ARIZONA && SND_SOC + select INPUT_FF_MEMLESS + help + Say Y to enable support for the haptics module in Arizona CODECs. + + To compile this driver as a module, choose M here: the + module will be called arizona-haptics. + config INPUT_BMA150 tristate "BMA150/SMB380 acceleration sensor support" depends on I2C diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 83fe6f5b77d1..5ea769eda999 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o obj-$(CONFIG_INPUT_APANEL) += apanel.o +obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c new file mode 100644 index 000000000000..7a04f54ef961 --- /dev/null +++ b/drivers/input/misc/arizona-haptics.c @@ -0,0 +1,255 @@ +/* + * Arizona haptics driver + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/slab.h> + +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include <linux/mfd/arizona/core.h> +#include <linux/mfd/arizona/pdata.h> +#include <linux/mfd/arizona/registers.h> + +struct arizona_haptics { + struct arizona *arizona; + struct input_dev *input_dev; + struct work_struct work; + + struct mutex mutex; + u8 intensity; +}; + +static void arizona_haptics_work(struct work_struct *work) +{ + struct arizona_haptics *haptics = container_of(work, + struct arizona_haptics, + work); + struct arizona *arizona = haptics->arizona; + struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex; + int ret; + + if (!haptics->arizona->dapm) { + dev_err(arizona->dev, "No DAPM context\n"); + return; + } + + if (haptics->intensity) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_HAPTICS_PHASE_2_INTENSITY, + ARIZONA_PHASE2_INTENSITY_MASK, + haptics->intensity); + if (ret != 0) { + dev_err(arizona->dev, "Failed to set intensity: %d\n", + ret); + return; + } + + /* This enable sequence will be a noop if already enabled */ + ret = regmap_update_bits(arizona->regmap, + ARIZONA_HAPTICS_CONTROL_1, + ARIZONA_HAP_CTRL_MASK, + 1 << ARIZONA_HAP_CTRL_SHIFT); + if (ret != 0) { + dev_err(arizona->dev, "Failed to start haptics: %d\n", + ret); + return; + } + + mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS"); + if (ret != 0) { + dev_err(arizona->dev, "Failed to start HAPTICS: %d\n", + ret); + mutex_unlock(dapm_mutex); + return; + } + + ret = snd_soc_dapm_sync(arizona->dapm); + if (ret != 0) { + dev_err(arizona->dev, "Failed to sync DAPM: %d\n", + ret); + mutex_unlock(dapm_mutex); + return; + } + + mutex_unlock(dapm_mutex); + + } else { + /* This disable sequence will be a noop if already enabled */ + mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS"); + if (ret != 0) { + dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n", + ret); + mutex_unlock(dapm_mutex); + return; + } + + ret = snd_soc_dapm_sync(arizona->dapm); + if (ret != 0) { + dev_err(arizona->dev, "Failed to sync DAPM: %d\n", + ret); + mutex_unlock(dapm_mutex); + return; + } + + mutex_unlock(dapm_mutex); + + ret = regmap_update_bits(arizona->regmap, + ARIZONA_HAPTICS_CONTROL_1, + ARIZONA_HAP_CTRL_MASK, + 1 << ARIZONA_HAP_CTRL_SHIFT); + if (ret != 0) { + dev_err(arizona->dev, "Failed to stop haptics: %d\n", + ret); + return; + } + } +} + +static int arizona_haptics_play(struct input_dev *input, void *data, + struct ff_effect *effect) +{ + struct arizona_haptics *haptics = input_get_drvdata(input); + struct arizona *arizona = haptics->arizona; + + if (!arizona->dapm) { + dev_err(arizona->dev, "No DAPM context\n"); + return -EBUSY; + } + + if (effect->u.rumble.strong_magnitude) { + /* Scale the magnitude into the range the device supports */ + if (arizona->pdata.hap_act) { + haptics->intensity = + effect->u.rumble.strong_magnitude >> 9; + if (effect->direction < 0x8000) + haptics->intensity += 0x7f; + } else { + haptics->intensity = + effect->u.rumble.strong_magnitude >> 8; + } + } else { + haptics->intensity = 0; + } + + schedule_work(&haptics->work); + + return 0; +} + +static void arizona_haptics_close(struct input_dev *input) +{ + struct arizona_haptics *haptics = input_get_drvdata(input); + struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex; + + cancel_work_sync(&haptics->work); + + mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + if (haptics->arizona->dapm) + snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS"); + + mutex_unlock(dapm_mutex); +} + +static int arizona_haptics_probe(struct platform_device *pdev) +{ + struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + struct arizona_haptics *haptics; + int ret; + + haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL); + if (!haptics) + return -ENOMEM; + + haptics->arizona = arizona; + + ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1, + ARIZONA_HAP_ACT, arizona->pdata.hap_act); + if (ret != 0) { + dev_err(arizona->dev, "Failed to set haptics actuator: %d\n", + ret); + return ret; + } + + INIT_WORK(&haptics->work, arizona_haptics_work); + + haptics->input_dev = input_allocate_device(); + if (haptics->input_dev == NULL) { + dev_err(arizona->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + input_set_drvdata(haptics->input_dev, haptics); + + haptics->input_dev->name = "arizona:haptics"; + haptics->input_dev->dev.parent = pdev->dev.parent; + haptics->input_dev->close = arizona_haptics_close; + __set_bit(FF_RUMBLE, haptics->input_dev->ffbit); + + ret = input_ff_create_memless(haptics->input_dev, NULL, + arizona_haptics_play); + if (ret < 0) { + dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n", + ret); + goto err_ialloc; + } + + ret = input_register_device(haptics->input_dev); + if (ret < 0) { + dev_err(arizona->dev, "couldn't register input device: %d\n", + ret); + goto err_iff; + } + + platform_set_drvdata(pdev, haptics); + + return 0; + +err_iff: + if (haptics->input_dev) + input_ff_destroy(haptics->input_dev); +err_ialloc: + input_free_device(haptics->input_dev); + + return ret; +} + +static int arizona_haptics_remove(struct platform_device *pdev) +{ + struct arizona_haptics *haptics = platform_get_drvdata(pdev); + + input_unregister_device(haptics->input_dev); + + return 0; +} + +static struct platform_driver arizona_haptics_driver = { + .probe = arizona_haptics_probe, + .remove = arizona_haptics_remove, + .driver = { + .name = "arizona-haptics", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(arizona_haptics_driver); + +MODULE_ALIAS("platform:arizona-haptics"); +MODULE_DESCRIPTION("Arizona haptics driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 8f02e3d0e712..4c842c320c2e 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -12,8 +12,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define MOUSEDEV_MINOR_BASE 32 -#define MOUSEDEV_MINORS 32 -#define MOUSEDEV_MIX 31 +#define MOUSEDEV_MINORS 31 +#define MOUSEDEV_MIX 63 #include <linux/sched.h> #include <linux/slab.h> diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f02028ec3db6..78e5d9ab0ba7 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -955,7 +955,8 @@ static int ads7846_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); -static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts) +static int __devinit ads7846_setup_pendown(struct spi_device *spi, + struct ads7846 *ts) { struct ads7846_platform_data *pdata = spi->dev.platform_data; int err; @@ -981,6 +982,9 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784 ts->gpio_pendown = pdata->gpio_pendown; + if (pdata->gpio_pendown_debounce) + gpio_set_debounce(pdata->gpio_pendown, + pdata->gpio_pendown_debounce); } else { dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); return -EINVAL; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index d4a4cd445cab..0badfa48b32b 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4108,7 +4108,7 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) static int intel_iommu_add_device(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct pci_dev *bridge, *dma_pdev; + struct pci_dev *bridge, *dma_pdev = NULL; struct iommu_group *group; int ret; @@ -4122,7 +4122,7 @@ static int intel_iommu_add_device(struct device *dev) dma_pdev = pci_get_domain_bus_and_slot( pci_domain_nr(pdev->bus), bridge->subordinate->number, 0); - else + if (!dma_pdev) dma_pdev = pci_dev_get(bridge); } else dma_pdev = pci_dev_get(pdev); diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index a649f146d17b..c0f7a4266263 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1054,6 +1054,7 @@ static int smmu_debugfs_stats_show(struct seq_file *s, void *v) stats[i], val, offs); } seq_printf(s, "\n"); + dput(dent); return 0; } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 02db9183ca01..77e6eff41cae 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -740,8 +740,14 @@ static void rq_completed(struct mapped_device *md, int rw, int run_queue) if (!md_in_flight(md)) wake_up(&md->wait); + /* + * Run this off this callpath, as drivers could invoke end_io while + * inside their request_fn (and holding the queue lock). Calling + * back into ->request_fn() could deadlock attempting to grab the + * queue lock again. + */ if (run_queue) - blk_run_queue(md->queue); + blk_run_queue_async(md->queue); /* * dm_put() must be at the end of this function. See the comment above diff --git a/drivers/md/md.c b/drivers/md/md.c index 9ab768acfb62..61200717687b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1817,10 +1817,10 @@ retry: memset(bbp, 0xff, PAGE_SIZE); for (i = 0 ; i < bb->count ; i++) { - u64 internal_bb = *p++; + u64 internal_bb = p[i]; u64 store_bb = ((BB_OFFSET(internal_bb) << 10) | BB_LEN(internal_bb)); - *bbp++ = cpu_to_le64(store_bb); + bbp[i] = cpu_to_le64(store_bb); } bb->changed = 0; if (read_seqretry(&bb->lock, seq)) @@ -5294,7 +5294,7 @@ void md_stop_writes(struct mddev *mddev) } EXPORT_SYMBOL_GPL(md_stop_writes); -void md_stop(struct mddev *mddev) +static void __md_stop(struct mddev *mddev) { mddev->ready = 0; mddev->pers->stop(mddev); @@ -5304,6 +5304,18 @@ void md_stop(struct mddev *mddev) mddev->pers = NULL; clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); } + +void md_stop(struct mddev *mddev) +{ + /* stop the array and free an attached data structures. + * This is called from dm-raid + */ + __md_stop(mddev); + bitmap_destroy(mddev); + if (mddev->bio_set) + bioset_free(mddev->bio_set); +} + EXPORT_SYMBOL_GPL(md_stop); static int md_set_readonly(struct mddev *mddev, struct block_device *bdev) @@ -5364,7 +5376,7 @@ static int do_md_stop(struct mddev * mddev, int mode, set_disk_ro(disk, 0); __md_stop_writes(mddev); - md_stop(mddev); + __md_stop(mddev); mddev->queue->merge_bvec_fn = NULL; mddev->queue->backing_dev_info.congested_fn = NULL; @@ -7936,9 +7948,9 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, sector_t *first_bad, int *bad_sectors) { int hi; - int lo = 0; + int lo; u64 *p = bb->page; - int rv = 0; + int rv; sector_t target = s + sectors; unsigned seq; @@ -7953,7 +7965,8 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, retry: seq = read_seqbegin(&bb->lock); - + lo = 0; + rv = 0; hi = bb->count; /* Binary search between lo and hi for 'target' diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d1295aff4173..0d5d0ff2c0f7 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -499,7 +499,7 @@ static void raid10_end_write_request(struct bio *bio, int error) */ one_write_done(r10_bio); if (dec_rdev) - rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); + rdev_dec_pending(rdev, conf->mddev); } /* @@ -1334,18 +1334,21 @@ retry_write: blocked_rdev = rrdev; break; } + if (rdev && (test_bit(Faulty, &rdev->flags) + || test_bit(Unmerged, &rdev->flags))) + rdev = NULL; if (rrdev && (test_bit(Faulty, &rrdev->flags) || test_bit(Unmerged, &rrdev->flags))) rrdev = NULL; r10_bio->devs[i].bio = NULL; r10_bio->devs[i].repl_bio = NULL; - if (!rdev || test_bit(Faulty, &rdev->flags) || - test_bit(Unmerged, &rdev->flags)) { + + if (!rdev && !rrdev) { set_bit(R10BIO_Degraded, &r10_bio->state); continue; } - if (test_bit(WriteErrorSeen, &rdev->flags)) { + if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) { sector_t first_bad; sector_t dev_sector = r10_bio->devs[i].addr; int bad_sectors; @@ -1387,8 +1390,10 @@ retry_write: max_sectors = good_sectors; } } - r10_bio->devs[i].bio = bio; - atomic_inc(&rdev->nr_pending); + if (rdev) { + r10_bio->devs[i].bio = bio; + atomic_inc(&rdev->nr_pending); + } if (rrdev) { r10_bio->devs[i].repl_bio = bio; atomic_inc(&rrdev->nr_pending); @@ -1444,69 +1449,71 @@ retry_write: for (i = 0; i < conf->copies; i++) { struct bio *mbio; int d = r10_bio->devs[i].devnum; - if (!r10_bio->devs[i].bio) - continue; + if (r10_bio->devs[i].bio) { + struct md_rdev *rdev = conf->mirrors[d].rdev; + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr+ + choose_data_offset(r10_bio, + rdev)); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_private = r10_bio; - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].bio = mbio; + atomic_inc(&r10_bio->remaining); - mbio->bi_sector = (r10_bio->devs[i].addr+ - choose_data_offset(r10_bio, - conf->mirrors[d].rdev)); - mbio->bi_bdev = conf->mirrors[d].rdev->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; - mbio->bi_private = r10_bio; + cb = blk_check_plugged(raid10_unplug, mddev, + sizeof(*plug)); + if (cb) + plug = container_of(cb, struct raid10_plug_cb, + cb); + else + plug = NULL; + spin_lock_irqsave(&conf->device_lock, flags); + if (plug) { + bio_list_add(&plug->pending, mbio); + plug->pending_cnt++; + } else { + bio_list_add(&conf->pending_bio_list, mbio); + conf->pending_count++; + } + spin_unlock_irqrestore(&conf->device_lock, flags); + if (!plug) + md_wakeup_thread(mddev->thread); + } - atomic_inc(&r10_bio->remaining); + if (r10_bio->devs[i].repl_bio) { + struct md_rdev *rdev = conf->mirrors[d].replacement; + if (rdev == NULL) { + /* Replacement just got moved to main 'rdev' */ + smp_mb(); + rdev = conf->mirrors[d].rdev; + } + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].repl_bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr + + choose_data_offset( + r10_bio, rdev)); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_private = r10_bio; - cb = blk_check_plugged(raid10_unplug, mddev, sizeof(*plug)); - if (cb) - plug = container_of(cb, struct raid10_plug_cb, cb); - else - plug = NULL; - spin_lock_irqsave(&conf->device_lock, flags); - if (plug) { - bio_list_add(&plug->pending, mbio); - plug->pending_cnt++; - } else { + atomic_inc(&r10_bio->remaining); + spin_lock_irqsave(&conf->device_lock, flags); bio_list_add(&conf->pending_bio_list, mbio); conf->pending_count++; + spin_unlock_irqrestore(&conf->device_lock, flags); + if (!mddev_check_plugged(mddev)) + md_wakeup_thread(mddev->thread); } - spin_unlock_irqrestore(&conf->device_lock, flags); - if (!plug) - md_wakeup_thread(mddev->thread); - - if (!r10_bio->devs[i].repl_bio) - continue; - - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].repl_bio = mbio; - - /* We are actively writing to the original device - * so it cannot disappear, so the replacement cannot - * become NULL here - */ - mbio->bi_sector = (r10_bio->devs[i].addr + - choose_data_offset( - r10_bio, - conf->mirrors[d].replacement)); - mbio->bi_bdev = conf->mirrors[d].replacement->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; - mbio->bi_private = r10_bio; - - atomic_inc(&r10_bio->remaining); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_add(&conf->pending_bio_list, mbio); - conf->pending_count++; - spin_unlock_irqrestore(&conf->device_lock, flags); - if (!mddev_check_plugged(mddev)) - md_wakeup_thread(mddev->thread); } /* Don't remove the bias on 'remaining' (one_write_done) until diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index c5439dce0295..a4502686e7a8 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2774,10 +2774,12 @@ static void handle_stripe_clean_event(struct r5conf *conf, dev = &sh->dev[i]; if (!test_bit(R5_LOCKED, &dev->flags) && (test_bit(R5_UPTODATE, &dev->flags) || - test_and_clear_bit(R5_Discard, &dev->flags))) { + test_bit(R5_Discard, &dev->flags))) { /* We can return any write requests */ struct bio *wbi, *wbi2; pr_debug("Return write for disc %d\n", i); + if (test_and_clear_bit(R5_Discard, &dev->flags)) + clear_bit(R5_UPTODATE, &dev->flags); wbi = dev->written; dev->written = NULL; while (wbi && wbi->bi_sector < @@ -2795,7 +2797,8 @@ static void handle_stripe_clean_event(struct r5conf *conf, !test_bit(STRIPE_DEGRADED, &sh->state), 0); } - } + } else if (test_bit(R5_Discard, &sh->dev[i].flags)) + clear_bit(R5_Discard, &sh->dev[i].flags); if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state)) if (atomic_dec_and_test(&conf->pending_full_writes)) @@ -3490,40 +3493,6 @@ static void handle_stripe(struct stripe_head *sh) handle_failed_sync(conf, sh, &s); } - /* - * might be able to return some write requests if the parity blocks - * are safe, or on a failed drive - */ - pdev = &sh->dev[sh->pd_idx]; - s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx) - || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx); - qdev = &sh->dev[sh->qd_idx]; - s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx) - || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx) - || conf->level < 6; - - if (s.written && - (s.p_failed || ((test_bit(R5_Insync, &pdev->flags) - && !test_bit(R5_LOCKED, &pdev->flags) - && (test_bit(R5_UPTODATE, &pdev->flags) || - test_bit(R5_Discard, &pdev->flags))))) && - (s.q_failed || ((test_bit(R5_Insync, &qdev->flags) - && !test_bit(R5_LOCKED, &qdev->flags) - && (test_bit(R5_UPTODATE, &qdev->flags) || - test_bit(R5_Discard, &qdev->flags)))))) - handle_stripe_clean_event(conf, sh, disks, &s.return_bi); - - /* Now we might consider reading some blocks, either to check/generate - * parity, or to satisfy requests - * or to load a block that is being partially written. - */ - if (s.to_read || s.non_overwrite - || (conf->level == 6 && s.to_write && s.failed) - || (s.syncing && (s.uptodate + s.compute < disks)) - || s.replacing - || s.expanding) - handle_stripe_fill(sh, &s, disks); - /* Now we check to see if any write operations have recently * completed */ @@ -3561,6 +3530,40 @@ static void handle_stripe(struct stripe_head *sh) s.dec_preread_active = 1; } + /* + * might be able to return some write requests if the parity blocks + * are safe, or on a failed drive + */ + pdev = &sh->dev[sh->pd_idx]; + s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx) + || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx); + qdev = &sh->dev[sh->qd_idx]; + s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx) + || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx) + || conf->level < 6; + + if (s.written && + (s.p_failed || ((test_bit(R5_Insync, &pdev->flags) + && !test_bit(R5_LOCKED, &pdev->flags) + && (test_bit(R5_UPTODATE, &pdev->flags) || + test_bit(R5_Discard, &pdev->flags))))) && + (s.q_failed || ((test_bit(R5_Insync, &qdev->flags) + && !test_bit(R5_LOCKED, &qdev->flags) + && (test_bit(R5_UPTODATE, &qdev->flags) || + test_bit(R5_Discard, &qdev->flags)))))) + handle_stripe_clean_event(conf, sh, disks, &s.return_bi); + + /* Now we might consider reading some blocks, either to check/generate + * parity, or to satisfy requests + * or to load a block that is being partially written. + */ + if (s.to_read || s.non_overwrite + || (conf->level == 6 && s.to_write && s.failed) + || (s.syncing && (s.uptodate + s.compute < disks)) + || s.replacing + || s.expanding) + handle_stripe_fill(sh, &s, disks); + /* Now to consider new write requests and what else, if anything * should be read. We do not handle new writes when: * 1/ A 'write' operation (copy+xor) is already in flight. @@ -5529,6 +5532,10 @@ static int run(struct mddev *mddev) * discard data disk but write parity disk */ stripe = stripe * PAGE_SIZE; + /* Round up to power of 2, as discard handling + * currently assumes that */ + while ((stripe-1) & stripe) + stripe = (stripe | (stripe-1)) + 1; mddev->queue->limits.discard_alignment = stripe; mddev->queue->limits.discard_granularity = stripe; /* diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 1b48f2094806..75619711a9e7 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -272,6 +272,7 @@ static struct mfd_cell early_devs[] = { static struct mfd_cell wm5102_devs[] = { { .name = "arizona-extcon" }, { .name = "arizona-gpio" }, + { .name = "arizona-haptics" }, { .name = "arizona-micsupp" }, { .name = "arizona-pwm" }, { .name = "wm5102-codec" }, @@ -280,6 +281,7 @@ static struct mfd_cell wm5102_devs[] = { static struct mfd_cell wm5110_devs[] = { { .name = "arizona-extcon" }, { .name = "arizona-gpio" }, + { .name = "arizona-haptics" }, { .name = "arizona-micsupp" }, { .name = "arizona-pwm" }, { .name = "wm5110-codec" }, diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5bb187781074..d07a9eda7fff 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -18,6 +18,8 @@ #include <linux/slab.h> #include <linux/module.h> +#include <linux/of.h> + /* Serialize access to ssc_list and user count */ static DEFINE_SPINLOCK(user_lock); static LIST_HEAD(ssc_list); @@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num) spin_lock(&user_lock); list_for_each_entry(ssc, &ssc_list, list) { - if (ssc->pdev->id == ssc_num) { + if (ssc->pdev->dev.of_node) { + if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc") + == ssc_num) { + ssc_valid = 1; + break; + } + } else if (ssc->pdev->id == ssc_num) { ssc_valid = 1; break; } @@ -68,39 +76,93 @@ void ssc_free(struct ssc_device *ssc) } EXPORT_SYMBOL(ssc_free); -static int __init ssc_probe(struct platform_device *pdev) +static struct atmel_ssc_platform_data at91rm9200_config = { + .use_dma = 0, +}; + +static struct atmel_ssc_platform_data at91sam9g45_config = { + .use_dma = 1, +}; + +static const struct platform_device_id atmel_ssc_devtypes[] = { + { + .name = "at91rm9200_ssc", + .driver_data = (unsigned long) &at91rm9200_config, + }, { + .name = "at91sam9g45_ssc", + .driver_data = (unsigned long) &at91sam9g45_config, + }, { + /* sentinel */ + } +}; + +#ifdef CONFIG_OF +static const struct of_device_id atmel_ssc_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-ssc", + .data = &at91rm9200_config, + }, { + .compatible = "atmel,at91sam9g45-ssc", + .data = &at91sam9g45_config, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids); +#endif + +static inline const struct atmel_ssc_platform_data * __init + atmel_ssc_get_driver_data(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_ssc_dt_ids, pdev->dev.of_node); + if (match == NULL) + return NULL; + return match->data; + } + + return (struct atmel_ssc_platform_data *) + platform_get_device_id(pdev)->driver_data; +} + +static int ssc_probe(struct platform_device *pdev) { - int retval = 0; struct resource *regs; struct ssc_device *ssc; + const struct atmel_ssc_platform_data *plat_dat; - ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL); + ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); if (!ssc) { dev_dbg(&pdev->dev, "out of memory\n"); - retval = -ENOMEM; - goto out; + return -ENOMEM; } + ssc->pdev = pdev; + + plat_dat = atmel_ssc_get_driver_data(pdev); + if (!plat_dat) + return -ENODEV; + ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat; + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_dbg(&pdev->dev, "no mmio resource defined\n"); - retval = -ENXIO; - goto out_free; + return -ENXIO; } - ssc->clk = clk_get(&pdev->dev, "pclk"); - if (IS_ERR(ssc->clk)) { - dev_dbg(&pdev->dev, "no pclk clock defined\n"); - retval = -ENXIO; - goto out_free; - } - - ssc->pdev = pdev; - ssc->regs = ioremap(regs->start, resource_size(regs)); + ssc->regs = devm_request_and_ioremap(&pdev->dev, regs); if (!ssc->regs) { dev_dbg(&pdev->dev, "ioremap failed\n"); - retval = -EINVAL; - goto out_clk; + return -EINVAL; + } + + ssc->phybase = regs->start; + + ssc->clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(ssc->clk)) { + dev_dbg(&pdev->dev, "no pclk clock defined\n"); + return -ENXIO; } /* disable all interrupts */ @@ -112,8 +174,7 @@ static int __init ssc_probe(struct platform_device *pdev) ssc->irq = platform_get_irq(pdev, 0); if (!ssc->irq) { dev_dbg(&pdev->dev, "could not get irq\n"); - retval = -ENXIO; - goto out_unmap; + return -ENXIO; } spin_lock(&user_lock); @@ -125,16 +186,7 @@ static int __init ssc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n", ssc->regs, ssc->irq); - goto out; - -out_unmap: - iounmap(ssc->regs); -out_clk: - clk_put(ssc->clk); -out_free: - kfree(ssc); -out: - return retval; + return 0; } static int __devexit ssc_remove(struct platform_device *pdev) @@ -142,34 +194,23 @@ static int __devexit ssc_remove(struct platform_device *pdev) struct ssc_device *ssc = platform_get_drvdata(pdev); spin_lock(&user_lock); - iounmap(ssc->regs); - clk_put(ssc->clk); list_del(&ssc->list); - kfree(ssc); spin_unlock(&user_lock); return 0; } static struct platform_driver ssc_driver = { - .remove = __devexit_p(ssc_remove), .driver = { .name = "ssc", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_ssc_dt_ids), }, + .id_table = atmel_ssc_devtypes, + .probe = ssc_probe, + .remove = __devexit_p(ssc_remove), }; - -static int __init ssc_init(void) -{ - return platform_driver_probe(&ssc_driver, ssc_probe); -} -module_init(ssc_init); - -static void __exit ssc_exit(void) -{ - platform_driver_unregister(&ssc_driver); -} -module_exit(ssc_exit); +module_platform_driver(ssc_driver); MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91"); diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 8f52fc858e48..5a5cd2ace4a6 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -240,7 +240,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) if (*(szlength) != '+') { devlength = simple_strtoul(szlength, &buffer, 0); - devlength = handle_unit(devlength, buffer) - devstart; + devlength = handle_unit(devlength, buffer); if (devlength < devstart) goto err_out; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ec6841d8e956..1a03b7f673ce 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2983,13 +2983,15 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, /* * Field definitions are in the following datasheets: * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New style (6 byte ID): Samsung K9GAG08U0F (p.44) + * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22) * - * Check for ID length, cell type, and Hynix/Samsung ID to decide what - * to do. + * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung + * ID to decide what to do. */ - if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG) { + if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && + (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + id_data[5] != 0x00) { /* Calc pagesize */ mtd->writesize = 2048 << (extid & 0x03); extid >>= 2; diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 64be8f0848b0..d9127e2ed808 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -121,7 +121,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, nr_parts = plen / sizeof(part[0]); *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); - if (!pparts) + if (!*pparts) return -ENOMEM; names = of_get_property(dp, "partition-names", &plen); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7153e0d27101..b3f41f200622 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -3694,7 +3694,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int * flexonenand_set_boundary - Writes the SLC boundary * @param mtd - mtd info structure */ -int flexonenand_set_boundary(struct mtd_info *mtd, int die, +static int flexonenand_set_boundary(struct mtd_info *mtd, int die, int boundary, int lock) { struct onenand_chip *this = mtd->priv; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b2530b002125..5f5b69f37d2e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1379,6 +1379,8 @@ static void bond_compute_features(struct bonding *bond) struct net_device *bond_dev = bond->dev; netdev_features_t vlan_features = BOND_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; + unsigned int gso_max_size = GSO_MAX_SIZE; + u16 gso_max_segs = GSO_MAX_SEGS; int i; unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE; @@ -1394,11 +1396,16 @@ static void bond_compute_features(struct bonding *bond) dst_release_flag &= slave->dev->priv_flags; if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; + + gso_max_size = min(gso_max_size, slave->dev->gso_max_size); + gso_max_segs = min(gso_max_segs, slave->dev->gso_max_segs); } done: bond_dev->vlan_features = vlan_features; bond_dev->hard_header_len = max_hard_header_len; + bond_dev->gso_max_segs = gso_max_segs; + netif_set_gso_max_size(bond_dev, gso_max_size); flags = bond_dev->priv_flags & ~IFF_XMIT_DST_RELEASE; bond_dev->priv_flags = flags | dst_release_flag; diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index d04911d33b64..47618e505355 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -813,6 +813,7 @@ static int __init ne_drv_probe(struct platform_device *pdev) dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; } + SET_NETDEV_DEV(dev, &pdev->dev); err = do_ne_probe(dev); if (err) { free_netdev(dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index bd1fd3d87c24..01611b33a93d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9545,10 +9545,13 @@ static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp) */ static void __devinit bnx2x_prev_interrupted_dmae(struct bnx2x *bp) { - u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); - if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { - BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); - REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, 1 << BP_FUNC(bp)); + if (!CHIP_IS_E1x(bp)) { + u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { + BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); + REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, + 1 << BP_FUNC(bp)); + } } } diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 1c818254b7be..b01f83a044c4 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -979,17 +979,6 @@ static void cp_init_hw (struct cp_private *cp) cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); - cpw32_f(HiTxRingAddr, 0); - cpw32_f(HiTxRingAddr + 4, 0); - - ring_dma = cp->ring_dma; - cpw32_f(RxRingAddr, ring_dma & 0xffffffff); - cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); - - ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; - cpw32_f(TxRingAddr, ring_dma & 0xffffffff); - cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); - cp_start_hw(cp); cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ @@ -1003,6 +992,17 @@ static void cp_init_hw (struct cp_private *cp) cpw8(Config5, cpr8(Config5) & PMEStatus); + cpw32_f(HiTxRingAddr, 0); + cpw32_f(HiTxRingAddr + 4, 0); + + ring_dma = cp->ring_dma; + cpw32_f(RxRingAddr, ring_dma & 0xffffffff); + cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); + + ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; + cpw32_f(TxRingAddr, ring_dma & 0xffffffff); + cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); + cpw16(MultiIntr, 0); cpw8_f(Cfg9346, Cfg9346_Lock); diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index fb9f6b38511f..edf5edb13140 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -2479,7 +2479,7 @@ static int sis900_resume(struct pci_dev *pci_dev) netif_start_queue(net_dev); /* Workaround for EDB */ - sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); + sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); /* Enable all known interrupts by setting the interrupt mask. */ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 77e6db9dcfed..a788501e978e 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -894,6 +894,8 @@ out: return IRQ_HANDLED; } +static void axienet_dma_err_handler(unsigned long data); + /** * axienet_open - Driver open routine. * @ndev: Pointer to net_device structure diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index 98934bdf6acf..477d6729b17f 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -1102,10 +1102,12 @@ static int init_queues(struct port *port) { int i; - if (!ports_open) - if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, - POOL_ALLOC_SIZE, 32, 0))) + if (!ports_open) { + dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev, + POOL_ALLOC_SIZE, 32, 0); + if (!dma_pool) return -ENOMEM; + } if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, &port->desc_tab_phys))) diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 5039f08f5a5b..43e9ab4f4d7e 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -222,7 +222,7 @@ static void sirdev_config_fsm(struct work_struct *work) break; case SIRDEV_STATE_DONGLE_SPEED: - if (dev->dongle_drv->reset) { + if (dev->dongle_drv->set_speed) { ret = dev->dongle_drv->set_speed(dev, fsm->param); if (ret < 0) { fsm->result = ret; diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 899274f2f9b1..2ed1140df3e9 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -185,17 +185,20 @@ static int __devinit mdio_gpio_probe(struct platform_device *pdev) { struct mdio_gpio_platform_data *pdata; struct mii_bus *new_bus; - int ret; + int ret, bus_id; - if (pdev->dev.of_node) + if (pdev->dev.of_node) { pdata = mdio_gpio_of_get_data(pdev); - else + bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); + } else { pdata = pdev->dev.platform_data; + bus_id = pdev->id; + } if (!pdata) return -ENODEV; - new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id); + new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, bus_id); if (!new_bus) return -ENODEV; diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c index 9db0171e9366..c5db428e73fa 100644 --- a/drivers/net/team/team_mode_broadcast.c +++ b/drivers/net/team/team_mode_broadcast.c @@ -29,8 +29,8 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb) if (last) { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { - ret = team_dev_queue_xmit(team, last, - skb2); + ret = !team_dev_queue_xmit(team, last, + skb2); if (!sum_ret) sum_ret = ret; } @@ -39,7 +39,7 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb) } } if (last) { - ret = team_dev_queue_xmit(team, last, skb); + ret = !team_dev_queue_xmit(team, last, skb); if (!sum_ret) sum_ret = ret; } diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 3f575afd8cfc..e9a3da588e95 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -969,10 +969,12 @@ static int init_hdlc_queues(struct port *port) { int i; - if (!ports_open) - if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, - POOL_ALLOC_SIZE, 32, 0))) + if (!ports_open) { + dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev, + POOL_ALLOC_SIZE, 32, 0); + if (!dma_pool) return -ENOMEM; + } if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, &port->desc_tab_phys))) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8e1559aba495..1829b445d0b0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1456,7 +1456,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: ret = ath9k_hw_set_reset_power_on(ah); - if (!ret) + if (ret) ah->reset_power_on = true; break; case ATH9K_RESET_WARM: diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index fa4d1b8cd9f6..2d9eee93c743 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1354,6 +1354,20 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, vif_priv->ctx = ctx; ctx->vif = vif; + /* + * In SNIFFER device type, the firmware reports the FCS to + * the host, rather than snipping it off. Unfortunately, + * mac80211 doesn't (yet) provide a per-packet flag for + * this, so that we have to set the hardware flag based + * on the interfaces added. As the monitor interface can + * only be present by itself, and will be removed before + * other interfaces are added, this is safe. + */ + if (vif->type == NL80211_IFTYPE_MONITOR) + priv->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + priv->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + err = iwl_setup_interface(priv, ctx); if (!err || reset) goto out; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 105e3af3c621..79a4ddc002d3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -480,20 +480,12 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 rd_ptr, wr_ptr; - int n_bd = trans_pcie->txq[txq_id].q.n_bd; if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) { WARN_ONCE(1, "queue %d not used", txq_id); return; } - rd_ptr = iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (n_bd - 1); - wr_ptr = iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id)); - - WARN_ONCE(rd_ptr != wr_ptr, "queue %d isn't empty: [%d,%d]", - txq_id, rd_ptr, wr_ptr); - iwl_txq_set_inactive(trans, txq_id); IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id); } diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 8d465107f52b..ae9010ed58de 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -890,9 +890,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wait_q_enabled) - adapter->cmd_wait_q.status = -ETIMEDOUT; - if (cmd_node) { adapter->dbg.timeout_cmd_id = adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; @@ -938,6 +935,14 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + wake_up_interruptible(&adapter->cmd_wait_q.wait); + mwifiex_cancel_pending_ioctl(adapter); + /* reset cmd_sent flag to unblock new commands */ + adapter->cmd_sent = false; + } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index fc8a9bfa1248..82cf0fa2d9f6 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -161,7 +161,6 @@ static int mwifiex_sdio_suspend(struct device *dev) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; - int hs_actived = 0; int i; int ret = 0; @@ -188,12 +187,14 @@ static int mwifiex_sdio_suspend(struct device *dev) adapter = card->adapter; /* Enable the Host Sleep */ - hs_actived = mwifiex_enable_hs(adapter); - if (hs_actived) { - pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (!mwifiex_enable_hs(adapter)) { + dev_err(adapter->dev, "cmd: failed to suspend\n"); + return -EFAULT; } + dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + /* Indicate device suspended */ adapter->is_suspended = true; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 9970c2b1b199..b7e6607e6b6d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -297,6 +297,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { /*=== Customer ID ===*/ /****** 8188CU ********/ {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ + {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/ {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index caa011008cd0..fc24eb9b3948 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -452,29 +452,85 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, /* Grant backend access to each skb fragment page. */ for (i = 0; i < frags; i++) { skb_frag_t *frag = skb_shinfo(skb)->frags + i; + struct page *page = skb_frag_page(frag); - tx->flags |= XEN_NETTXF_more_data; + len = skb_frag_size(frag); + offset = frag->page_offset; - id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs); - np->tx_skbs[id].skb = skb_get(skb); - tx = RING_GET_REQUEST(&np->tx, prod++); - tx->id = id; - ref = gnttab_claim_grant_reference(&np->gref_tx_head); - BUG_ON((signed short)ref < 0); + /* Data must not cross a page boundary. */ + BUG_ON(len + offset > PAGE_SIZE<<compound_order(page)); - mfn = pfn_to_mfn(page_to_pfn(skb_frag_page(frag))); - gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, - mfn, GNTMAP_readonly); + /* Skip unused frames from start of page */ + page += offset >> PAGE_SHIFT; + offset &= ~PAGE_MASK; - tx->gref = np->grant_tx_ref[id] = ref; - tx->offset = frag->page_offset; - tx->size = skb_frag_size(frag); - tx->flags = 0; + while (len > 0) { + unsigned long bytes; + + BUG_ON(offset >= PAGE_SIZE); + + bytes = PAGE_SIZE - offset; + if (bytes > len) + bytes = len; + + tx->flags |= XEN_NETTXF_more_data; + + id = get_id_from_freelist(&np->tx_skb_freelist, + np->tx_skbs); + np->tx_skbs[id].skb = skb_get(skb); + tx = RING_GET_REQUEST(&np->tx, prod++); + tx->id = id; + ref = gnttab_claim_grant_reference(&np->gref_tx_head); + BUG_ON((signed short)ref < 0); + + mfn = pfn_to_mfn(page_to_pfn(page)); + gnttab_grant_foreign_access_ref(ref, + np->xbdev->otherend_id, + mfn, GNTMAP_readonly); + + tx->gref = np->grant_tx_ref[id] = ref; + tx->offset = offset; + tx->size = bytes; + tx->flags = 0; + + offset += bytes; + len -= bytes; + + /* Next frame */ + if (offset == PAGE_SIZE && len) { + BUG_ON(!PageCompound(page)); + page++; + offset = 0; + } + } } np->tx.req_prod_pvt = prod; } +/* + * Count how many ring slots are required to send the frags of this + * skb. Each frag might be a compound page. + */ +static int xennet_count_skb_frag_slots(struct sk_buff *skb) +{ + int i, frags = skb_shinfo(skb)->nr_frags; + int pages = 0; + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + unsigned long size = skb_frag_size(frag); + unsigned long offset = frag->page_offset; + + /* Skip unused frames from start of page */ + offset &= ~PAGE_MASK; + + pages += PFN_UP(offset + size); + } + + return pages; +} + static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned short id; @@ -487,23 +543,23 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) grant_ref_t ref; unsigned long mfn; int notify; - int frags = skb_shinfo(skb)->nr_frags; + int slots; unsigned int offset = offset_in_page(data); unsigned int len = skb_headlen(skb); unsigned long flags; - frags += DIV_ROUND_UP(offset + len, PAGE_SIZE); - if (unlikely(frags > MAX_SKB_FRAGS + 1)) { - printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n", - frags); - dump_stack(); + slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) + + xennet_count_skb_frag_slots(skb); + if (unlikely(slots > MAX_SKB_FRAGS + 1)) { + net_alert_ratelimited( + "xennet: skb rides the rocket: %d slots\n", slots); goto drop; } spin_lock_irqsave(&np->tx_lock, flags); if (unlikely(!netif_carrier_ok(dev) || - (frags > 1 && !xennet_can_sg(dev)) || + (slots > 1 && !xennet_can_sg(dev)) || netif_needs_gso(skb, netif_skb_features(skb)))) { spin_unlock_irqrestore(&np->tx_lock, flags); goto drop; diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 97c440a8cd61..30ae18a03a9c 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -698,13 +698,14 @@ static void pn533_wq_cmd(struct work_struct *work) cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); + list_del(&cmd->queue); + mutex_unlock(&dev->cmd_lock); __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, cmd->in_frame_len, cmd->cmd_complete, cmd->arg, cmd->flags); - list_del(&cmd->queue); kfree(cmd); } @@ -1678,11 +1679,14 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { - struct pn533_cmd_jump_dep *cmd; struct pn533_cmd_jump_dep_response *resp; struct nfc_target nfc_target; u8 target_gt_len; int rc; + struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg; + u8 active = cmd->active; + + kfree(arg); if (params_len == -ENOENT) { nfc_dev_dbg(&dev->interface->dev, ""); @@ -1704,7 +1708,6 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, } resp = (struct pn533_cmd_jump_dep_response *) params; - cmd = (struct pn533_cmd_jump_dep *) arg; rc = resp->status & PN533_CMD_RET_MASK; if (rc != PN533_CMD_RET_SUCCESS) { nfc_dev_err(&dev->interface->dev, @@ -1734,7 +1737,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, if (rc == 0) rc = nfc_dep_link_is_up(dev->nfc_dev, dev->nfc_dev->targets[0].idx, - !cmd->active, NFC_RF_INITIATOR); + !active, NFC_RF_INITIATOR); return 0; } @@ -1819,12 +1822,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, dev->in_maxlen, pn533_in_dep_link_up_complete, cmd, GFP_KERNEL); - if (rc) - goto out; - - -out: - kfree(cmd); + if (rc < 0) + kfree(cmd); return rc; } @@ -2078,8 +2077,12 @@ error: static int pn533_tm_send_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { + struct sk_buff *skb_out = arg; + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + dev_kfree_skb(skb_out); + if (params_len < 0) { nfc_dev_err(&dev->interface->dev, "Error %d when sending data", @@ -2117,7 +2120,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame, dev->in_maxlen, pn533_tm_send_complete, - NULL, GFP_KERNEL); + skb, GFP_KERNEL); if (rc) { nfc_dev_err(&dev->interface->dev, "Error %d when trying to send data", rc); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d96caefd914a..aeecf0f72cad 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -178,7 +178,7 @@ config PINCTRL_COH901 ports of 8 GPIO pins each. config PINCTRL_SAMSUNG - bool "Samsung pinctrl driver" + bool depends on OF && GPIOLIB select PINMUX select PINCONF diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index c1bafc3f3fb1..9594ab62702b 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1972,7 +1972,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, frame_index, (void **)&frame_buffer); - sci_controller_copy_sata_response(&ireq->stp.req, + sci_controller_copy_sata_response(&ireq->stp.rsp, frame_header, frame_buffer); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2936b447cae9..2c0d0ec8150b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -55,6 +55,7 @@ #include <linux/cpu.h> #include <linux/mutex.h> #include <linux/async.h> +#include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -1062,6 +1063,50 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, EXPORT_SYMBOL_GPL(scsi_get_vpd_page); /** + * scsi_report_opcode - Find out if a given command opcode is supported + * @sdev: scsi device to query + * @buffer: scratch buffer (must be at least 20 bytes long) + * @len: length of buffer + * @opcode: opcode for command to look up + * + * Uses the REPORT SUPPORTED OPERATION CODES to look up the given + * opcode. Returns 0 if RSOC fails or if the command opcode is + * unsupported. Returns 1 if the device claims to support the command. + */ +int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, + unsigned int len, unsigned char opcode) +{ + unsigned char cmd[16]; + struct scsi_sense_hdr sshdr; + int result; + + if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3) + return 0; + + memset(cmd, 0, 16); + cmd[0] = MAINTENANCE_IN; + cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES; + cmd[2] = 1; /* One command format */ + cmd[3] = opcode; + put_unaligned_be32(len, &cmd[6]); + memset(buffer, 0, len); + + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, + &sshdr, 30 * HZ, 3, NULL); + + if (result && scsi_sense_valid(&sshdr) && + sshdr.sense_key == ILLEGAL_REQUEST && + (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00) + return 0; + + if ((buffer[1] & 3) == 3) /* Command supported */ + return 1; + + return 0; +} +EXPORT_SYMBOL(scsi_report_opcode); + +/** * scsi_device_get - get an additional reference to a scsi_device * @sdev: device to get a reference to * diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index da36a3a81a9e..9032e910bca3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -900,11 +900,23 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) action = ACTION_FAIL; error = -EILSEQ; /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (cmd->cmnd[0] == UNMAP || - cmd->cmnd[0] == WRITE_SAME_16 || - cmd->cmnd[0] == WRITE_SAME)) { - description = "Discard failure"; + } else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { + switch (cmd->cmnd[0]) { + case UNMAP: + description = "Discard failure"; + break; + case WRITE_SAME: + case WRITE_SAME_16: + if (cmd->cmnd[1] & 0x8) + description = "Discard failure"; + else + description = + "Write same failure"; + break; + default: + description = "Invalid command failure"; + break; + } action = ACTION_FAIL; error = -EREMOTEIO; } else diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 12f6fdfc1147..352bc77b7c88 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -99,6 +99,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); #endif static void sd_config_discard(struct scsi_disk *, unsigned int); +static void sd_config_write_same(struct scsi_disk *); static int sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); static int sd_probe(struct device *); @@ -395,6 +396,45 @@ sd_store_max_medium_access_timeouts(struct device *dev, return err ? err : count; } +static ssize_t +sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", sdkp->max_ws_blocks); +} + +static ssize_t +sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + unsigned long max; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (sdp->type != TYPE_DISK) + return -EINVAL; + + err = kstrtoul(buf, 10, &max); + + if (err) + return err; + + if (max == 0) + sdp->no_write_same = 1; + else if (max <= SD_MAX_WS16_BLOCKS) + sdkp->max_ws_blocks = max; + + sd_config_write_same(sdkp); + + return count; +} + static struct device_attribute sd_disk_attrs[] = { __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type), @@ -410,6 +450,8 @@ static struct device_attribute sd_disk_attrs[] = { __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL), __ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode, sd_store_provisioning_mode), + __ATTR(max_write_same_blocks, S_IRUGO|S_IWUSR, + sd_show_write_same_blocks, sd_store_write_same_blocks), __ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR, sd_show_max_medium_access_timeouts, sd_store_max_medium_access_timeouts), @@ -561,19 +603,23 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) return; case SD_LBP_UNMAP: - max_blocks = min_not_zero(sdkp->max_unmap_blocks, 0xffffffff); + max_blocks = min_not_zero(sdkp->max_unmap_blocks, + (u32)SD_MAX_WS16_BLOCKS); break; case SD_LBP_WS16: - max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS16_BLOCKS); break; case SD_LBP_WS10: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); break; case SD_LBP_ZERO: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); q->limits.discard_zeroes_data = 1; break; } @@ -583,29 +629,26 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) } /** - * scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device + * sd_setup_discard_cmnd - unmap blocks on thinly provisioned device * @sdp: scsi device to operate one * @rq: Request to prepare * * Will issue either UNMAP or WRITE SAME(16) depending on preference * indicated by target device. **/ -static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) +static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) { struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); - struct bio *bio = rq->bio; - sector_t sector = bio->bi_sector; - unsigned int nr_sectors = bio_sectors(bio); + sector_t sector = blk_rq_pos(rq); + unsigned int nr_sectors = blk_rq_sectors(rq); + unsigned int nr_bytes = blk_rq_bytes(rq); unsigned int len; int ret; char *buf; struct page *page; - if (sdkp->device->sector_size == 4096) { - sector >>= 3; - nr_sectors >>= 3; - } - + sector >>= ilog2(sdp->sector_size) - 9; + nr_sectors >>= ilog2(sdp->sector_size) - 9; rq->timeout = SD_TIMEOUT; memset(rq->cmd, 0, rq->cmd_len); @@ -660,6 +703,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) blk_add_request_payload(rq, page, len); ret = scsi_setup_blk_pc_cmnd(sdp, rq); rq->buffer = page_address(page); + rq->__data_len = nr_bytes; out: if (ret != BLKPREP_OK) { @@ -669,6 +713,83 @@ out: return ret; } +static void sd_config_write_same(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + unsigned int logical_block_size = sdkp->device->sector_size; + unsigned int blocks = 0; + + if (sdkp->device->no_write_same) { + sdkp->max_ws_blocks = 0; + goto out; + } + + /* Some devices can not handle block counts above 0xffff despite + * supporting WRITE SAME(16). Consequently we default to 64k + * blocks per I/O unless the device explicitly advertises a + * bigger limit. + */ + if (sdkp->max_ws_blocks == 0) + sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS; + + if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS) + blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS16_BLOCKS); + else + blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); + +out: + blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9)); +} + +/** + * sd_setup_write_same_cmnd - write the same data to multiple blocks + * @sdp: scsi device to operate one + * @rq: Request to prepare + * + * Will issue either WRITE SAME(10) or WRITE SAME(16) depending on + * preference indicated by target device. + **/ +static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) +{ + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); + struct bio *bio = rq->bio; + sector_t sector = blk_rq_pos(rq); + unsigned int nr_sectors = blk_rq_sectors(rq); + unsigned int nr_bytes = blk_rq_bytes(rq); + int ret; + + if (sdkp->device->no_write_same) + return BLKPREP_KILL; + + BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size); + + sector >>= ilog2(sdp->sector_size) - 9; + nr_sectors >>= ilog2(sdp->sector_size) - 9; + + rq->__data_len = sdp->sector_size; + rq->timeout = SD_WRITE_SAME_TIMEOUT; + memset(rq->cmd, 0, rq->cmd_len); + + if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff) { + rq->cmd_len = 16; + rq->cmd[0] = WRITE_SAME_16; + put_unaligned_be64(sector, &rq->cmd[2]); + put_unaligned_be32(nr_sectors, &rq->cmd[10]); + } else { + rq->cmd_len = 10; + rq->cmd[0] = WRITE_SAME; + put_unaligned_be32(sector, &rq->cmd[2]); + put_unaligned_be16(nr_sectors, &rq->cmd[7]); + } + + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + rq->__data_len = nr_bytes; + + return ret; +} + static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) { rq->timeout = SD_FLUSH_TIMEOUT; @@ -712,7 +833,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * block PC requests to make life easier. */ if (rq->cmd_flags & REQ_DISCARD) { - ret = scsi_setup_discard_cmnd(sdp, rq); + ret = sd_setup_discard_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_flags & REQ_WRITE_SAME) { + ret = sd_setup_write_same_cmnd(sdp, rq); goto out; } else if (rq->cmd_flags & REQ_FLUSH) { ret = scsi_setup_flush_cmnd(sdp, rq); @@ -1482,12 +1606,21 @@ static int sd_done(struct scsi_cmnd *SCpnt) unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); struct scsi_sense_hdr sshdr; struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); + struct request *req = SCpnt->request; int sense_valid = 0; int sense_deferred = 0; unsigned char op = SCpnt->cmnd[0]; + unsigned char unmap = SCpnt->cmnd[1] & 8; - if ((SCpnt->request->cmd_flags & REQ_DISCARD) && !result) - scsi_set_resid(SCpnt, 0); + if (req->cmd_flags & REQ_DISCARD || req->cmd_flags & REQ_WRITE_SAME) { + if (!result) { + good_bytes = blk_rq_bytes(req); + scsi_set_resid(SCpnt, 0); + } else { + good_bytes = 0; + scsi_set_resid(SCpnt, blk_rq_bytes(req)); + } + } if (result) { sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); @@ -1536,9 +1669,25 @@ static int sd_done(struct scsi_cmnd *SCpnt) if (sshdr.asc == 0x10) /* DIX: Host detected corruption */ good_bytes = sd_completed_bytes(SCpnt); /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (op == UNMAP || op == WRITE_SAME_16 || op == WRITE_SAME)) - sd_config_discard(sdkp, SD_LBP_DISABLE); + if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { + switch (op) { + case UNMAP: + sd_config_discard(sdkp, SD_LBP_DISABLE); + break; + case WRITE_SAME_16: + case WRITE_SAME: + if (unmap) + sd_config_discard(sdkp, SD_LBP_DISABLE); + else { + sdkp->device->no_write_same = 1; + sd_config_write_same(sdkp); + + good_bytes = 0; + req->__data_len = blk_rq_bytes(req); + req->cmd_flags |= REQ_QUIET; + } + } + } break; default: break; @@ -2374,9 +2523,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) if (buffer[3] == 0x3c) { unsigned int lba_count, desc_count; - sdkp->max_ws_blocks = - (u32) min_not_zero(get_unaligned_be64(&buffer[36]), - (u64)0xffffffff); + sdkp->max_ws_blocks = (u32)get_unaligned_be64(&buffer[36]); if (!sdkp->lbpme) goto out; @@ -2469,6 +2616,13 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp) kfree(buffer); } +static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) +{ + if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE, + WRITE_SAME_16)) + sdkp->ws16 = 1; +} + static int sd_try_extended_inquiry(struct scsi_device *sdp) { /* @@ -2528,6 +2682,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_write_protect_flag(sdkp, buffer); sd_read_cache_type(sdkp, buffer); sd_read_app_tag_own(sdkp, buffer); + sd_read_write_same(sdkp, buffer); } sdkp->first_scan = 0; @@ -2545,6 +2700,7 @@ static int sd_revalidate_disk(struct gendisk *disk) blk_queue_flush(sdkp->disk->queue, flush); set_capacity(disk, sdkp->capacity); + sd_config_write_same(sdkp); kfree(buffer); out: diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 47c52a6d733c..74a1e4ca5401 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -14,6 +14,7 @@ #define SD_TIMEOUT (30 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) #define SD_FLUSH_TIMEOUT (60 * HZ) +#define SD_WRITE_SAME_TIMEOUT (120 * HZ) /* * Number of allowed retries @@ -39,6 +40,11 @@ enum { }; enum { + SD_MAX_WS10_BLOCKS = 0xffff, + SD_MAX_WS16_BLOCKS = 0x7fffff, +}; + +enum { SD_LBP_FULL = 0, /* Full logical block provisioning */ SD_LBP_UNMAP, /* Use UNMAP command */ SD_LBP_WS16, /* Use WRITE SAME(16) with UNMAP bit */ @@ -77,6 +83,7 @@ struct scsi_disk { unsigned lbpws : 1; unsigned lbpws10 : 1; unsigned lbpvpd : 1; + unsigned ws16 : 1; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index a3d54366afcc..92f35abee92d 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -186,6 +186,12 @@ static int slave_configure(struct scsi_device *sdev) /* Some devices don't handle VPD pages correctly */ sdev->skip_vpd_pages = 1; + /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */ + sdev->no_report_opcodes = 1; + + /* Do not attempt to use WRITE SAME */ + sdev->no_write_same = 1; + /* Some disks return the total number of blocks in response * to READ CAPACITY rather than the highest block number. * If this device makes that mistake, tell the sd driver. */ diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index d64ac3842884..bee92846cfab 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -365,11 +365,20 @@ struct platform_device *dsi_get_dsidev_from_id(int module) struct omap_dss_output *out; enum omap_dss_output_id id; - id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + switch (module) { + case 0: + id = OMAP_DSS_OUTPUT_DSI1; + break; + case 1: + id = OMAP_DSS_OUTPUT_DSI2; + break; + default: + return NULL; + } out = omap_dss_get_output(id); - return out->pdev; + return out ? out->pdev : NULL; } static inline void dsi_write_reg(struct platform_device *dsidev, diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 2ab1c3e96553..5f6eea801b06 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -697,11 +697,15 @@ static int dss_get_clocks(void) dss.dss_clk = clk; - clk = clk_get(NULL, dss.feat->clk_name); - if (IS_ERR(clk)) { - DSSERR("Failed to get %s\n", dss.feat->clk_name); - r = PTR_ERR(clk); - goto err; + if (dss.feat->clk_name) { + clk = clk_get(NULL, dss.feat->clk_name); + if (IS_ERR(clk)) { + DSSERR("Failed to get %s\n", dss.feat->clk_name); + r = PTR_ERR(clk); + goto err; + } + } else { + clk = NULL; } dss.dpll4_m4_ck = clk; @@ -805,10 +809,10 @@ static int __init dss_init_features(struct device *dev) if (cpu_is_omap24xx()) src = &omap24xx_dss_feats; - else if (cpu_is_omap34xx()) - src = &omap34xx_dss_feats; else if (cpu_is_omap3630()) src = &omap3630_dss_feats; + else if (cpu_is_omap34xx()) + src = &omap34xx_dss_feats; else if (cpu_is_omap44xx()) src = &omap44xx_dss_feats; else if (soc_is_omap54xx()) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a48a7dd75b33..8c9b8b3b7f77 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -644,8 +644,10 @@ static void hdmi_dump_regs(struct seq_file *s) { mutex_lock(&hdmi.lock); - if (hdmi_runtime_get()) + if (hdmi_runtime_get()) { + mutex_unlock(&hdmi.lock); return; + } hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 606b89f12351..d630b26a005c 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -787,7 +787,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); - if (!display && !display->output && !display->output->manager) { + if (!display || !display->output || !display->output->manager) { r = -EINVAL; break; } diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 8adb9cc267f9..71f5c459b088 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -361,13 +361,13 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) down_write(&mm->mmap_sem); vma = find_vma(mm, m.addr); - ret = -EINVAL; if (!vma || vma->vm_ops != &privcmd_vm_ops || (m.addr != vma->vm_start) || ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) || !privcmd_enforce_singleshot_mapping(vma)) { up_write(&mm->mmap_sem); + ret = -EINVAL; goto out; } @@ -383,12 +383,16 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) up_write(&mm->mmap_sem); - if (state.global_error && (version == 1)) { - /* Write back errors in second pass. */ - state.user_mfn = (xen_pfn_t *)m.arr; - state.err = err_array; - ret = traverse_pages(m.num, sizeof(xen_pfn_t), - &pagelist, mmap_return_errors_v1, &state); + if (version == 1) { + if (state.global_error) { + /* Write back errors in second pass. */ + state.user_mfn = (xen_pfn_t *)m.arr; + state.err = err_array; + ret = traverse_pages(m.num, sizeof(xen_pfn_t), + &pagelist, mmap_return_errors_v1, &state); + } else + ret = 0; + } else if (version == 2) { ret = __copy_to_user(m.err, err_array, m.num * sizeof(int)); if (ret) diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 7320a66e958f..22548f56197b 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -2101,8 +2101,9 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range) end = start + (range->len >> sb->s_blocksize_bits) - 1; minlen = range->minlen >> sb->s_blocksize_bits; - if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)) || - unlikely(start >= max_blks)) + if (minlen > EXT3_BLOCKS_PER_GROUP(sb) || + start >= max_blks || + range->len < sb->s_blocksize) return -EINVAL; if (end >= max_blks) end = max_blks - 1; diff --git a/fs/file.c b/fs/file.c index 708d997a7748..7cb71b992603 100644 --- a/fs/file.c +++ b/fs/file.c @@ -685,7 +685,6 @@ void do_close_on_exec(struct files_struct *files) struct fdtable *fdt; /* exec unshares first */ - BUG_ON(atomic_read(&files->count) != 1); spin_lock(&files->file_lock); for (i = 0; ; i++) { unsigned long set; diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 60ef3fb707ff..1506673c087e 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -138,33 +138,39 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct page *pg; struct inode *inode = mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_raw_inode ri; + uint32_t alloc_len = 0; pgoff_t index = pos >> PAGE_CACHE_SHIFT; uint32_t pageofs = index << PAGE_CACHE_SHIFT; int ret = 0; + jffs2_dbg(1, "%s()\n", __func__); + + if (pageofs > inode->i_size) { + ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) + return ret; + } + + mutex_lock(&f->sem); pg = grab_cache_page_write_begin(mapping, index, flags); - if (!pg) + if (!pg) { + if (alloc_len) + jffs2_complete_reservation(c); + mutex_unlock(&f->sem); return -ENOMEM; + } *pagep = pg; - jffs2_dbg(1, "%s()\n", __func__); - - if (pageofs > inode->i_size) { + if (alloc_len) { /* Make new hole frag from old EOF to new page */ - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; - uint32_t alloc_len; jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs); - ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) - goto out_page; - - mutex_lock(&f->sem); memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -191,7 +197,6 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, if (IS_ERR(fn)) { ret = PTR_ERR(fn); jffs2_complete_reservation(c); - mutex_unlock(&f->sem); goto out_page; } ret = jffs2_add_full_dnode_to_inode(c, f, fn); @@ -206,12 +211,10 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); jffs2_complete_reservation(c); - mutex_unlock(&f->sem); goto out_page; } jffs2_complete_reservation(c); inode->i_size = pageofs; - mutex_unlock(&f->sem); } /* @@ -220,18 +223,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, * case of a short-copy. */ if (!PageUptodate(pg)) { - mutex_lock(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); - mutex_unlock(&f->sem); if (ret) goto out_page; } + mutex_unlock(&f->sem); jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); return ret; out_page: unlock_page(pg); page_cache_release(pg); + mutex_unlock(&f->sem); return ret; } diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 721d692fa8d4..6fcaeb8c902e 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -258,7 +258,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, if (ret) goto out_close_fd; - fd_install(fd, f); + if (fd != FAN_NOFD) + fd_install(fd, f); return fanotify_event_metadata.event_len; out_close_fd: diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index f27f01a98aa2..d83736fbc26c 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1782,8 +1782,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); - dquot_initialize(inode); + reiserfs_write_unlock(inode->i_sb); err = dquot_alloc_inode(inode); + reiserfs_write_lock(inode->i_sb); if (err) goto out_end_trans; if (!dir->i_nlink) { @@ -1979,8 +1980,10 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, out_end_trans: journal_end(th, th->t_super, th->t_blocks_allocated); + reiserfs_write_unlock(inode->i_sb); /* Drop can be outside and it needs more credits so it's better to have it outside */ dquot_drop(inode); + reiserfs_write_lock(inode->i_sb); inode->i_flags |= S_NOQUOTA; make_bad_inode(inode); @@ -3103,10 +3106,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) /* must be turned off for recursive notify_change calls */ ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); - depth = reiserfs_write_lock_once(inode->i_sb); if (is_quota_modification(inode, attr)) dquot_initialize(inode); - + depth = reiserfs_write_lock_once(inode->i_sb); if (attr->ia_valid & ATTR_SIZE) { /* version 2 items will be caught by the s_maxbytes check ** done for us in vmtruncate @@ -3170,7 +3172,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) error = journal_begin(&th, inode->i_sb, jbegin_count); if (error) goto out; + reiserfs_write_unlock_once(inode->i_sb, depth); error = dquot_transfer(inode, attr); + depth = reiserfs_write_lock_once(inode->i_sb); if (error) { journal_end(&th, inode->i_sb, jbegin_count); goto out; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index f8afa4b162b8..2f40a4c70a4d 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -1968,7 +1968,9 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree key2type(&(key->on_disk_key))); #endif + reiserfs_write_unlock(inode->i_sb); retval = dquot_alloc_space_nodirty(inode, pasted_size); + reiserfs_write_lock(inode->i_sb); if (retval) { pathrelse(search_path); return retval; @@ -2061,9 +2063,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, "reiserquota insert_item(): allocating %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(ih)); #endif + reiserfs_write_unlock(inode->i_sb); /* We can't dirty inode here. It would be immediately written but * appropriate stat item isn't inserted yet... */ retval = dquot_alloc_space_nodirty(inode, quota_bytes); + reiserfs_write_lock(inode->i_sb); if (retval) { pathrelse(path); return retval; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 1078ae179993..418bdc3a57da 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -298,7 +298,9 @@ static int finish_unfinished(struct super_block *s) retval = remove_save_link_only(s, &save_link_key, 0); continue; } + reiserfs_write_unlock(s); dquot_initialize(inode); + reiserfs_write_lock(s); if (truncate && S_ISDIR(inode->i_mode)) { /* We got a truncate request for a dir which is impossible. @@ -1335,7 +1337,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) kfree(qf_names[i]); #endif err = -EINVAL; - goto out_err; + goto out_unlock; } #ifdef CONFIG_QUOTA handle_quota_files(s, qf_names, &qfmt); @@ -1379,7 +1381,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) if (blocks) { err = reiserfs_resize(s, blocks); if (err != 0) - goto out_err; + goto out_unlock; } if (*mount_flags & MS_RDONLY) { @@ -1389,9 +1391,15 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) /* it is read-only already */ goto out_ok; + /* + * Drop write lock. Quota will retake it when needed and lock + * ordering requires calling dquot_suspend() without it. + */ + reiserfs_write_unlock(s); err = dquot_suspend(s, -1); if (err < 0) goto out_err; + reiserfs_write_lock(s); /* try to remount file system with read-only permissions */ if (sb_umount_state(rs) == REISERFS_VALID_FS @@ -1401,7 +1409,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) err = journal_begin(&th, s, 10); if (err) - goto out_err; + goto out_unlock; /* Mounting a rw partition read-only. */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); @@ -1416,7 +1424,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) if (reiserfs_is_journal_aborted(journal)) { err = journal->j_errno; - goto out_err; + goto out_unlock; } handle_data_mode(s, mount_options); @@ -1425,7 +1433,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) s->s_flags &= ~MS_RDONLY; /* now it is safe to call journal_begin */ err = journal_begin(&th, s, 10); if (err) - goto out_err; + goto out_unlock; /* Mount a partition which is read-only, read-write */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); @@ -1442,10 +1450,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) SB_JOURNAL(s)->j_must_wait = 1; err = journal_end(&th, s, 10); if (err) - goto out_err; + goto out_unlock; if (!(*mount_flags & MS_RDONLY)) { + /* + * Drop write lock. Quota will retake it when needed and lock + * ordering requires calling dquot_resume() without it. + */ + reiserfs_write_unlock(s); dquot_resume(s, -1); + reiserfs_write_lock(s); finish_unfinished(s); reiserfs_xattr_init(s, *mount_flags); } @@ -1455,9 +1469,10 @@ out_ok: reiserfs_write_unlock(s); return 0; +out_unlock: + reiserfs_write_unlock(s); out_err: kfree(new_opts); - reiserfs_write_unlock(s); return err; } @@ -2095,13 +2110,15 @@ static int reiserfs_write_dquot(struct dquot *dquot) REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); if (ret) goto out; + reiserfs_write_unlock(dquot->dq_sb); ret = dquot_commit(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(dquot->dq_sb); return ret; } @@ -2117,13 +2134,15 @@ static int reiserfs_acquire_dquot(struct dquot *dquot) REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); if (ret) goto out; + reiserfs_write_unlock(dquot->dq_sb); ret = dquot_acquire(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(dquot->dq_sb); return ret; } @@ -2137,19 +2156,21 @@ static int reiserfs_release_dquot(struct dquot *dquot) ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); + reiserfs_write_unlock(dquot->dq_sb); if (ret) { /* Release dquot anyway to avoid endless cycle in dqput() */ dquot_release(dquot); goto out; } ret = dquot_release(dquot); + reiserfs_write_lock(dquot->dq_sb); err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); if (!ret && err) ret = err; - out: reiserfs_write_unlock(dquot->dq_sb); +out: return ret; } @@ -2174,11 +2195,13 @@ static int reiserfs_write_info(struct super_block *sb, int type) ret = journal_begin(&th, sb, 2); if (ret) goto out; + reiserfs_write_unlock(sb); ret = dquot_commit_info(sb, type); + reiserfs_write_lock(sb); err = journal_end(&th, sb, 2); if (!ret && err) ret = err; - out: +out: reiserfs_write_unlock(sb); return ret; } @@ -2203,8 +2226,11 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, struct reiserfs_transaction_handle th; int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA; - if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) - return -EINVAL; + reiserfs_write_lock(sb); + if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) { + err = -EINVAL; + goto out; + } /* Quotafile not on the same filesystem? */ if (path->dentry->d_sb != sb) { @@ -2246,8 +2272,10 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, if (err) goto out; } - err = dquot_quota_on(sb, type, format_id, path); + reiserfs_write_unlock(sb); + return dquot_quota_on(sb, type, format_id, path); out: + reiserfs_write_unlock(sb); return err; } @@ -2320,7 +2348,9 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; tmp_bh.b_state = 0; + reiserfs_write_lock(sb); err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE); + reiserfs_write_unlock(sb); if (err) goto out; if (offset || tocopy != sb->s_blocksize) @@ -2336,10 +2366,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, flush_dcache_page(bh->b_page); set_buffer_uptodate(bh); unlock_buffer(bh); + reiserfs_write_lock(sb); reiserfs_prepare_for_journal(sb, bh, 1); journal_mark_dirty(current->journal_info, sb, bh); if (!journal_quota) reiserfs_add_ordered_list(inode, bh); + reiserfs_write_unlock(sb); brelse(bh); offset = 0; towrite -= tocopy; diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index e562dd43f41f..e57e2daa357c 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -481,11 +481,17 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh) * * The fix is two passes across the ioend list - one to start writeback on the * buffer_heads, and then submit them for I/O on the second pass. + * + * If @fail is non-zero, it means that we have a situation where some part of + * the submission process has failed after we have marked paged for writeback + * and unlocked them. In this situation, we need to fail the ioend chain rather + * than submit it to IO. This typically only happens on a filesystem shutdown. */ STATIC void xfs_submit_ioend( struct writeback_control *wbc, - xfs_ioend_t *ioend) + xfs_ioend_t *ioend, + int fail) { xfs_ioend_t *head = ioend; xfs_ioend_t *next; @@ -506,6 +512,18 @@ xfs_submit_ioend( next = ioend->io_list; bio = NULL; + /* + * If we are failing the IO now, just mark the ioend with an + * error and finish it. This will run IO completion immediately + * as there is only one reference to the ioend at this point in + * time. + */ + if (fail) { + ioend->io_error = -fail; + xfs_finish_ioend(ioend); + continue; + } + for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { if (!bio) { @@ -1060,7 +1078,18 @@ xfs_vm_writepage( xfs_start_page_writeback(page, 1, count); - if (ioend && imap_valid) { + /* if there is no IO to be submitted for this page, we are done */ + if (!ioend) + return 0; + + ASSERT(iohead); + + /* + * Any errors from this point onwards need tobe reported through the IO + * completion path as we have marked the initial page as under writeback + * and unlocked it. + */ + if (imap_valid) { xfs_off_t end_index; end_index = imap.br_startoff + imap.br_blockcount; @@ -1079,20 +1108,15 @@ xfs_vm_writepage( wbc, end_index); } - if (iohead) { - /* - * Reserve log space if we might write beyond the on-disk - * inode size. - */ - if (ioend->io_type != XFS_IO_UNWRITTEN && - xfs_ioend_is_append(ioend)) { - err = xfs_setfilesize_trans_alloc(ioend); - if (err) - goto error; - } - xfs_submit_ioend(wbc, iohead); - } + /* + * Reserve log space if we might write beyond the on-disk inode size. + */ + err = 0; + if (ioend->io_type != XFS_IO_UNWRITTEN && xfs_ioend_is_append(ioend)) + err = xfs_setfilesize_trans_alloc(ioend); + + xfs_submit_ioend(wbc, iohead, err); return 0; diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index d330111ca738..70eec1829776 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -1291,6 +1291,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, leaf2 = blk2->bp->b_addr; ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); + ASSERT(leaf2->hdr.count == 0); args = state->args; trace_xfs_attr_leaf_rebalance(args); @@ -1361,6 +1362,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, * I assert that since all callers pass in an empty * second buffer, this code should never execute. */ + ASSERT(0); /* * Figure the total bytes to be added to the destination leaf. @@ -1422,10 +1424,24 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, args->index2 = 0; args->blkno2 = blk2->blkno; } else { + /* + * On a double leaf split, the original attr location + * is already stored in blkno2/index2, so don't + * overwrite it overwise we corrupt the tree. + */ blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); - args->index = args->index2 = blk2->index; - args->blkno = args->blkno2 = blk2->blkno; + args->index = blk2->index; + args->blkno = blk2->blkno; + if (!state->extravalid) { + /* + * set the new attr location to match the old + * one and let the higher level split code + * decide where in the leaf to place it. + */ + args->index2 = blk2->index; + args->blkno2 = blk2->blkno; + } } } else { ASSERT(state->inleaf == 1); diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 933b7930b863..4b0b8dd1b7b0 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1197,9 +1197,14 @@ xfs_buf_bio_end_io( { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; - xfs_buf_ioerror(bp, -error); + /* + * don't overwrite existing errors - otherwise we can lose errors on + * buffers that require multiple bios to complete. + */ + if (!bp->b_error) + xfs_buf_ioerror(bp, -error); - if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) + if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); _xfs_buf_ioend(bp, 1); @@ -1279,6 +1284,11 @@ next_chunk: if (size) goto next_chunk; } else { + /* + * This is guaranteed not to be the last io reference count + * because the caller (xfs_buf_iorequest) holds a count itself. + */ + atomic_dec(&bp->b_io_remaining); xfs_buf_ioerror(bp, EIO); bio_put(bio); } diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index af1cbaf535ed..c5c35e629426 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -210,6 +210,7 @@ {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h index 4eb31752e2b7..deb0ae58b99b 100644 --- a/include/linux/atmel-ssc.h +++ b/include/linux/atmel-ssc.h @@ -5,10 +5,16 @@ #include <linux/list.h> #include <linux/io.h> +struct atmel_ssc_platform_data { + int use_dma; +}; + struct ssc_device { struct list_head list; + resource_size_t phybase; void __iomem *regs; struct platform_device *pdev; + struct atmel_ssc_platform_data *pdata; struct clk *clk; int user; int irq; diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index df804ba73e0b..92a0dc75bc74 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -34,6 +34,7 @@ struct omap_i2c_bus_platform_data { u32 clkrate; u32 rev; u32 flags; + void (*set_mpu_wkup_lat)(struct device *dev, long set); }; #endif diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index dd231ac0bb1f..a580363a7d29 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h @@ -78,6 +78,8 @@ enum arizona_type { #define ARIZONA_NUM_IRQ 50 +struct snd_soc_dapm_context; + struct arizona { struct regmap *regmap; struct device *dev; @@ -98,6 +100,8 @@ struct arizona { struct mutex clk_lock; int clk32k_ref; + + struct snd_soc_dapm_context *dapm; }; int arizona_clk32k_enable(struct arizona *arizona); diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index 7ab442905a57..8b1d1daaae16 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h @@ -62,6 +62,9 @@ #define ARIZONA_MAX_OUTPUT 6 +#define ARIZONA_HAP_ACT_ERM 0 +#define ARIZONA_HAP_ACT_LRA 2 + #define ARIZONA_MAX_PDM_SPK 2 struct regulator_init_data; @@ -114,6 +117,9 @@ struct arizona_pdata { /** PDM speaker format */ unsigned int spk_fmt[ARIZONA_MAX_PDM_SPK]; + + /** Haptic actuator type */ + unsigned int hap_act; }; #endif diff --git a/include/linux/of_address.h b/include/linux/of_address.h index e20e3af68fb6..0506eb53519b 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -42,10 +42,12 @@ static inline struct device_node *of_find_matching_node_by_address( { return NULL; } +#ifndef of_iomap static inline void __iomem *of_iomap(struct device_node *device, int index) { return NULL; } +#endif static inline const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h index aa9875f77c40..88272591a895 100644 --- a/include/linux/platform_data/asoc-s3c.h +++ b/include/linux/platform_data/asoc-s3c.h @@ -38,12 +38,6 @@ struct samsung_i2s { #define QUIRK_NEED_RSTCLR (1 << 3) /* Quirks of the I2S controller */ u32 quirks; - - /* - * Array of clock names that can be used to generate I2S signals. - * Also corresponds to clocks of I2SMOD[10] - */ - const char **src_clk; dma_addr_t idma_addr; }; diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index d0c5825876f8..8db5ae03b6e3 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -16,12 +16,13 @@ #ifndef __DAVINCI_ASP_H #define __DAVINCI_ASP_H +#include <linux/genalloc.h> + struct snd_platform_data { u32 tx_dma_offset; u32 rx_dma_offset; int asp_chan_q; /* event queue number for ASP channel */ int ram_chan_q; /* event queue number for RAM channel */ - unsigned int codec_fmt; /* * Allowing this is more efficient and eliminates left and right swaps * caused by underruns, but will swap the left and right channels @@ -30,6 +31,7 @@ struct snd_platform_data { unsigned enable_channel_combine:1; unsigned sram_size_playback; unsigned sram_size_capture; + struct gen_pool *sram_pool; /* * If McBSP peripheral gets the clock from an external pin, diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h index c7bef788daab..ee60ef79d792 100644 --- a/include/linux/platform_data/omap-twl4030.h +++ b/include/linux/platform_data/omap-twl4030.h @@ -25,8 +25,34 @@ #ifndef _OMAP_TWL4030_H_ #define _OMAP_TWL4030_H_ +/* To select if only one channel is connected in a stereo port */ +#define OMAP_TWL4030_LEFT (1 << 0) +#define OMAP_TWL4030_RIGHT (1 << 1) + struct omap_tw4030_pdata { const char *card_name; + /* Voice port is connected to McBSP3 */ + bool voice_connected; + + /* The driver will parse the connection flags if this flag is set */ + bool custom_routing; + /* Flags to indicate connected audio ports. */ + u8 has_hs; + u8 has_hf; + u8 has_predriv; + u8 has_carkit; + bool has_ear; + + bool has_mainmic; + bool has_submic; + bool has_hsmic; + bool has_carkitmic; + bool has_digimic0; + bool has_digimic1; + u8 has_linein; + + /* Jack detect GPIO or <= 0 if it is not implemented */ + int jack_detect; }; #endif /* _OMAP_TWL4030_H_ */ diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e3bcc3f4dcb8..9f228d7f7ac4 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -133,7 +133,7 @@ struct regmap_config { enum regmap_endian val_format_endian; const struct regmap_range_cfg *ranges; - unsigned int n_ranges; + unsigned int num_ranges; }; /** @@ -142,6 +142,8 @@ struct regmap_config { * 1. page selector register update; * 2. access through data window registers. * + * @name: Descriptive name for diagnostics + * * @range_min: Address of the lowest register address in virtual range. * @range_max: Address of the highest register in virtual range. * @@ -153,6 +155,8 @@ struct regmap_config { * @window_len: Number of registers in data window. */ struct regmap_range_cfg { + const char *name; + /* Registers of virtual address range */ unsigned int range_min; unsigned int range_max; diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index c64de9dd7631..2f694f3846a9 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h @@ -46,8 +46,9 @@ struct ads7846_platform_data { u16 debounce_rep; /* additional consecutive good readings * required after the first two */ int gpio_pendown; /* the GPIO used to decide the pendown - * state if get_pendown_state == NULL - */ + * state if get_pendown_state == NULL */ + int gpio_pendown_debounce; /* platform specific debounce time for + * the gpio_pendown */ int (*get_pendown_state)(void); int (*filter_init) (const struct ads7846_platform_data *pdata, void **filter_data); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 6f0ba01afe73..63445ede48bb 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1351,7 +1351,7 @@ struct xfrm6_tunnel { }; extern void xfrm_init(void); -extern void xfrm4_init(int rt_hash_size); +extern void xfrm4_init(void); extern int xfrm_state_init(struct net *net); extern void xfrm_state_fini(struct net *net); extern void xfrm4_state_init(void); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 88fae8d20154..55367b04dc94 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -135,6 +135,8 @@ struct scsi_device { * because we did a bus reset. */ unsigned use_10_for_rw:1; /* first try 10-byte read / write */ unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ + unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ + unsigned no_write_same:1; /* no WRITE SAME command */ unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ unsigned skip_vpd_pages:1; /* do not read VPD pages */ @@ -362,6 +364,8 @@ extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, struct scsi_sense_hdr *sshdr); extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, int buf_len); +extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, + unsigned int len, unsigned char opcode); extern int scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state); extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, diff --git a/include/sound/cs4271.h b/include/sound/cs4271.h index 50a059e7d116..6d9e15ed1dcf 100644 --- a/include/sound/cs4271.h +++ b/include/sound/cs4271.h @@ -19,6 +19,7 @@ struct cs4271_platform_data { int gpio_nreset; /* GPIO driving Reset pin, if any */ + int amutec_eq_bmutec:1; /* flag to enable AMUTEC=BMUTEC */ }; #endif /* __CS4271_H */ diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 906010344dd7..cc1c919c6436 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -26,6 +26,7 @@ * A: inversion * B: format mode * C: chip specific + * D: clock selecter if master mode */ /* A: clock inversion */ @@ -44,6 +45,11 @@ #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 * diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h index c009f70b4029..24e5d991f148 100644 --- a/include/sound/tlv320aic32x4.h +++ b/include/sound/tlv320aic32x4.h @@ -26,6 +26,7 @@ struct aic32x4_pdata { u32 power_cfg; u32 micpga_routing; bool swapdacs; + int rstn_gpio; }; #endif diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index 678ce4f1e124..095ab157a521 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -641,7 +641,14 @@ do { \ ************** MIPS ***************** ***************************************/ #if defined(__mips__) && W_TYPE_SIZE == 32 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + UDItype __ll = (UDItype)(u) * (v); \ + w1 = __ll >> 32; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("multu %2,%3" \ : "=l" ((USItype)(w0)), \ @@ -666,7 +673,15 @@ do { \ ************** MIPS/64 ************** ***************************************/ #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + typedef unsigned int __ll_UTItype __attribute__((mode(TI))); \ + __ll_UTItype __ll = (__ll_UTItype)(u) * (v); \ + w1 = __ll >> 64; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("dmultu %2,%3" \ : "=l" ((UDItype)(w0)), \ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 7bb35ac0964a..bcb72c6e2b2d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1405,7 +1405,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype) mt = get_pageblock_migratetype(page); if (unlikely(mt != MIGRATE_ISOLATE)) - __mod_zone_freepage_state(zone, -(1UL << order), mt); + __mod_zone_freepage_state(zone, -(1UL << alloc_order), mt); if (alloc_order != order) expand(zone, page, alloc_order, order, diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index bcf02f608cbf..017a8bacfb27 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -429,6 +429,17 @@ static struct attribute_group netstat_group = { .name = "statistics", .attrs = netstat_attrs, }; + +#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) +static struct attribute *wireless_attrs[] = { + NULL +}; + +static struct attribute_group wireless_group = { + .name = "wireless", + .attrs = wireless_attrs, +}; +#endif #endif /* CONFIG_SYSFS */ #ifdef CONFIG_RPS @@ -1409,6 +1420,15 @@ int netdev_register_kobject(struct net_device *net) groups++; *groups++ = &netstat_group; + +#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) + if (net->ieee80211_ptr) + *groups++ = &wireless_group; +#if IS_ENABLED(CONFIG_WIRELESS_EXT) + else if (net->wireless_handlers) + *groups++ = &wireless_group; +#endif +#endif #endif /* CONFIG_SYSFS */ error = device_add(dev); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a8c651216fa6..df251424d816 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1785,6 +1785,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; + do_cache = true; if (type == RTN_BROADCAST) { flags |= RTCF_BROADCAST | RTCF_LOCAL; fi = NULL; @@ -1793,6 +1794,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr, fl4->flowi4_proto)) flags &= ~RTCF_LOCAL; + else + do_cache = false; /* If multicast route do not exist use * default one, but do not gateway in this case. * Yes, it is hack. @@ -1802,8 +1805,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, } fnhe = NULL; - do_cache = fi != NULL; - if (fi) { + do_cache &= fi != NULL; + if (do_cache) { struct rtable __rcu **prth; struct fib_nh *nh = &FIB_RES_NH(*res); @@ -2597,7 +2600,7 @@ int __init ip_rt_init(void) pr_err("Unable to create route proc files\n"); #ifdef CONFIG_XFRM xfrm_init(); - xfrm4_init(ip_rt_max_size); + xfrm4_init(); #endif rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL, NULL); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 05c5ab8d983c..3be0ac2c1920 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -279,19 +279,8 @@ static void __exit xfrm4_policy_fini(void) xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); } -void __init xfrm4_init(int rt_max_size) +void __init xfrm4_init(void) { - /* - * Select a default value for the gc_thresh based on the main route - * table hash size. It seems to me the worst case scenario is when - * we have ipsec operating in transport mode, in which we create a - * dst_entry per socket. The xfrm gc algorithm starts trying to remove - * entries at gc_thresh, and prevents new allocations as 2*gc_thresh - * so lets set an initial xfrm gc_thresh value at the rt_max_size/2. - * That will let us store an ipsec connection per route table entry, - * and start cleaning when were 1/2 full - */ - xfrm4_dst_ops.gc_thresh = rt_max_size/2; dst_entries_init(&xfrm4_dst_ops); xfrm4_state_init(); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index c4f934176cab..30647857a375 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -252,6 +252,7 @@ struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu) return NULL; dst->ops->update_pmtu(dst, sk, NULL, mtu); - return inet6_csk_route_socket(sk, &fl6); + dst = inet6_csk_route_socket(sk, &fl6); + return IS_ERR(dst) ? NULL : dst; } EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index bf87c70ac6c5..c21e33d1abd0 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1151,10 +1151,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->u.ibss.mtx); - sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; - memset(sdata->u.ibss.bssid, 0, ETH_ALEN); - sdata->u.ibss.ssid_len = 0; - active_ibss = ieee80211_sta_active_ibss(sdata); if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { @@ -1175,6 +1171,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) } } + ifibss->state = IEEE80211_IBSS_MLME_SEARCH; + memset(ifibss->bssid, 0, ETH_ALEN); + ifibss->ssid_len = 0; + sta_info_flush(sdata->local, sdata); spin_lock_bh(&ifibss->incomplete_lock); diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index ec3dba5dcd62..5c0b78528e55 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c @@ -173,6 +173,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], return adtfn(set, &nip, timeout, flags); } + ip_to = ip; if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -185,8 +186,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 0171f7502fa5..6283351f4eeb 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -162,7 +162,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipport4_elem data = { }; - u32 ip, ip_to = 0, p = 0, port, port_to; + u32 ip, ip_to, p = 0, port, port_to; u32 timeout = h->timeout; bool with_ports = false; int ret; @@ -210,7 +210,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } - ip = ntohl(data.ip); + ip_to = ip = ntohl(data.ip); if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -223,8 +223,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } port_to = port = ntohs(data.port); if (with_ports && tb[IPSET_ATTR_PORT_TO]) { diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 6344ef551ec8..6a21271c8d5a 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -166,7 +166,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportip4_elem data = { }; - u32 ip, ip_to = 0, p = 0, port, port_to; + u32 ip, ip_to, p = 0, port, port_to; u32 timeout = h->timeout; bool with_ports = false; int ret; @@ -218,7 +218,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } - ip = ntohl(data.ip); + ip_to = ip = ntohl(data.ip); if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -231,8 +231,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } port_to = port = ntohs(data.port); if (with_ports && tb[IPSET_ATTR_PORT_TO]) { diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index cb71f9a774e7..2d5cd4ee30eb 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -215,8 +215,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 }; - u32 ip, ip_to = 0, p = 0, port, port_to; - u32 ip2_from = 0, ip2_to, ip2_last, ip2; + u32 ip, ip_to, p = 0, port, port_to; + u32 ip2_from, ip2_to, ip2_last, ip2; u32 timeout = h->timeout; bool with_ports = false; u8 cidr; @@ -286,6 +286,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } + ip_to = ip; if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -306,6 +307,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], if (port > port_to) swap(port, port_to); } + + ip2_to = ip2_from; if (tb[IPSET_ATTR_IP2_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); if (ret) diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 8847b4d8be06..701c88a20fea 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -41,7 +41,8 @@ MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tu static LIST_HEAD(cttimeout_list); static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { - [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING }, + [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING, + .len = CTNL_TIMEOUT_NAME_MAX - 1}, [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index cc10d073c338..9e8f4b2801f6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -1210,7 +1210,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) local->remote_miu = LLCP_DEFAULT_MIU; local->remote_lto = LLCP_DEFAULT_LTO; - list_add(&llcp_devices, &local->list); + list_add(&local->list, &llcp_devices); return 0; } diff --git a/scripts/sign-file b/scripts/sign-file index 87ca59d36e7e..974a20b661b7 100755 --- a/scripts/sign-file +++ b/scripts/sign-file @@ -156,12 +156,12 @@ sub asn1_extract($$@) if ($l == 0x1) { $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); - } elsif ($l = 0x2) { + } elsif ($l == 0x2) { $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); - } elsif ($l = 0x3) { + } elsif ($l == 0x3) { $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); - } elsif ($l = 0x4) { + } elsif ($l == 0x4) { $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); } else { die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 28f911cdd7c7..c5454c0477c3 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -174,7 +174,8 @@ static void sel_netnode_insert(struct sel_netnode *node) if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) { struct sel_netnode *tail; tail = list_entry( - rcu_dereference(sel_netnode_hash[idx].list.prev), + rcu_dereference_protected(sel_netnode_hash[idx].list.prev, + lockdep_is_held(&sel_netnode_lock)), struct sel_netnode, list); list_del_rcu(&tail->list); kfree_rcu(tail, rcu); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70d4848b5cd0..d010de12335e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -95,6 +95,7 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_PM +#define codec_in_pm(codec) ((codec)->in_pm) static void hda_power_work(struct work_struct *work); static void hda_keep_power_on(struct hda_codec *codec); #define hda_codec_is_power_on(codec) ((codec)->power_on) @@ -104,6 +105,7 @@ static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) bus->ops.pm_notify(bus, power_up); } #else +#define codec_in_pm(codec) 0 static inline void hda_keep_power_on(struct hda_codec *codec) {} #define hda_codec_is_power_on(codec) 1 #define hda_call_pm_notify(bus, state) {} @@ -228,7 +230,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, } mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); - if (res && *res == -1 && bus->rirb_error) { + if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) { if (bus->response_reset) { snd_printd("hda_codec: resetting BUS due to " "fatal communication error\n"); @@ -238,7 +240,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, goto again; } /* clear reset-flag when the communication gets recovered */ - if (!err) + if (!err || codec_in_pm(codec)) bus->response_reset = 0; return err; } @@ -3616,6 +3618,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) { unsigned int state; + codec->in_pm = 1; + if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec); hda_cleanup_all_streams(codec); @@ -3630,6 +3634,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) codec->power_transition = 0; codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); + codec->in_pm = 0; return state; } @@ -3638,6 +3643,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) */ static void hda_call_codec_resume(struct hda_codec *codec) { + codec->in_pm = 1; + /* set as if powered on for avoiding re-entering the resume * in the resume / power-save sequence */ @@ -3656,6 +3663,8 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); } snd_hda_jack_report_sync(codec); + + codec->in_pm = 0; snd_hda_power_down(codec); /* flag down before returning */ } #endif /* CONFIG_PM */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 507fe8a917b6..4f4e545c0f4b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -869,6 +869,7 @@ struct hda_codec { unsigned int power_on :1; /* current (global) power-state */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int pm_down_notified:1; /* PM notified to controller */ + unsigned int in_pm:1; /* suspend/resume being performed */ int power_transition; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cd2dbaf1be78..f9d870e554d9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -556,6 +556,12 @@ enum { #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ +#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ + +/* quirks for Intel PCH */ +#define AZX_DCAPS_INTEL_PCH \ + (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ + AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -2433,6 +2439,9 @@ static void azx_power_notify(struct hda_bus *bus, bool power_up) { struct azx *chip = bus->private_data; + if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return; + if (power_up) pm_runtime_get_sync(&chip->pci->dev); else @@ -2548,7 +2557,8 @@ static int azx_runtime_suspend(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; - if (!power_save_controller) + if (!power_save_controller || + !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) return -EAGAIN; azx_stop_chip(chip); @@ -3429,39 +3439,30 @@ static void __devexit azx_remove(struct pci_dev *pci) static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0c0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, { PCI_DEVICE(0x8086, 0x0d0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, /* 5 Series/3400 */ { PCI_DEVICE(0x8086, 0x3b56), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d5f3a26d608d..3bcb67172358 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -466,6 +466,7 @@ static int parse_output(struct hda_codec *codec) memcpy(cfg->speaker_pins, cfg->line_out_pins, sizeof(cfg->speaker_pins)); cfg->line_outs = 0; + memset(cfg->line_out_pins, 0, sizeof(cfg->line_out_pins)); } return 0; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 68fd49294b26..ad68d223f8af 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7065,6 +7065,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, + { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 72b09cfd3dc3..d1b691bf8e2d 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -6,6 +6,14 @@ config SND_ATMEL_SOC the ATMEL SSC interface. You will also need to select the audio interfaces to support below. +config SND_ATMEL_SOC_PDC + tristate + depends on SND_ATMEL_SOC + +config SND_ATMEL_SOC_DMA + tristate + depends on SND_ATMEL_SOC + config SND_ATMEL_SOC_SSC tristate depends on SND_ATMEL_SOC @@ -16,8 +24,8 @@ config SND_ATMEL_SOC_SSC config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \ - AT91_PROGRAMMABLE_CLOCKS + depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS + select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC select SND_SOC_WM8731 help @@ -27,6 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 config SND_AT91_SOC_AFEB9260 tristate "SoC Audio support for AFEB9260 board" depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC + select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC select SND_SOC_TLV320AIC23 help diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index a5c0bf19da78..41967ccb6f41 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -1,8 +1,12 @@ # AT91 Platform Support snd-soc-atmel-pcm-objs := atmel-pcm.o +snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o +snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o +obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o +obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o # AT91 Machine Support diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c new file mode 100644 index 000000000000..30184a4a147a --- /dev/null +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -0,0 +1,240 @@ +/* + * atmel-pcm-dma.c -- ALSA PCM DMA support for the Atmel SoC. + * + * Copyright (C) 2012 Atmel + * + * Author: Bo Shen <voice.shen@atmel.com> + * + * Based on atmel-pcm by: + * Sedji Gaouaou <sedji.gaouaou@atmel.com> + * Copyright 2008 Atmel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/atmel-ssc.h> +#include <linux/platform_data/dma-atmel.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/dmaengine_pcm.h> + +#include "atmel-pcm.h" + +/*--------------------------------------------------------------------------*\ + * Hardware definition +\*--------------------------------------------------------------------------*/ +static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 256, /* lighting DMA overhead */ + .period_bytes_max = 2 * 0xffff, /* if 2 bytes format */ + .periods_min = 8, + .periods_max = 1024, /* no limit */ + .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, +}; + +/** + * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC + * + * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to + * check if any overrun occured. + */ +static void atmel_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct atmel_pcm_dma_params *prtd; + + prtd = snd_dmaengine_pcm_get_data(substream); + + if (ssc_sr & prtd->mask->ssc_error) { + if (snd_pcm_running(substream)) + pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", prtd->name, + ssc_sr); + + /* stop RX and capture: will be enabled again at restart */ + ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + + /* now drain RHR and read status to remove xrun condition */ + ssc_readx(prtd->ssc->regs, SSC_RHR); + ssc_readx(prtd->ssc->regs, SSC_SR); + } +} + +/*--------------------------------------------------------------------------*\ + * DMAENGINE operations +\*--------------------------------------------------------------------------*/ +static bool filter(struct dma_chan *chan, void *slave) +{ + struct at_dma_slave *sl = slave; + + if (sl->dma_dev == chan->device->dev) { + chan->private = sl; + return true; + } else { + return false; + } +} + +static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct atmel_pcm_dma_params *prtd; + struct ssc_device *ssc; + struct dma_chan *dma_chan; + struct dma_slave_config slave_config; + int ret; + + prtd = snd_dmaengine_pcm_get_data(substream); + ssc = prtd->ssc; + + ret = snd_hwparams_to_dma_slave_config(substream, params, + &slave_config); + if (ret) { + pr_err("atmel-pcm: hwparams to dma slave configure failed\n"); + return ret; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR; + slave_config.dst_maxburst = 1; + } else { + slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR; + slave_config.src_maxburst = 1; + } + + slave_config.device_fc = false; + + dma_chan = snd_dmaengine_pcm_get_chan(substream); + if (dmaengine_slave_config(dma_chan, &slave_config)) { + pr_err("atmel-pcm: failed to configure dma channel\n"); + ret = -EBUSY; + return ret; + } + + return 0; +} + +static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pcm_dma_params *prtd; + struct ssc_device *ssc; + struct at_dma_slave *sdata = NULL; + int ret; + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + ssc = prtd->ssc; + if (ssc->pdev) + sdata = ssc->pdev->dev.platform_data; + + ret = snd_dmaengine_pcm_open(substream, filter, sdata); + if (ret) { + pr_err("atmel-pcm: dmaengine pcm open failed\n"); + return -EINVAL; + } + + snd_dmaengine_pcm_set_data(substream, prtd); + + ret = atmel_pcm_configure_dma(substream, params); + if (ret) { + pr_err("atmel-pcm: failed to configure dmai\n"); + goto err; + } + + prtd->dma_intr_handler = atmel_pcm_dma_irq; + + return 0; +err: + snd_dmaengine_pcm_close(substream); + return ret; +} + +static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) +{ + struct atmel_pcm_dma_params *prtd; + + prtd = snd_dmaengine_pcm_get_data(substream); + + ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); + ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); + + return 0; +} + +static int atmel_pcm_open(struct snd_pcm_substream *substream) +{ + snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware); + + return 0; +} + +static int atmel_pcm_close(struct snd_pcm_substream *substream) +{ + snd_dmaengine_pcm_close(substream); + + return 0; +} + +static struct snd_pcm_ops atmel_pcm_ops = { + .open = atmel_pcm_open, + .close = atmel_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = atmel_pcm_hw_params, + .prepare = atmel_pcm_dma_prepare, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer_no_residue, + .mmap = atmel_pcm_mmap, +}; + +static struct snd_soc_platform_driver atmel_soc_platform = { + .ops = &atmel_pcm_ops, + .pcm_new = atmel_pcm_new, + .pcm_free = atmel_pcm_free, +}; + +int atmel_pcm_dma_platform_register(struct device *dev) +{ + return snd_soc_register_platform(dev, &atmel_soc_platform); +} +EXPORT_SYMBOL(atmel_pcm_dma_platform_register); + +void atmel_pcm_dma_platform_unregister(struct device *dev) +{ + snd_soc_unregister_platform(dev); +} +EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister); + +MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>"); +MODULE_DESCRIPTION("Atmel DMA based PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c new file mode 100644 index 000000000000..6a293c713a38 --- /dev/null +++ b/sound/soc/atmel/atmel-pcm-pdc.c @@ -0,0 +1,401 @@ +/* + * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> + * + * Based on at91-pcm. by: + * Frank Mandarino <fmandarino@endrelia.com> + * Copyright 2006 Endrelia Technologies Inc. + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> +#include <linux/atmel-ssc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "atmel-pcm.h" + + +/*--------------------------------------------------------------------------*\ + * Hardware definition +\*--------------------------------------------------------------------------*/ +/* TODO: These values were taken from the AT91 platform driver, check + * them against real values for AT32 + */ +static const struct snd_pcm_hardware atmel_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, +}; + + +/*--------------------------------------------------------------------------*\ + * Data types +\*--------------------------------------------------------------------------*/ +struct atmel_runtime_data { + struct atmel_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of dma buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + + dma_addr_t period_ptr; /* physical address of next period */ + + /* PDC register save */ + u32 pdc_xpr_save; + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + +/*--------------------------------------------------------------------------*\ + * ISR +\*--------------------------------------------------------------------------*/ +static void atmel_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + static int count; + + count++; + + if (ssc_sr & params->mask->ssc_endbuf) { + pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", + params->name, ssc_sr, count); + + /* re-start the PDC */ + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + } + + if (ssc_sr & params->mask->ssc_endx) { + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + snd_pcm_period_elapsed(substream); +} + + +/*--------------------------------------------------------------------------*\ + * PCM operations +\*--------------------------------------------------------------------------*/ +static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params */ + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + prtd->params->dma_intr_handler = atmel_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + pr_debug("atmel-pcm: " + "hw_params: DMA for %s initialized " + "(dma_bytes=%u, period_size=%u)\n", + prtd->params->name, + runtime->dma_bytes, + prtd->period_size); + return 0; +} + +static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + +static int atmel_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + + ssc_writex(params->ssc->regs, SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + return 0; +} + +static int atmel_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct atmel_runtime_data *prtd = rtd->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + int ret = 0; + + pr_debug("atmel-pcm:buffer_size = %ld," + "dma_area = %p, dma_bytes = %u\n", + rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + pr_debug("atmel-pcm: trigger: " + "period_ptr=%lx, xpr=%u, " + "xcr=%u, xnpr=%u, xncr=%u\n", + (unsigned long)prtd->period_ptr, + ssc_readx(params->ssc->regs, params->pdc->xpr), + ssc_readx(params->ssc->regs, params->pdc->xcr), + ssc_readx(params->ssc->regs, params->pdc->xnpr), + ssc_readx(params->ssc->regs, params->pdc->xncr)); + + ssc_writex(params->ssc->regs, SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_enable); + + pr_debug("sr=%u imr=%u\n", + ssc_readx(params->ssc->regs, SSC_SR), + ssc_readx(params->ssc->regs, SSC_IER)); + break; /* SNDRV_PCM_TRIGGER_START */ + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t atmel_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd = runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + + return x; +} + +static int atmel_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + out: + return ret; +} + +static int atmel_pcm_close(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static struct snd_pcm_ops atmel_pcm_ops = { + .open = atmel_pcm_open, + .close = atmel_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = atmel_pcm_hw_params, + .hw_free = atmel_pcm_hw_free, + .prepare = atmel_pcm_prepare, + .trigger = atmel_pcm_trigger, + .pointer = atmel_pcm_pointer, + .mmap = atmel_pcm_mmap, +}; + + +/*--------------------------------------------------------------------------*\ + * ASoC platform driver +\*--------------------------------------------------------------------------*/ +#ifdef CONFIG_PM +static int atmel_pcm_suspend(struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* disable the PDC and save the PDC registers */ + + ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); + + prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); + prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); + prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); + prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); + + return 0; +} + +static int atmel_pcm_resume(struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* restore the PDC registers and enable the PDC */ + ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); + ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); + ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); + ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); + + ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); + return 0; +} +#else +#define atmel_pcm_suspend NULL +#define atmel_pcm_resume NULL +#endif + +static struct snd_soc_platform_driver atmel_soc_platform = { + .ops = &atmel_pcm_ops, + .pcm_new = atmel_pcm_new, + .pcm_free = atmel_pcm_free, + .suspend = atmel_pcm_suspend, + .resume = atmel_pcm_resume, +}; + +int atmel_pcm_pdc_platform_register(struct device *dev) +{ + return snd_soc_register_platform(dev, &atmel_soc_platform); +} +EXPORT_SYMBOL(atmel_pcm_pdc_platform_register); + +void atmel_pcm_pdc_platform_unregister(struct device *dev) +{ + snd_soc_unregister_platform(dev); +} +EXPORT_SYMBOL(atmel_pcm_pdc_platform_unregister); + +MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); +MODULE_DESCRIPTION("Atmel PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 9b84f985770e..e99f1811300a 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -32,80 +32,25 @@ */ #include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> #include <linux/dma-mapping.h> -#include <linux/atmel_pdc.h> -#include <linux/atmel-ssc.h> - -#include <sound/core.h> #include <sound/pcm.h> -#include <sound/pcm_params.h> #include <sound/soc.h> - #include "atmel-pcm.h" - -/*--------------------------------------------------------------------------*\ - * Hardware definition -\*--------------------------------------------------------------------------*/ -/* TODO: These values were taken from the AT91 platform driver, check - * them against real values for AT32 - */ -static const struct snd_pcm_hardware atmel_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - - -/*--------------------------------------------------------------------------*\ - * Data types -\*--------------------------------------------------------------------------*/ -struct atmel_runtime_data { - struct atmel_pcm_dma_params *params; - dma_addr_t dma_buffer; /* physical address of dma buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - - dma_addr_t period_ptr; /* physical address of next period */ - - /* PDC register save */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - - -/*--------------------------------------------------------------------------*\ - * Helper functions -\*--------------------------------------------------------------------------*/ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = atmel_pcm_hardware.buffer_bytes_max; + size_t size = ATMEL_SSC_DMABUF_SIZE; buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; buf->private_data = NULL; buf->area = dma_alloc_coherent(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - pr_debug("atmel-pcm:" - "preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, - (void *) buf->addr, - size); + &buf->addr, GFP_KERNEL); + pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n", + (void *)buf->area, (void *)buf->addr, size); if (!buf->area) return -ENOMEM; @@ -113,258 +58,19 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, buf->bytes = size; return 0; } -/*--------------------------------------------------------------------------*\ - * ISR -\*--------------------------------------------------------------------------*/ -static void atmel_pcm_dma_irq(u32 ssc_sr, - struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - static int count; - - count++; - - if (ssc_sr & params->mask->ssc_endbuf) { - pr_warning("atmel-pcm: buffer %s on %s" - " (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? "underrun" : "overrun", - params->name, ssc_sr, count); - - /* re-start the PDC */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - } - - if (ssc_sr & params->mask->ssc_endx) { - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - snd_pcm_period_elapsed(substream); -} - - -/*--------------------------------------------------------------------------*\ - * PCM operations -\*--------------------------------------------------------------------------*/ -static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params */ - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - prtd->params->dma_intr_handler = atmel_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - pr_debug("atmel-pcm: " - "hw_params: DMA for %s initialized " - "(dma_bytes=%u, period_size=%u)\n", - prtd->params->name, - runtime->dma_bytes, - prtd->period_size); - return 0; -} - -static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - -static int atmel_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - ssc_writex(params->ssc->regs, SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - return 0; -} - -static int atmel_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct atmel_runtime_data *prtd = rtd->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - int ret = 0; - - pr_debug("atmel-pcm:buffer_size = %ld," - "dma_area = %p, dma_bytes = %u\n", - rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - pr_debug("atmel-pcm: trigger: " - "period_ptr=%lx, xpr=%u, " - "xcr=%u, xnpr=%u, xncr=%u\n", - (unsigned long)prtd->period_ptr, - ssc_readx(params->ssc->regs, params->pdc->xpr), - ssc_readx(params->ssc->regs, params->pdc->xcr), - ssc_readx(params->ssc->regs, params->pdc->xnpr), - ssc_readx(params->ssc->regs, params->pdc->xncr)); - - ssc_writex(params->ssc->regs, SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_enable); - - pr_debug("sr=%u imr=%u\n", - ssc_readx(params->ssc->regs, SSC_SR), - ssc_readx(params->ssc->regs, SSC_IER)); - break; /* SNDRV_PCM_TRIGGER_START */ - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - break; - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - return ret; -} - -static snd_pcm_uframes_t atmel_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - - return x; -} - -static int atmel_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - out: - return ret; -} - -static int atmel_pcm_close(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - -static int atmel_pcm_mmap(struct snd_pcm_substream *substream, +int atmel_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { return remap_pfn_range(vma, vma->vm_start, substream->dma_buffer.addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); } +EXPORT_SYMBOL_GPL(atmel_pcm_mmap); -static struct snd_pcm_ops atmel_pcm_ops = { - .open = atmel_pcm_open, - .close = atmel_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = atmel_pcm_hw_params, - .hw_free = atmel_pcm_hw_free, - .prepare = atmel_pcm_prepare, - .trigger = atmel_pcm_trigger, - .pointer = atmel_pcm_pointer, - .mmap = atmel_pcm_mmap, -}; - - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32); -static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) +int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -376,6 +82,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n"); ret = atmel_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) @@ -383,8 +90,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) } if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { - pr_debug("atmel-pcm:" - "Allocating PCM capture DMA buffer\n"); + pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n"); ret = atmel_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) @@ -393,8 +99,9 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) out: return ret; } +EXPORT_SYMBOL_GPL(atmel_pcm_new); -static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) +void atmel_pcm_free(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -413,89 +120,5 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) buf->area = NULL; } } +EXPORT_SYMBOL_GPL(atmel_pcm_free); -#ifdef CONFIG_PM -static int atmel_pcm_suspend(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); - prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); - prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); - prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); - - return 0; -} - -static int atmel_pcm_resume(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); - ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); - ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); - ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else -#define atmel_pcm_suspend NULL -#define atmel_pcm_resume NULL -#endif - -static struct snd_soc_platform_driver atmel_soc_platform = { - .ops = &atmel_pcm_ops, - .pcm_new = atmel_pcm_new, - .pcm_free = atmel_pcm_free_dma_buffers, - .suspend = atmel_pcm_suspend, - .resume = atmel_pcm_resume, -}; - -static int __devinit atmel_soc_platform_probe(struct platform_device *pdev) -{ - return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform); -} - -static int __devexit atmel_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -static struct platform_driver atmel_pcm_driver = { - .driver = { - .name = "atmel-pcm-audio", - .owner = THIS_MODULE, - }, - - .probe = atmel_soc_platform_probe, - .remove = __devexit_p(atmel_soc_platform_remove), -}; - -module_platform_driver(atmel_pcm_driver); - -MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); -MODULE_DESCRIPTION("Atmel PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h index 5e0a95e64329..bb45d20e7250 100644 --- a/sound/soc/atmel/atmel-pcm.h +++ b/sound/soc/atmel/atmel-pcm.h @@ -36,6 +36,8 @@ #include <linux/atmel-ssc.h> +#define ATMEL_SSC_DMABUF_SIZE (64 * 1024) + /* * Registers and status bits that are required by the PCM driver. */ @@ -50,6 +52,7 @@ struct atmel_pdc_regs { struct atmel_ssc_mask { u32 ssc_enable; /* SSC recv/trans enable */ u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_error; /* SSC error conditions */ u32 ssc_endx; /* SSC ENDTX or ENDRX */ u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ u32 pdc_enable; /* PDC recv/trans enable */ @@ -80,4 +83,35 @@ struct atmel_pcm_dma_params { #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) +int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd); +void atmel_pcm_free(struct snd_pcm *pcm); +int atmel_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma); + +#ifdef CONFIG_SND_ATMEL_SOC_PDC +int atmel_pcm_pdc_platform_register(struct device *dev); +void atmel_pcm_pdc_platform_unregister(struct device *dev); +#else +static inline int atmel_pcm_pdc_platform_register(struct device *dev) +{ + return 0; +} +static inline void atmel_pcm_pdc_platform_unregister(struct device *dev) +{ +} +#endif + +#ifdef CONFIG_SND_ATMEL_SOC_DMA +int atmel_pcm_dma_platform_register(struct device *dev); +void atmel_pcm_dma_platform_unregister(struct device *dev); +#else +static inline int atmel_pcm_dma_platform_register(struct device *dev) +{ + return 0; +} +static inline void atmel_pcm_dma_platform_unregister(struct device *dev) +{ +} +#endif + #endif /* _ATMEL_PCM_H */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 354341ec0f42..1c7663422054 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -48,11 +48,7 @@ #include "atmel_ssc_dai.h" -#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) -#define NUM_SSC_DEVICES 1 -#else #define NUM_SSC_DEVICES 3 -#endif /* * SSC PDC registers required by the PCM DMA engine. @@ -107,7 +103,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { .pdc = &pdc_rx_reg, .mask = &ssc_rx_mask, } }, -#if NUM_SSC_DEVICES == 3 {{ .name = "SSC1 PCM out", .pdc = &pdc_tx_reg, @@ -128,7 +123,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { .pdc = &pdc_rx_reg, .mask = &ssc_rx_mask, } }, -#endif }; @@ -139,7 +133,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { .dir_mask = SSC_DIR_MASK_UNUSED, .initialized = 0, }, -#if NUM_SSC_DEVICES == 3 { .name = "ssc1", .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), @@ -152,7 +145,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { .dir_mask = SSC_DIR_MASK_UNUSED, .initialized = 0, }, -#endif }; @@ -690,27 +682,9 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) static int atmel_ssc_probe(struct snd_soc_dai *dai) { struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; - int ret = 0; snd_soc_dai_set_drvdata(dai, ssc_p); - /* - * Request SSC device - */ - ssc_p->ssc = ssc_request(dai->id); - if (IS_ERR(ssc_p->ssc)) { - printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id); - ret = PTR_ERR(ssc_p->ssc); - } - - return ret; -} - -static int atmel_ssc_remove(struct snd_soc_dai *dai) -{ - struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai); - - ssc_free(ssc_p->ssc); return 0; } @@ -728,30 +702,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .set_clkdiv = atmel_ssc_set_dai_clkdiv, }; -static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = { - { - .name = "atmel-ssc-dai.0", - .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = &atmel_ssc_dai_ops, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "atmel-ssc-dai.1", +static struct snd_soc_dai_driver atmel_ssc_dai = { .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -765,50 +717,50 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = { .rates = ATMEL_SSC_RATES, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, - }, - { - .name = "atmel-ssc-dai.2", - .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = &atmel_ssc_dai_ops, - }, -#endif }; -static __devinit int asoc_ssc_probe(struct platform_device *pdev) +static int asoc_ssc_init(struct device *dev) { - BUG_ON(pdev->id < 0); - BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai)); - return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]); -} + struct platform_device *pdev = to_platform_device(dev); + struct ssc_device *ssc = platform_get_drvdata(pdev); + int ret; + + ret = snd_soc_register_dai(dev, &atmel_ssc_dai); + if (ret) { + dev_err(dev, "Could not register DAI: %d\n", ret); + goto err; + } + + if (ssc->pdata->use_dma) + ret = atmel_pcm_dma_platform_register(dev); + else + ret = atmel_pcm_pdc_platform_register(dev); + + if (ret) { + dev_err(dev, "Could not register PCM: %d\n", ret); + goto err_unregister_dai; + }; -static int __devexit asoc_ssc_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&pdev->dev); return 0; + +err_unregister_dai: + snd_soc_unregister_dai(dev); +err: + return ret; } -static struct platform_driver asoc_ssc_driver = { - .driver = { - .name = "atmel-ssc-dai", - .owner = THIS_MODULE, - }, +static void asoc_ssc_exit(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ssc_device *ssc = platform_get_drvdata(pdev); - .probe = asoc_ssc_probe, - .remove = __devexit_p(asoc_ssc_remove), -}; + if (ssc->pdata->use_dma) + atmel_pcm_dma_platform_unregister(dev); + else + atmel_pcm_pdc_platform_unregister(dev); + + snd_soc_unregister_dai(dev); +} /** * atmel_ssc_set_audio - Allocate the specified SSC for audio use. @@ -816,50 +768,32 @@ static struct platform_driver asoc_ssc_driver = { int atmel_ssc_set_audio(int ssc_id) { struct ssc_device *ssc; - static struct platform_device *dma_pdev; - struct platform_device *ssc_pdev; int ret; - if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai)) - return -EINVAL; - - /* Allocate a dummy device for DMA if we don't have one already */ - if (!dma_pdev) { - dma_pdev = platform_device_alloc("atmel-pcm-audio", -1); - if (!dma_pdev) - return -ENOMEM; - - ret = platform_device_add(dma_pdev); - if (ret < 0) { - platform_device_put(dma_pdev); - dma_pdev = NULL; - return ret; - } - } - - ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); - if (!ssc_pdev) - return -ENOMEM; - /* If we can grab the SSC briefly to parent the DAI device off it */ ssc = ssc_request(ssc_id); - if (IS_ERR(ssc)) - pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n", + if (IS_ERR(ssc)) { + pr_err("Unable to parent ASoC SSC DAI on SSC: %ld\n", PTR_ERR(ssc)); - else { - ssc_pdev->dev.parent = &(ssc->pdev->dev); - ssc_free(ssc); + return PTR_ERR(ssc); + } else { + ssc_info[ssc_id].ssc = ssc; } - ret = platform_device_add(ssc_pdev); - if (ret < 0) - platform_device_put(ssc_pdev); + ret = asoc_ssc_init(&ssc->pdev->dev); return ret; } EXPORT_SYMBOL_GPL(atmel_ssc_set_audio); -module_platform_driver(asoc_ssc_driver); +void atmel_ssc_put_audio(int ssc_id) +{ + struct ssc_device *ssc = ssc_info[ssc_id].ssc; + + ssc_free(ssc); + asoc_ssc_exit(&ssc->pdev->dev); +} +EXPORT_SYMBOL_GPL(atmel_ssc_put_audio); /* Module information */ MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index 5d4f0f9b4d9a..b1f08d511495 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -117,6 +117,7 @@ struct atmel_ssc_info { struct atmel_ssc_state ssc_state; }; -int atmel_ssc_set_audio(int ssc); +int atmel_ssc_set_audio(int ssc_id); +void atmel_ssc_put_audio(int ssc_id); #endif /* _AT91_SSC_DAI_H */ diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index c88351488f45..0744610e53dd 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -38,6 +38,8 @@ #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/pinctrl/consumer.h> + #include <linux/atmel-ssc.h> #include <sound/core.h> @@ -179,10 +181,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link at91sam9g20ek_dai = { .name = "WM8731", .stream_name = "WM8731 PCM", - .cpu_dai_name = "atmel-ssc-dai.0", + .cpu_dai_name = "at91rm9200_ssc.0", .codec_dai_name = "wm8731-hifi", .init = at91sam9g20ek_wm8731_init, - .platform_name = "atmel-pcm-audio", + .platform_name = "at91rm9200_ssc.0", .codec_name = "wm8731.0-001b", .ops = &at91sam9g20ek_ops, }; @@ -195,20 +197,31 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { .set_bias_level = at91sam9g20ek_set_bias_level, }; -static struct platform_device *at91sam9g20ek_snd_device; - -static int __init at91sam9g20ek_init(void) +static int __devinit at91sam9g20ek_audio_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; struct clk *pllb; + struct snd_soc_card *card = &snd_soc_at91sam9g20ek; + struct pinctrl *pinctrl; int ret; - if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) - return -ENODEV; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + dev_err(&pdev->dev, "Failed to request pinctrl for mck\n"); + return PTR_ERR(pinctrl); + } + + if (!np) { + if (!(machine_is_at91sam9g20ek() || + machine_is_at91sam9g20ek_2mmc())) + return -ENODEV; + } ret = atmel_ssc_set_audio(0); - if (ret != 0) { - pr_err("Failed to set SSC 0 for audio: %d\n", ret); - return ret; + if (ret) { + dev_err(&pdev->dev, "ssc channel is not valid\n"); + return -EINVAL; } /* @@ -236,45 +249,92 @@ static int __init at91sam9g20ek_init(void) clk_set_rate(mclk, MCLK_RATE); - at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); - if (!at91sam9g20ek_snd_device) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - ret = -ENOMEM; - goto err_mclk; + card->dev = &pdev->dev; + + /* Parse device node info */ + if (np) { + ret = snd_soc_of_parse_card_name(card, "atmel,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, + "atmel,audio-routing"); + if (ret) + goto err; + + /* Parse codec info */ + at91sam9g20ek_dai.codec_name = NULL; + codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "codec info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.codec_of_node = codec_np; + + /* Parse dai and platform info */ + at91sam9g20ek_dai.cpu_dai_name = NULL; + at91sam9g20ek_dai.platform_name = NULL; + cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "dai and pcm info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.cpu_of_node = cpu_np; + at91sam9g20ek_dai.platform_of_node = cpu_np; + + of_node_put(codec_np); + of_node_put(cpu_np); } - platform_set_drvdata(at91sam9g20ek_snd_device, - &snd_soc_at91sam9g20ek); - - ret = platform_device_add(at91sam9g20ek_snd_device); + ret = snd_soc_register_card(card); if (ret) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - goto err_device_add; + printk(KERN_ERR "ASoC: snd_soc_register_card() failed\n"); } return ret; -err_device_add: - platform_device_put(at91sam9g20ek_snd_device); err_mclk: clk_put(mclk); mclk = NULL; err: + atmel_ssc_put_audio(0); return ret; } -static void __exit at91sam9g20ek_exit(void) +static int __devexit at91sam9g20ek_audio_remove(struct platform_device *pdev) { - platform_device_unregister(at91sam9g20ek_snd_device); - at91sam9g20ek_snd_device = NULL; + struct snd_soc_card *card = platform_get_drvdata(pdev); + + atmel_ssc_put_audio(0); + snd_soc_unregister_card(card); clk_put(mclk); mclk = NULL; + + return 0; } -module_init(at91sam9g20ek_init); -module_exit(at91sam9g20ek_exit); +#ifdef CONFIG_OF +static const struct of_device_id at91sam9g20ek_wm8731_dt_ids[] = { + { .compatible = "atmel,at91sam9g20ek-wm8731-audio", }, + { } +}; +MODULE_DEVICE_TABLE(of, at91sam9g20ek_wm8731_dt_ids); +#endif + +static struct platform_driver at91sam9g20ek_audio_driver = { + .driver = { + .name = "at91sam9g20ek-audio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91sam9g20ek_wm8731_dt_ids), + }, + .probe = at91sam9g20ek_audio_probe, + .remove = __devexit_p(at91sam9g20ek_audio_remove), +}; + +module_platform_driver(at91sam9g20ek_audio_driver); /* Module information */ MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); +MODULE_ALIAS("platform:at91sam9g20ek-audio"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b92759a39361..3a847828932a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_LM4857 if I2C select SND_SOC_LM49453 if I2C select SND_SOC_MAX98088 if I2C + select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C @@ -54,6 +55,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM3008 select SND_SOC_RT5631 if I2C select SND_SOC_SGTL5000 if I2C + select SND_SOC_SI476X if MFD_SI476X_CORE select SND_SOC_SN95031 if INTEL_SCU_IPC select SND_SOC_SPDIF select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI @@ -146,6 +148,13 @@ config SND_SOC_WM_HUBS default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m +config SND_SOC_WM_ADSP + tristate + default y if SND_SOC_WM5102=y + default y if SND_SOC_WM2200=y + default m if SND_SOC_WM5102=m + default m if SND_SOC_WM2200=m + config SND_SOC_AB8500_CODEC tristate @@ -229,6 +238,7 @@ config SND_SOC_CX20442 tristate config SND_SOC_JZ4740_CODEC + select REGMAP_MMIO tristate config SND_SOC_L3 @@ -258,6 +268,9 @@ config SND_SOC_LM49453 config SND_SOC_MAX98088 tristate +config SND_SOC_MAX98090 + tristate + config SND_SOC_MAX98095 tristate @@ -277,6 +290,9 @@ config SND_SOC_RT5631 config SND_SOC_SGTL5000 tristate +config SND_SOC_SI476X + tristate + config SND_SOC_SIGMADSP tristate select CRC32 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9bd4d95aab4f..f6e8e36cceb7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -34,6 +34,7 @@ snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o snd-soc-max9768-objs := max9768.o snd-soc-max98088-objs := max98088.o +snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o @@ -45,6 +46,7 @@ snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o snd-soc-sigmadsp-objs := sigmadsp.o +snd-soc-si476x-objs := si476x.o snd-soc-sn95031-objs := sn95031.o snd-soc-spdif-tx-objs := spdif_transciever.o snd-soc-spdif-rx-objs := spdif_receiver.o @@ -62,6 +64,7 @@ snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wl1273-objs := wl1273.o +snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o snd-soc-wm1250-ev1-objs := wm1250-ev1.o snd-soc-wm2000-objs := wm2000.o @@ -155,6 +158,7 @@ obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o +obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o @@ -164,6 +168,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o +obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o @@ -229,6 +234,7 @@ obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o +obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index af547490b4f7..4d96090db662 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2356,7 +2356,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } -struct snd_soc_dai_driver ab8500_codec_dai[] = { +static struct snd_soc_dai_driver ab8500_codec_dai[] = { { .name = "ab8500-codec-dai.0", .id = 0, diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 31d4483245d0..4b11b82b2273 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -15,6 +15,8 @@ #include <sound/soc.h> #include <sound/initval.h> #include <linux/spi/spi.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <sound/asoundef.h> /* AK4104 registers addresses */ @@ -98,14 +100,32 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, val = 0; switch (params_rate(params)) { + case 22050: + val |= IEC958_AES3_CON_FS_22050; + break; + case 24000: + val |= IEC958_AES3_CON_FS_24000; + break; + case 32000: + val |= IEC958_AES3_CON_FS_32000; + break; case 44100: val |= IEC958_AES3_CON_FS_44100; break; case 48000: val |= IEC958_AES3_CON_FS_48000; break; - case 32000: - val |= IEC958_AES3_CON_FS_32000; + case 88200: + val |= IEC958_AES3_CON_FS_88200; + break; + case 96000: + val |= IEC958_AES3_CON_FS_96000; + break; + case 176400: + val |= IEC958_AES3_CON_FS_176400; + break; + case 192000: + val |= IEC958_AES3_CON_FS_192000; break; default: dev_err(codec->dev, "unsupported sampling rate\n"); @@ -186,6 +206,7 @@ static const struct regmap_config ak4104_regmap = { static int ak4104_spi_probe(struct spi_device *spi) { + struct device_node *np = spi->dev.of_node; struct ak4104_private *ak4104; unsigned int val; int ret; @@ -201,49 +222,59 @@ static int ak4104_spi_probe(struct spi_device *spi) if (ak4104 == NULL) return -ENOMEM; - ak4104->regmap = regmap_init_spi(spi, &ak4104_regmap); + ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); if (IS_ERR(ak4104->regmap)) { ret = PTR_ERR(ak4104->regmap); return ret; } + if (np) { + enum of_gpio_flags flags; + int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); + + if (gpio_is_valid(gpio)) { + ret = devm_gpio_request_one(&spi->dev, gpio, + flags & OF_GPIO_ACTIVE_LOW ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + "ak4104 reset"); + if (ret < 0) + return ret; + } + } + /* read the 'reserved' register - according to the datasheet, it * should contain 0x5b. Not a good way to verify the presence of * the device, but there is no hardware ID register. */ ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val); if (ret != 0) - goto err; - if (val != AK4104_RESERVED_VAL) { - ret = -ENODEV; - goto err; - } + return ret; + if (val != AK4104_RESERVED_VAL) + return -ENODEV; spi_set_drvdata(spi, ak4104); ret = snd_soc_register_codec(&spi->dev, &soc_codec_device_ak4104, &ak4104_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(ak4104->regmap); return ret; } static int __devexit ak4104_spi_remove(struct spi_device *spi) { - struct ak4104_private *ak4101 = spi_get_drvdata(spi); - regmap_exit(ak4101->regmap); snd_soc_unregister_codec(&spi->dev); return 0; } +static const struct of_device_id ak4104_of_match[] = { + { .compatible = "asahi-kasei,ak4104", }, + { } +}; +MODULE_DEVICE_TABLE(of, ak4104_of_match); + static struct spi_driver ak4104_spi_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = ak4104_of_match, }, .probe = ak4104_spi_probe, .remove = __devexit_p(ak4104_spi_remove), diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 618fdc30f73e..fc5581063b2d 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -447,7 +447,7 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c, if (ak4535 == NULL) return -ENOMEM; - ak4535->regmap = regmap_init_i2c(i2c, &ak4535_regmap); + ak4535->regmap = devm_regmap_init_i2c(i2c, &ak4535_regmap); if (IS_ERR(ak4535->regmap)) { ret = PTR_ERR(ak4535->regmap); dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); @@ -458,18 +458,13 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4535, &ak4535_dai, 1); - if (ret != 0) - regmap_exit(ak4535->regmap); return ret; } static __devexit int ak4535_i2c_remove(struct i2c_client *client) { - struct ak4535_priv *ak4535 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(ak4535->regmap); return 0; } diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index b3e24f289421..546466abb77f 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -194,12 +194,6 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { {"LINEOUT Mixer", "DACL", "DAC"}, }; -/* codec private data */ -struct ak4642_priv { - unsigned int sysclk; - enum snd_soc_control_type control_type; -}; - /* * ak4642 register cache */ @@ -468,10 +462,9 @@ static int ak4642_resume(struct snd_soc_codec *codec) static int ak4642_probe(struct snd_soc_codec *codec) { - struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4642->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -523,21 +516,9 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { static __devinit int ak4642_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct ak4642_priv *ak4642; - int ret; - - ak4642 = devm_kzalloc(&i2c->dev, sizeof(struct ak4642_priv), - GFP_KERNEL); - if (!ak4642) - return -ENOMEM; - - i2c_set_clientdata(i2c, ak4642); - ak4642->control_type = SND_SOC_I2C; - - ret = snd_soc_register_codec(&i2c->dev, + return snd_soc_register_codec(&i2c->dev, (struct snd_soc_codec_driver *)id->driver_data, &ak4642_dai, 1); - return ret; } static __devexit int ak4642_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index c03b65af3059..adf397b9d0e6 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -226,6 +226,31 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values); const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0); EXPORT_SYMBOL_GPL(arizona_mixer_tlv); +static const char *arizona_vol_ramp_text[] = { + "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", + "15ms/6dB", "30ms/6dB", +}; + +const struct soc_enum arizona_in_vd_ramp = + SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, + ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); + +const struct soc_enum arizona_in_vi_ramp = + SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, + ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); + +const struct soc_enum arizona_out_vd_ramp = + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, + ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); + +const struct soc_enum arizona_out_vi_ramp = + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, + ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); + static const char *arizona_lhpf_mode_text[] = { "Low-pass", "High-pass" }; @@ -268,7 +293,7 @@ EXPORT_SYMBOL_GPL(arizona_out_ev); static unsigned int arizona_sysclk_48k_rates[] = { 6144000, 12288000, - 22579200, + 24576000, 49152000, 73728000, 98304000, @@ -278,7 +303,7 @@ static unsigned int arizona_sysclk_48k_rates[] = { static unsigned int arizona_sysclk_44k1_rates[] = { 5644800, 11289600, - 24576000, + 22579200, 45158400, 67737600, 90316800, @@ -380,6 +405,18 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, case 49152000: val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT; break; + case 67737600: + case 73728000: + val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT; + break; + case 90316800: + case 98304000: + val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT; + break; + case 135475200: + case 147456000: + val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; + break; default: return -EINVAL; } @@ -737,6 +774,9 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, return -EBUSY; } + dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1, + arizona_dai_clk_str(clk_id)); + memset(&routes, 0, sizeof(routes)); routes[0].sink = dai->driver->capture.stream_name; routes[1].sink = dai->driver->playback.stream_name; @@ -749,6 +789,8 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, routes[1].source = arizona_dai_clk_str(clk_id); snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes)); + dai_priv->clk = clk_id; + return snd_soc_dapm_sync(&codec->dapm); } @@ -925,6 +967,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source, bool ena; int ret; + if (fll->fref == Fref && fll->fout == Fout) + return 0; + ret = regmap_read(arizona->regmap, fll->base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", @@ -970,6 +1015,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ena) pm_runtime_put_autosuspend(arizona->dev); + fll->fref = Fref; + fll->fout = Fout; + return 0; } @@ -998,10 +1046,13 @@ int arizona_set_fll(struct arizona_fll *fll, int source, ARIZONA_FLL1_SYNC_ENA); ret = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(25)); + msecs_to_jiffies(250)); if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); + fll->fref = Fref; + fll->fout = Fout; + return 0; } EXPORT_SYMBOL_GPL(arizona_set_fll); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 36ec64946120..41dae1ed3b71 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -17,6 +17,8 @@ #include <sound/soc.h> +#include "wm_adsp.h" + #define ARIZONA_CLK_SYSCLK 1 #define ARIZONA_CLK_ASYNCCLK 2 #define ARIZONA_CLK_OPCLK 3 @@ -46,15 +48,18 @@ #define ARIZONA_MIXER_VOL_SHIFT 1 #define ARIZONA_MIXER_VOL_WIDTH 7 -#define ARIZONA_MAX_DAI 3 +#define ARIZONA_MAX_DAI 4 +#define ARIZONA_MAX_ADSP 4 struct arizona; +struct wm_adsp; struct arizona_dai_priv { int clk; }; struct arizona_priv { + struct wm_adsp adsp[ARIZONA_MAX_ADSP]; struct arizona *arizona; int sysclk; int asyncclk; @@ -89,19 +94,30 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; const struct snd_kcontrol_new name##_mux = \ SOC_DAPM_VALUE_ENUM("Route", name##_enum) +#define ARIZONA_MUX_ENUMS(name, base_reg) \ + static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg); \ + static ARIZONA_MUX_CTL_DECL(name) + #define ARIZONA_MIXER_ENUMS(name, base_reg) \ - static ARIZONA_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ - static ARIZONA_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \ - static ARIZONA_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \ - static ARIZONA_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \ - static ARIZONA_MUX_CTL_DECL(name##_in1); \ - static ARIZONA_MUX_CTL_DECL(name##_in2); \ - static ARIZONA_MUX_CTL_DECL(name##_in3); \ - static ARIZONA_MUX_CTL_DECL(name##_in4) + ARIZONA_MUX_ENUMS(name##_in1, base_reg); \ + ARIZONA_MUX_ENUMS(name##_in2, base_reg + 2); \ + ARIZONA_MUX_ENUMS(name##_in3, base_reg + 4); \ + ARIZONA_MUX_ENUMS(name##_in4, base_reg + 6) + +#define ARIZONA_DSP_AUX_ENUMS(name, base_reg) \ + ARIZONA_MUX_ENUMS(name##_aux1, base_reg); \ + ARIZONA_MUX_ENUMS(name##_aux2, base_reg + 8); \ + ARIZONA_MUX_ENUMS(name##_aux3, base_reg + 16); \ + ARIZONA_MUX_ENUMS(name##_aux4, base_reg + 24); \ + ARIZONA_MUX_ENUMS(name##_aux5, base_reg + 32); \ + ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40) #define ARIZONA_MUX(name, ctrl) \ SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) +#define ARIZONA_MUX_WIDGETS(name, name_str) \ + ARIZONA_MUX(name_str " Input", &name##_mux) + #define ARIZONA_MIXER_WIDGETS(name, name_str) \ ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \ ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \ @@ -109,6 +125,19 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) +#define ARIZONA_DSP_WIDGETS(name, name_str) \ + ARIZONA_MIXER_WIDGETS(name##L, name_str "L"), \ + ARIZONA_MIXER_WIDGETS(name##R, name_str "R"), \ + ARIZONA_MUX(name_str " Aux 1", &name##_aux1_mux), \ + ARIZONA_MUX(name_str " Aux 2", &name##_aux2_mux), \ + ARIZONA_MUX(name_str " Aux 3", &name##_aux3_mux), \ + ARIZONA_MUX(name_str " Aux 4", &name##_aux4_mux), \ + ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \ + ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux) + +#define ARIZONA_MUX_ROUTES(name) \ + ARIZONA_MIXER_INPUT_ROUTES(name " Input") + #define ARIZONA_MIXER_ROUTES(widget, name) \ { widget, NULL, name " Mixer" }, \ { name " Mixer", NULL, name " Input 1" }, \ @@ -120,6 +149,28 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Input 4") +#define ARIZONA_DSP_ROUTES(name) \ + { name, NULL, name " Aux 1" }, \ + { name, NULL, name " Aux 2" }, \ + { name, NULL, name " Aux 3" }, \ + { name, NULL, name " Aux 4" }, \ + { name, NULL, name " Aux 5" }, \ + { name, NULL, name " Aux 6" }, \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \ + ARIZONA_MIXER_ROUTES(name, name "L"), \ + ARIZONA_MIXER_ROUTES(name, name "R") + +extern const struct soc_enum arizona_in_vi_ramp; +extern const struct soc_enum arizona_in_vd_ramp; + +extern const struct soc_enum arizona_out_vi_ramp; +extern const struct soc_enum arizona_out_vd_ramp; + extern const struct soc_enum arizona_lhpf1_mode; extern const struct soc_enum arizona_lhpf2_mode; extern const struct soc_enum arizona_lhpf3_mode; @@ -146,6 +197,8 @@ struct arizona_fll { unsigned int vco_mult; struct completion lock; struct completion ok; + unsigned int fref; + unsigned int fout; char lock_name[ARIZONA_FLL_NAME_LEN]; char clock_ok_name[ARIZONA_FLL_NAME_LEN]; diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index f994af34f552..6ad3878db8fc 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -474,18 +474,28 @@ static int cs4271_probe(struct snd_soc_codec *codec) struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; int ret; int gpio_nreset = -EINVAL; + int amutec_eq_bmutec = 0; #ifdef CONFIG_OF - if (of_match_device(cs4271_dt_ids, codec->dev)) + if (of_match_device(cs4271_dt_ids, codec->dev)) { gpio_nreset = of_get_named_gpio(codec->dev->of_node, "reset-gpio", 0); + + if (!of_get_property(codec->dev->of_node, + "cirrus,amutec-eq-bmutec", NULL)) + amutec_eq_bmutec = 1; + } #endif - if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset)) - gpio_nreset = cs4271plat->gpio_nreset; + if (cs4271plat) { + if (gpio_is_valid(cs4271plat->gpio_nreset)) + gpio_nreset = cs4271plat->gpio_nreset; + + amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; + } if (gpio_nreset >= 0) - if (gpio_request(gpio_nreset, "CS4271 Reset")) + if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) gpio_nreset = -EINVAL; if (gpio_nreset >= 0) { /* Reset codec */ @@ -528,6 +538,11 @@ static int cs4271_probe(struct snd_soc_codec *codec) /* Power-up sequence requires 85 uS */ udelay(85); + if (amutec_eq_bmutec) + snd_soc_update_bits(codec, CS4271_MODE2, + CS4271_MODE2_MUTECAEQUB, + CS4271_MODE2_MUTECAEQUB); + return snd_soc_add_codec_controls(codec, cs4271_snd_controls, ARRAY_SIZE(cs4271_snd_controls)); } @@ -535,15 +550,10 @@ static int cs4271_probe(struct snd_soc_codec *codec) static int cs4271_remove(struct snd_soc_codec *codec) { struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); - int gpio_nreset; - - gpio_nreset = cs4271->gpio_nreset; - if (gpio_is_valid(gpio_nreset)) { + if (gpio_is_valid(cs4271->gpio_nreset)) /* Set codec to the reset state */ - gpio_set_value(gpio_nreset, 0); - gpio_free(gpio_nreset); - } + gpio_set_value(cs4271->gpio_nreset, 0); return 0; }; diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index af5db7080519..843c1eb72faf 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1231,7 +1231,7 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, da7210); - da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap_config_i2c); + da7210->regmap = devm_regmap_init_i2c(i2c, &da7210_regmap_config_i2c); if (IS_ERR(da7210->regmap)) { ret = PTR_ERR(da7210->regmap); dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); @@ -1245,24 +1245,15 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7210, &da7210_dai, 1); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); - goto err_regmap; - } - return ret; - -err_regmap: - regmap_exit(da7210->regmap); return ret; } static int __devexit da7210_i2c_remove(struct i2c_client *client) { - struct da7210_priv *da7210 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(da7210->regmap); return 0; } @@ -1346,24 +1337,15 @@ static int __devinit da7210_spi_probe(struct spi_device *spi) if (ret != 0) dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret); - ret = snd_soc_register_codec(&spi->dev, + ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_da7210, &da7210_dai, 1); - if (ret < 0) - goto err_regmap; - - return ret; - -err_regmap: - regmap_exit(da7210->regmap); return ret; } static int __devexit da7210_spi_remove(struct spi_device *spi) { - struct da7210_priv *da7210 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(da7210->regmap); return 0; } diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index f379b085c392..d3a6de2e757b 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -173,6 +173,7 @@ #define DA9055_AIF_FORMAT_I2S_MODE (0 << 0) #define DA9055_AIF_FORMAT_LEFT_J (1 << 0) #define DA9055_AIF_FORMAT_RIGHT_J (2 << 0) +#define DA9055_AIF_FORMAT_DSP (3 << 0) #define DA9055_AIF_WORD_S16_LE (0 << 2) #define DA9055_AIF_WORD_S20_3LE (1 << 2) #define DA9055_AIF_WORD_S24_LE (2 << 2) @@ -752,6 +753,17 @@ static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] = { 6, 1, 0), }; +/* Headphone Output Enable */ +static const struct snd_kcontrol_new da9055_dapm_hp_l_control = +SOC_DAPM_SINGLE("Switch", DA9055_HP_L_CTRL, 3, 1, 0); + +static const struct snd_kcontrol_new da9055_dapm_hp_r_control = +SOC_DAPM_SINGLE("Switch", DA9055_HP_R_CTRL, 3, 1, 0); + +/* Lineout Output Enable */ +static const struct snd_kcontrol_new da9055_dapm_lineout_control = +SOC_DAPM_SINGLE("Switch", DA9055_LINE_CTRL, 3, 1, 0); + /* DAPM widgets */ static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = { /* Input Side */ @@ -816,6 +828,14 @@ static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = { &da9055_dapm_mixoutr_controls[0], ARRAY_SIZE(da9055_dapm_mixoutr_controls)), + /* Output Enable Switches */ + SND_SOC_DAPM_SWITCH("Headphone Left Enable", SND_SOC_NOPM, 0, 0, + &da9055_dapm_hp_l_control), + SND_SOC_DAPM_SWITCH("Headphone Right Enable", SND_SOC_NOPM, 0, 0, + &da9055_dapm_hp_r_control), + SND_SOC_DAPM_SWITCH("Lineout Enable", SND_SOC_NOPM, 0, 0, + &da9055_dapm_lineout_control), + /* Output PGAs */ SND_SOC_DAPM_PGA("MIXOUT Left", DA9055_MIXOUT_L_CTRL, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("MIXOUT Right", DA9055_MIXOUT_R_CTRL, 7, 0, NULL, 0), @@ -901,17 +921,20 @@ static const struct snd_soc_dapm_route da9055_audio_map[] = { {"Out Mixer Right", "DAC Right Switch", "DAC Right"}, {"MIXOUT Left", NULL, "Out Mixer Left"}, - {"Headphone Left", NULL, "MIXOUT Left"}, + {"Headphone Left Enable", "Switch", "MIXOUT Left"}, + {"Headphone Left", NULL, "Headphone Left Enable"}, {"Headphone Left", NULL, "Charge Pump"}, {"HPL", NULL, "Headphone Left"}, {"MIXOUT Right", NULL, "Out Mixer Right"}, - {"Headphone Right", NULL, "MIXOUT Right"}, + {"Headphone Right Enable", "Switch", "MIXOUT Right"}, + {"Headphone Right", NULL, "Headphone Right Enable"}, {"Headphone Right", NULL, "Charge Pump"}, {"HPR", NULL, "Headphone Right"}, {"MIXOUT Right", NULL, "Out Mixer Right"}, - {"Lineout", NULL, "MIXOUT Right"}, + {"Lineout Enable", "Switch", "MIXOUT Right"}, + {"Lineout", NULL, "Lineout Enable"}, {"LINE", NULL, "Lineout"}, }; @@ -1175,6 +1198,9 @@ static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_RIGHT_J: aif_ctrl = DA9055_AIF_FORMAT_RIGHT_J; break; + case SND_SOC_DAIFMT_DSP_A: + aif_ctrl = DA9055_AIF_FORMAT_DSP; + break; default: return -EINVAL; } @@ -1390,8 +1416,7 @@ static int da9055_probe(struct snd_soc_codec *codec) DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); /* - * There are two separate control bits for input and output mixers as - * well as headphone and line outs. + * There are two separate control bits for input and output mixers. * One to enable corresponding amplifier and other to enable its * output. As amplifier bits are related to power control, they are * being managed by DAPM while other (non power related) bits are @@ -1407,14 +1432,6 @@ static int da9055_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, DA9055_MIXOUT_R_CTRL, DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN); - snd_soc_update_bits(codec, DA9055_HP_L_CTRL, - DA9055_HP_L_AMP_OE, DA9055_HP_L_AMP_OE); - snd_soc_update_bits(codec, DA9055_HP_R_CTRL, - DA9055_HP_R_AMP_OE, DA9055_HP_R_AMP_OE); - - snd_soc_update_bits(codec, DA9055_LINE_CTRL, - DA9055_LINE_AMP_OE, DA9055_LINE_AMP_OE); - /* Set this as per your system configuration */ snd_soc_write(codec, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ); diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 85d9cabe6d55..9ad1da36887e 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/regmap.h> #include <linux/delay.h> @@ -24,9 +25,10 @@ #include <sound/pcm_params.h> #include <sound/initval.h> #include <sound/soc.h> +#include <sound/tlv.h> #define JZ4740_REG_CODEC_1 0x0 -#define JZ4740_REG_CODEC_2 0x1 +#define JZ4740_REG_CODEC_2 0x4 #define JZ4740_CODEC_1_LINE_ENABLE BIT(29) #define JZ4740_CODEC_1_MIC_ENABLE BIT(28) @@ -67,43 +69,36 @@ #define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4 #define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0 -static const uint32_t jz4740_codec_regs[] = { - 0x021b2302, 0x00170803, +static const struct reg_default jz4740_codec_reg_defaults[] = { + { JZ4740_REG_CODEC_1, 0x021b2302 }, + { JZ4740_REG_CODEC_2, 0x00170803 }, }; struct jz4740_codec { - void __iomem *base; - struct resource *mem; + struct regmap *regmap; }; -static unsigned int jz4740_codec_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); - return readl(jz4740_codec->base + (reg << 2)); -} - -static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); - u32 *cache = codec->reg_cache; - - cache[reg] = val; - writel(val, jz4740_codec->base + (reg << 2)); +static const unsigned int jz4740_mic_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 2, TLV_DB_SCALE_ITEM(0, 600, 0), + 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), +}; - return 0; -} +static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0); +static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0); static const struct snd_kcontrol_new jz4740_codec_controls[] = { - SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2, - JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0), - SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2, - JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0), + SOC_SINGLE_TLV("Master Playback Volume", JZ4740_REG_CODEC_2, + JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0, + jz4740_out_tlv), + SOC_SINGLE_TLV("Master Capture Volume", JZ4740_REG_CODEC_2, + JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0, + jz4740_in_tlv), SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1, JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1), - SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2, - JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0), + SOC_SINGLE_TLV("Mic Capture Volume", JZ4740_REG_CODEC_2, + JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0, + jz4740_mic_tlv), }; static const struct snd_kcontrol_new jz4740_codec_output_controls[] = { @@ -163,8 +158,8 @@ static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = { static int jz4740_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(dai->codec); uint32_t val; - struct snd_soc_codec *codec = dai->codec; switch (params_rate(params)) { case 8000: @@ -200,7 +195,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream, val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_2, + regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_2, JZ4740_CODEC_2_SAMPLE_RATE_MASK, val); return 0; @@ -230,25 +225,23 @@ static struct snd_soc_dai_driver jz4740_codec_dai = { .symmetric_rates = 1, }; -static void jz4740_codec_wakeup(struct snd_soc_codec *codec) +static void jz4740_codec_wakeup(struct regmap *regmap) { - int i; - uint32_t *cache = codec->reg_cache; - - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET); udelay(2); - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0); - for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i) - jz4740_codec_write(codec, i, cache[i]); + regcache_sync(regmap); } static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); + struct regmap *regmap = jz4740_codec->regmap; unsigned int mask; unsigned int value; @@ -261,12 +254,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; value = 0; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); break; case SND_SOC_BIAS_STANDBY: /* The only way to clear the suspend flag is to reset the codec */ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) - jz4740_codec_wakeup(codec); + jz4740_codec_wakeup(regmap); mask = JZ4740_CODEC_1_VREF_DISABLE | JZ4740_CODEC_1_VREF_AMP_DISABLE | @@ -275,13 +268,14 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, JZ4740_CODEC_1_VREF_AMP_DISABLE | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); break; case SND_SOC_BIAS_OFF: mask = JZ4740_CODEC_1_SUSPEND; value = JZ4740_CODEC_1_SUSPEND; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); + regcache_mark_dirty(regmap); break; default: break; @@ -294,7 +288,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, static int jz4740_codec_dev_probe(struct snd_soc_codec *codec) { - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, + struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -331,12 +327,7 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .remove = jz4740_codec_dev_remove, .suspend = jz4740_codec_suspend, .resume = jz4740_codec_resume, - .read = jz4740_codec_read, - .write = jz4740_codec_write, .set_bias_level = jz4740_codec_set_bias_level, - .reg_cache_default = jz4740_codec_regs, - .reg_word_size = sizeof(u32), - .reg_cache_size = 2, .controls = jz4740_codec_controls, .num_controls = ARRAY_SIZE(jz4740_codec_controls), @@ -346,11 +337,23 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes), }; +static const struct regmap_config jz4740_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = JZ4740_REG_CODEC_2, + + .reg_defaults = jz4740_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + static int __devinit jz4740_codec_probe(struct platform_device *pdev) { int ret; struct jz4740_codec *jz4740_codec; struct resource *mem; + void __iomem *base; jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec), GFP_KERNEL); @@ -358,56 +361,29 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev) return -ENOMEM; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); - ret = -ENOENT; - goto err_out; - } - - mem = request_mem_region(mem->start, resource_size(mem), pdev->name); - if (!mem) { - dev_err(&pdev->dev, "Failed to request mmio memory region\n"); - ret = -EBUSY; - goto err_out; - } + base = devm_request_and_ioremap(&pdev->dev, mem); + if (!base) + return -EBUSY; - jz4740_codec->base = ioremap(mem->start, resource_size(mem)); - if (!jz4740_codec->base) { - dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); - ret = -EBUSY; - goto err_release_mem_region; - } - jz4740_codec->mem = mem; + jz4740_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &jz4740_codec_regmap_config); + if (IS_ERR(jz4740_codec->regmap)) + return PTR_ERR(jz4740_codec->regmap); platform_set_drvdata(pdev, jz4740_codec); ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1); - if (ret) { + if (ret) dev_err(&pdev->dev, "Failed to register codec\n"); - goto err_iounmap; - } - return 0; - -err_iounmap: - iounmap(jz4740_codec->base); -err_release_mem_region: - release_mem_region(mem->start, resource_size(mem)); -err_out: return ret; } static int __devexit jz4740_codec_remove(struct platform_device *pdev) { - struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev); - struct resource *mem = jz4740_codec->mem; - snd_soc_unregister_codec(&pdev->dev); - iounmap(jz4740_codec->base); - release_mem_region(mem->start, resource_size(mem)); - platform_set_drvdata(pdev, NULL); return 0; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 99b0a9dcff34..096b6aa87f0f 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1497,7 +1497,7 @@ static __devinit int lm49453_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, lm49453); - lm49453->regmap = regmap_init_i2c(i2c, &lm49453_regmap_config); + lm49453->regmap = devm_regmap_init_i2c(i2c, &lm49453_regmap_config); if (IS_ERR(lm49453->regmap)) { ret = PTR_ERR(lm49453->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -1508,21 +1508,15 @@ static __devinit int lm49453_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm49453, lm49453_dai, ARRAY_SIZE(lm49453_dai)); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); - regmap_exit(lm49453->regmap); - return ret; - } return ret; } static int __devexit lm49453_i2c_remove(struct i2c_client *client) { - struct lm49453_priv *lm49453 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(lm49453->regmap); return 0; } diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 17b3ec2d05cb..a777de6a1b23 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -187,7 +187,7 @@ static int __devinit max9768_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, max9768); - max9768->regmap = regmap_init_i2c(client, &max9768_i2c_regmap_config); + max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config); if (IS_ERR(max9768->regmap)) { err = PTR_ERR(max9768->regmap); goto err_gpio_free; @@ -195,12 +195,10 @@ static int __devinit max9768_i2c_probe(struct i2c_client *client, err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0); if (err) - goto err_regmap_free; + goto err_gpio_free; return 0; - err_regmap_free: - regmap_exit(max9768->regmap); err_gpio_free: if (gpio_is_valid(max9768->shdn_gpio)) gpio_free(max9768->shdn_gpio); @@ -215,7 +213,6 @@ static int __devexit max9768_i2c_remove(struct i2c_client *client) struct max9768 *max9768 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - regmap_exit(max9768->regmap); if (gpio_is_valid(max9768->shdn_gpio)) gpio_free(max9768->shdn_gpio); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 3264a5169306..b858264235c4 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2098,13 +2098,13 @@ static const struct i2c_device_id max98088_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); static struct i2c_driver max98088_i2c_driver = { - .driver = { - .name = "max98088", - .owner = THIS_MODULE, - }, - .probe = max98088_i2c_probe, - .remove = __devexit_p(max98088_i2c_remove), - .id_table = max98088_i2c_id, + .driver = { + .name = "max98088", + .owner = THIS_MODULE, + }, + .probe = max98088_i2c_probe, + .remove = max98088_i2c_remove, + .id_table = max98088_i2c_id, }; module_i2c_driver(max98088_i2c_driver); diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c new file mode 100644 index 000000000000..c9772ca3da4f --- /dev/null +++ b/sound/soc/codecs/max98090.c @@ -0,0 +1,577 @@ +/* + * max98090.c -- MAX98090 ALSA SoC Audio driver + * based on Rev0p8 datasheet + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * Based on + * + * max98095.c + * Copyright 2011 Maxim Integrated Products + * + * https://github.com/hardkernel/linux/commit/\ + * 3417d7166b17113b3b33b0a337c74d1c7cc313df#sound/soc/codecs/max98090.c + * Copyright 2011 Maxim Integrated Products + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +/* + * + * MAX98090 Registers Definition + * + */ + +/* RESET / STATUS / INTERRUPT REGISTERS */ +#define MAX98090_0x00_SW_RESET 0x00 +#define MAX98090_0x01_INT_STS 0x01 +#define MAX98090_0x02_JACK_STS 0x02 +#define MAX98090_0x03_INT_MASK 0x03 + +/* QUICK SETUP REGISTERS */ +#define MAX98090_0x04_SYS_CLK 0x04 +#define MAX98090_0x05_SAMPLE_RATE 0x05 +#define MAX98090_0x06_DAI_IF 0x06 +#define MAX98090_0x07_DAC_PATH 0x07 +#define MAX98090_0x08_MIC_TO_ADC 0x08 +#define MAX98090_0x09_LINE_TO_ADC 0x09 +#define MAX98090_0x0A_ANALOG_MIC_LOOP 0x0A +#define MAX98090_0x0B_ANALOG_LINE_LOOP 0x0B + +/* ANALOG INPUT CONFIGURATION REGISTERS */ +#define MAX98090_0x0D_INPUT_CONFIG 0x0D +#define MAX98090_0x0E_LINE_IN_LVL 0x0E +#define MAX98090_0x0F_LINI_IN_CFG 0x0F +#define MAX98090_0x10_MIC1_IN_LVL 0x10 +#define MAX98090_0x11_MIC2_IN_LVL 0x11 + +/* MICROPHONE CONFIGURATION REGISTERS */ +#define MAX98090_0x12_MIC_BIAS_VOL 0x12 +#define MAX98090_0x13_DIGITAL_MIC_CFG 0x13 +#define MAX98090_0x14_DIGITAL_MIC_MODE 0x14 + +/* ADC PATH AND CONFIGURATION REGISTERS */ +#define MAX98090_0x15_L_ADC_MIX 0x15 +#define MAX98090_0x16_R_ADC_MIX 0x16 +#define MAX98090_0x17_L_ADC_LVL 0x17 +#define MAX98090_0x18_R_ADC_LVL 0x18 +#define MAX98090_0x19_ADC_BIQUAD_LVL 0x19 +#define MAX98090_0x1A_ADC_SIDETONE 0x1A + +/* CLOCK CONFIGURATION REGISTERS */ +#define MAX98090_0x1B_SYS_CLK 0x1B +#define MAX98090_0x1C_CLK_MODE 0x1C +#define MAX98090_0x1D_ANY_CLK1 0x1D +#define MAX98090_0x1E_ANY_CLK2 0x1E +#define MAX98090_0x1F_ANY_CLK3 0x1F +#define MAX98090_0x20_ANY_CLK4 0x20 +#define MAX98090_0x21_MASTER_MODE 0x21 + +/* INTERFACE CONTROL REGISTERS */ +#define MAX98090_0x22_DAI_IF_FMT 0x22 +#define MAX98090_0x23_DAI_TDM_FMT1 0x23 +#define MAX98090_0x24_DAI_TDM_FMT2 0x24 +#define MAX98090_0x25_DAI_IO_CFG 0x25 +#define MAX98090_0x26_FILTER_CFG 0x26 +#define MAX98090_0x27_DAI_PLAYBACK_LVL 0x27 +#define MAX98090_0x28_EQ_PLAYBACK_LVL 0x28 + +/* HEADPHONE CONTROL REGISTERS */ +#define MAX98090_0x29_L_HP_MIX 0x29 +#define MAX98090_0x2A_R_HP_MIX 0x2A +#define MAX98090_0x2B_HP_CTR 0x2B +#define MAX98090_0x2C_L_HP_VOL 0x2C +#define MAX98090_0x2D_R_HP_VOL 0x2D + +/* SPEAKER CONFIGURATION REGISTERS */ +#define MAX98090_0x2E_L_SPK_MIX 0x2E +#define MAX98090_0x2F_R_SPK_MIX 0x2F +#define MAX98090_0x30_SPK_CTR 0x30 +#define MAX98090_0x31_L_SPK_VOL 0x31 +#define MAX98090_0x32_R_SPK_VOL 0x32 + +/* ALC CONFIGURATION REGISTERS */ +#define MAX98090_0x33_ALC_TIMING 0x33 +#define MAX98090_0x34_ALC_COMPRESSOR 0x34 +#define MAX98090_0x35_ALC_EXPANDER 0x35 +#define MAX98090_0x36_ALC_GAIN 0x36 + +/* RECEIVER AND LINE_OUTPUT REGISTERS */ +#define MAX98090_0x37_RCV_LOUT_L_MIX 0x37 +#define MAX98090_0x38_RCV_LOUT_L_CNTL 0x38 +#define MAX98090_0x39_RCV_LOUT_L_VOL 0x39 +#define MAX98090_0x3A_LOUT_R_MIX 0x3A +#define MAX98090_0x3B_LOUT_R_CNTL 0x3B +#define MAX98090_0x3C_LOUT_R_VOL 0x3C + +/* JACK DETECT AND ENABLE REGISTERS */ +#define MAX98090_0x3D_JACK_DETECT 0x3D +#define MAX98090_0x3E_IN_ENABLE 0x3E +#define MAX98090_0x3F_OUT_ENABLE 0x3F +#define MAX98090_0x40_LVL_CTR 0x40 +#define MAX98090_0x41_DSP_FILTER_ENABLE 0x41 + +/* BIAS AND POWER MODE CONFIGURATION REGISTERS */ +#define MAX98090_0x42_BIAS_CTR 0x42 +#define MAX98090_0x43_DAC_CTR 0x43 +#define MAX98090_0x44_ADC_CTR 0x44 +#define MAX98090_0x45_DEV_SHUTDOWN 0x45 + +/* REVISION ID REGISTER */ +#define MAX98090_0xFF_REV_ID 0xFF + +#define MAX98090_REG_MAX_CACHED 0x45 +#define MAX98090_REG_END 0xFF + +/* + * + * MAX98090 Registers Bit Fields + * + */ + +/* MAX98090_0x06_DAI_IF */ +#define MAX98090_DAI_IF_MASK 0x3F +#define MAX98090_RJ_M (1 << 5) +#define MAX98090_RJ_S (1 << 4) +#define MAX98090_LJ_M (1 << 3) +#define MAX98090_LJ_S (1 << 2) +#define MAX98090_I2S_M (1 << 1) +#define MAX98090_I2S_S (1 << 0) + +/* MAX98090_0x45_DEV_SHUTDOWN */ +#define MAX98090_SHDNRUN (1 << 7) + +/* codec private data */ +struct max98090_priv { + struct regmap *regmap; +}; + +static const struct reg_default max98090_reg_defaults[] = { + /* RESET / STATUS / INTERRUPT REGISTERS */ + {MAX98090_0x00_SW_RESET, 0x00}, + {MAX98090_0x01_INT_STS, 0x00}, + {MAX98090_0x02_JACK_STS, 0x00}, + {MAX98090_0x03_INT_MASK, 0x04}, + + /* QUICK SETUP REGISTERS */ + {MAX98090_0x04_SYS_CLK, 0x00}, + {MAX98090_0x05_SAMPLE_RATE, 0x00}, + {MAX98090_0x06_DAI_IF, 0x00}, + {MAX98090_0x07_DAC_PATH, 0x00}, + {MAX98090_0x08_MIC_TO_ADC, 0x00}, + {MAX98090_0x09_LINE_TO_ADC, 0x00}, + {MAX98090_0x0A_ANALOG_MIC_LOOP, 0x00}, + {MAX98090_0x0B_ANALOG_LINE_LOOP, 0x00}, + + /* ANALOG INPUT CONFIGURATION REGISTERS */ + {MAX98090_0x0D_INPUT_CONFIG, 0x00}, + {MAX98090_0x0E_LINE_IN_LVL, 0x1B}, + {MAX98090_0x0F_LINI_IN_CFG, 0x00}, + {MAX98090_0x10_MIC1_IN_LVL, 0x11}, + {MAX98090_0x11_MIC2_IN_LVL, 0x11}, + + /* MICROPHONE CONFIGURATION REGISTERS */ + {MAX98090_0x12_MIC_BIAS_VOL, 0x00}, + {MAX98090_0x13_DIGITAL_MIC_CFG, 0x00}, + {MAX98090_0x14_DIGITAL_MIC_MODE, 0x00}, + + /* ADC PATH AND CONFIGURATION REGISTERS */ + {MAX98090_0x15_L_ADC_MIX, 0x00}, + {MAX98090_0x16_R_ADC_MIX, 0x00}, + {MAX98090_0x17_L_ADC_LVL, 0x03}, + {MAX98090_0x18_R_ADC_LVL, 0x03}, + {MAX98090_0x19_ADC_BIQUAD_LVL, 0x00}, + {MAX98090_0x1A_ADC_SIDETONE, 0x00}, + + /* CLOCK CONFIGURATION REGISTERS */ + {MAX98090_0x1B_SYS_CLK, 0x00}, + {MAX98090_0x1C_CLK_MODE, 0x00}, + {MAX98090_0x1D_ANY_CLK1, 0x00}, + {MAX98090_0x1E_ANY_CLK2, 0x00}, + {MAX98090_0x1F_ANY_CLK3, 0x00}, + {MAX98090_0x20_ANY_CLK4, 0x00}, + {MAX98090_0x21_MASTER_MODE, 0x00}, + + /* INTERFACE CONTROL REGISTERS */ + {MAX98090_0x22_DAI_IF_FMT, 0x00}, + {MAX98090_0x23_DAI_TDM_FMT1, 0x00}, + {MAX98090_0x24_DAI_TDM_FMT2, 0x00}, + {MAX98090_0x25_DAI_IO_CFG, 0x00}, + {MAX98090_0x26_FILTER_CFG, 0x80}, + {MAX98090_0x27_DAI_PLAYBACK_LVL, 0x00}, + {MAX98090_0x28_EQ_PLAYBACK_LVL, 0x00}, + + /* HEADPHONE CONTROL REGISTERS */ + {MAX98090_0x29_L_HP_MIX, 0x00}, + {MAX98090_0x2A_R_HP_MIX, 0x00}, + {MAX98090_0x2B_HP_CTR, 0x00}, + {MAX98090_0x2C_L_HP_VOL, 0x1A}, + {MAX98090_0x2D_R_HP_VOL, 0x1A}, + + /* SPEAKER CONFIGURATION REGISTERS */ + {MAX98090_0x2E_L_SPK_MIX, 0x00}, + {MAX98090_0x2F_R_SPK_MIX, 0x00}, + {MAX98090_0x30_SPK_CTR, 0x00}, + {MAX98090_0x31_L_SPK_VOL, 0x2C}, + {MAX98090_0x32_R_SPK_VOL, 0x2C}, + + /* ALC CONFIGURATION REGISTERS */ + {MAX98090_0x33_ALC_TIMING, 0x00}, + {MAX98090_0x34_ALC_COMPRESSOR, 0x00}, + {MAX98090_0x35_ALC_EXPANDER, 0x00}, + {MAX98090_0x36_ALC_GAIN, 0x00}, + + /* RECEIVER AND LINE_OUTPUT REGISTERS */ + {MAX98090_0x37_RCV_LOUT_L_MIX, 0x00}, + {MAX98090_0x38_RCV_LOUT_L_CNTL, 0x00}, + {MAX98090_0x39_RCV_LOUT_L_VOL, 0x15}, + {MAX98090_0x3A_LOUT_R_MIX, 0x00}, + {MAX98090_0x3B_LOUT_R_CNTL, 0x00}, + {MAX98090_0x3C_LOUT_R_VOL, 0x15}, + + /* JACK DETECT AND ENABLE REGISTERS */ + {MAX98090_0x3D_JACK_DETECT, 0x00}, + {MAX98090_0x3E_IN_ENABLE, 0x00}, + {MAX98090_0x3F_OUT_ENABLE, 0x00}, + {MAX98090_0x40_LVL_CTR, 0x00}, + {MAX98090_0x41_DSP_FILTER_ENABLE, 0x00}, + + /* BIAS AND POWER MODE CONFIGURATION REGISTERS */ + {MAX98090_0x42_BIAS_CTR, 0x00}, + {MAX98090_0x43_DAC_CTR, 0x00}, + {MAX98090_0x44_ADC_CTR, 0x06}, + {MAX98090_0x45_DEV_SHUTDOWN, 0x00}, +}; + +static const unsigned int max98090_hp_tlv[] = { + TLV_DB_RANGE_HEAD(5), + 0x0, 0x6, TLV_DB_SCALE_ITEM(-6700, 400, 0), + 0x7, 0xE, TLV_DB_SCALE_ITEM(-4000, 300, 0), + 0xF, 0x15, TLV_DB_SCALE_ITEM(-1700, 200, 0), + 0x16, 0x1B, TLV_DB_SCALE_ITEM(-400, 100, 0), + 0x1C, 0x1F, TLV_DB_SCALE_ITEM(150, 50, 0), +}; + +static struct snd_kcontrol_new max98090_snd_controls[] = { + SOC_DOUBLE_R_TLV("Headphone Volume", MAX98090_0x2C_L_HP_VOL, + MAX98090_0x2D_R_HP_VOL, 0, 31, 0, max98090_hp_tlv), +}; + +/* Left HeadPhone Mixer Switch */ +static struct snd_kcontrol_new max98090_left_hp_mixer_controls[] = { + SOC_DAPM_SINGLE("DACR Switch", MAX98090_0x29_L_HP_MIX, 1, 1, 0), + SOC_DAPM_SINGLE("DACL Switch", MAX98090_0x29_L_HP_MIX, 0, 1, 0), +}; + +/* Right HeadPhone Mixer Switch */ +static struct snd_kcontrol_new max98090_right_hp_mixer_controls[] = { + SOC_DAPM_SINGLE("DACR Switch", MAX98090_0x2A_R_HP_MIX, 1, 1, 0), + SOC_DAPM_SINGLE("DACL Switch", MAX98090_0x2A_R_HP_MIX, 0, 1, 0), +}; + +static struct snd_soc_dapm_widget max98090_dapm_widgets[] = { + /* Output */ + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), + + /* PGA */ + SND_SOC_DAPM_PGA("HPL Out", MAX98090_0x3F_OUT_ENABLE, 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPR Out", MAX98090_0x3F_OUT_ENABLE, 6, 0, NULL, 0), + + /* Mixer */ + SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0, + max98090_left_hp_mixer_controls, + ARRAY_SIZE(max98090_left_hp_mixer_controls)), + + SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0, + max98090_right_hp_mixer_controls, + ARRAY_SIZE(max98090_right_hp_mixer_controls)), + + /* DAC */ + SND_SOC_DAPM_DAC("DACL", "Hifi Playback", MAX98090_0x3F_OUT_ENABLE, 0, 0), + SND_SOC_DAPM_DAC("DACR", "Hifi Playback", MAX98090_0x3F_OUT_ENABLE, 1, 0), +}; + +static struct snd_soc_dapm_route max98090_audio_map[] = { + /* Output */ + {"HPL", NULL, "HPL Out"}, + {"HPR", NULL, "HPR Out"}, + + /* PGA */ + {"HPL Out", NULL, "HPL Mixer"}, + {"HPR Out", NULL, "HPR Mixer"}, + + /* Mixer*/ + {"HPL Mixer", "DACR Switch", "DACR"}, + {"HPL Mixer", "DACL Switch", "DACL"}, + + {"HPR Mixer", "DACR Switch", "DACR"}, + {"HPR Mixer", "DACL Switch", "DACL"}, +}; + +static bool max98090_volatile(struct device *dev, unsigned int reg) +{ + if ((reg == MAX98090_0x01_INT_STS) || + (reg == MAX98090_0x02_JACK_STS) || + (reg > MAX98090_REG_MAX_CACHED)) + return true; + + return false; +} + +static int max98090_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val; + + switch (params_rate(params)) { + case 96000: + val = 1 << 5; + break; + case 32000: + val = 1 << 4; + break; + case 48000: + val = 1 << 3; + break; + case 44100: + val = 1 << 2; + break; + case 16000: + val = 1 << 1; + break; + case 8000: + val = 1 << 0; + break; + default: + dev_err(codec->dev, "unsupported rate\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, MAX98090_0x05_SAMPLE_RATE, 0x03F, val); + + return 0; +} + +static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val; + + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, 0); + + switch (freq) { + case 26000000: + val = 1 << 7; + break; + case 19200000: + val = 1 << 6; + break; + case 13000000: + val = 1 << 5; + break; + case 12288000: + val = 1 << 4; + break; + case 12000000: + val = 1 << 3; + break; + case 11289600: + val = 1 << 2; + break; + default: + dev_err(codec->dev, "Invalid master clock frequency\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, MAX98090_0x04_SYS_CLK, 0xFD, val); + + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, MAX98090_SHDNRUN); + + dev_dbg(dai->dev, "sysclk is %uHz\n", freq); + + return 0; +} + +static int max98090_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + int is_master; + u8 val; + + /* master/slave mode */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + is_master = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + is_master = 0; + break; + default: + dev_err(codec->dev, "unsupported clock\n"); + return -EINVAL; + } + + /* format */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_I2S: + val = (is_master) ? MAX98090_I2S_M : MAX98090_I2S_S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val = (is_master) ? MAX98090_RJ_M : MAX98090_RJ_S; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = (is_master) ? MAX98090_LJ_M : MAX98090_LJ_S; + break; + default: + dev_err(codec->dev, "unsupported format\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, MAX98090_0x06_DAI_IF, + MAX98090_DAI_IF_MASK, val); + + return 0; +} + +#define MAX98090_RATES SNDRV_PCM_RATE_8000_96000 +#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops max98090_dai_ops = { + .set_sysclk = max98090_dai_set_sysclk, + .set_fmt = max98090_dai_set_fmt, + .hw_params = max98090_dai_hw_params, +}; + +static struct snd_soc_dai_driver max98090_dai = { + .name = "max98090-Hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98090_RATES, + .formats = MAX98090_FORMATS, + }, + .ops = &max98090_dai_ops, +}; + +static int max98090_probe(struct snd_soc_codec *codec) +{ + struct max98090_priv *priv = snd_soc_codec_get_drvdata(codec); + struct device *dev = codec->dev; + int ret; + + codec->control_data = priv->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); + if (ret < 0) { + dev_err(dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + /* Device active */ + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, MAX98090_SHDNRUN); + + return 0; +} + +static int max98090_remove(struct snd_soc_codec *codec) +{ + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_max98090 = { + .probe = max98090_probe, + .remove = max98090_remove, + .controls = max98090_snd_controls, + .num_controls = ARRAY_SIZE(max98090_snd_controls), + .dapm_widgets = max98090_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98090_dapm_widgets), + .dapm_routes = max98090_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98090_audio_map), +}; + +static const struct regmap_config max98090_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX98090_REG_END, + .volatile_reg = max98090_volatile, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = max98090_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(max98090_reg_defaults), +}; + +static int max98090_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max98090_priv *priv; + struct device *dev = &i2c->dev; + unsigned int val; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct max98090_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(dev, "Failed to init regmap: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c, priv); + + ret = regmap_read(priv->regmap, MAX98090_0xFF_REV_ID, &val); + if (ret < 0) { + dev_err(dev, "Failed to read device revision: %d\n", ret); + return ret; + } + dev_info(dev, "revision 0x%02x\n", val); + + ret = snd_soc_register_codec(dev, + &soc_codec_dev_max98090, + &max98090_dai, 1); + + return ret; +} + +static int max98090_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max98090_i2c_id[] = { + { "max98090", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); + +static struct i2c_driver max98090_i2c_driver = { + .driver = { + .name = "max98090", + .owner = THIS_MODULE, + }, + .probe = max98090_i2c_probe, + .remove = max98090_i2c_remove, + .id_table = max98090_i2c_id, +}; +module_i2c_driver(max98090_i2c_driver); + +MODULE_DESCRIPTION("ALSA SoC MAX98090 driver"); +MODULE_AUTHOR("Peter Hsiang, Kuninori Morimoto"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 960d0e93cce9..d6ca615489ee 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1382,7 +1382,7 @@ static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream, timesofbclk); if (coeff < 0) { dev_err(codec->dev, "Fail to get coeff\n"); - return -EINVAL; + return coeff; } switch (params_format(params)) { diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c new file mode 100644 index 000000000000..38145ba74db8 --- /dev/null +++ b/sound/soc/codecs/si476x.c @@ -0,0 +1,255 @@ +#include <linux/module.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> + +#include <linux/i2c.h> + +#include <linux/mfd/si476x-core.h> + +enum si476x_audio_registers { + SI476X_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, + SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, +}; + +enum si476x_digital_io_output_format { + SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT = 11, + SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT = 8, +}; + +#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK ((0b111 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \ + (0b111 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)) +#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK (0b1111110) + +enum si476x_daudio_formats { + SI476X_DAUDIO_MODE_I2S = (0x0 << 1), + SI476X_DAUDIO_MODE_DSP_A = (0x6 << 1), + SI476X_DAUDIO_MODE_DSP_B = (0x7 << 1), + SI476X_DAUDIO_MODE_LEFT_J = (0x8 << 1), + SI476X_DAUDIO_MODE_RIGHT_J = (0x9 << 1), + + SI476X_DAUDIO_MODE_IB = (1 << 5), + SI476X_DAUDIO_MODE_IF = (1 << 6), +}; + +enum si476x_pcm_format { + SI476X_PCM_FORMAT_S8 = 2, + SI476X_PCM_FORMAT_S16_LE = 4, + SI476X_PCM_FORMAT_S20_3LE = 5, + SI476X_PCM_FORMAT_S24_LE = 6, +}; + +static unsigned int si476x_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + int err; + struct si476x_core *core = codec->control_data; + + si476x_core_lock(core); + err = si476x_core_cmd_get_property(core, reg); + si476x_core_unlock(core); + + return err; +} + +static int si476x_codec_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val) +{ + int err; + struct si476x_core *core = codec->control_data; + + si476x_core_lock(core); + err = si476x_core_cmd_set_property(core, reg, val); + si476x_core_unlock(core); + + return err; +} + +static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + int err; + u16 format = 0; + + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + return -EINVAL; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + format |= SI476X_DAUDIO_MODE_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + format |= SI476X_DAUDIO_MODE_DSP_B; + break; + case SND_SOC_DAIFMT_I2S: + format |= SI476X_DAUDIO_MODE_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + format |= SI476X_DAUDIO_MODE_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + format |= SI476X_DAUDIO_MODE_LEFT_J; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + format |= SI476X_DAUDIO_MODE_IB; + break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + format |= SI476X_DAUDIO_MODE_IB | + SI476X_DAUDIO_MODE_IF; + break; + case SND_SOC_DAIFMT_IB_NF: + format |= SI476X_DAUDIO_MODE_IB; + break; + case SND_SOC_DAIFMT_NB_IF: + format |= SI476X_DAUDIO_MODE_IF; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, + SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK, + format); + if (err < 0) { + dev_err(codec_dai->codec->dev, "Failed to set output format\n"); + return err; + } + + return 0; +} + +static int si476x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int rate, width, err; + + rate = params_rate(params); + if (rate < 32000 || rate > 48000) { + dev_err(dai->codec->dev, "Rate: %d is not supported\n", rate); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + width = SI476X_PCM_FORMAT_S8; + case SNDRV_PCM_FORMAT_S16_LE: + width = SI476X_PCM_FORMAT_S16_LE; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + width = SI476X_PCM_FORMAT_S20_3LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + width = SI476X_PCM_FORMAT_S24_LE; + break; + default: + return -EINVAL; + } + + err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE, + rate); + if (err < 0) { + dev_err(dai->codec->dev, "Failed to set sample rate\n"); + return err; + } + + err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, + SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK, + (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | + (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)); + if (err < 0) { + dev_err(dai->codec->dev, "Failed to set output width\n"); + return err; + } + + return 0; +} + +static int si476x_codec_probe(struct snd_soc_codec *codec) +{ + codec->control_data = i2c_mfd_cell_to_core(codec->dev); + return 0; +} + +static struct snd_soc_dai_ops si476x_dai_ops = { + .hw_params = si476x_codec_hw_params, + .set_fmt = si476x_codec_set_dai_fmt, +}; + +static struct snd_soc_dai_driver si476x_dai = { + .name = "si476x-codec", + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE + }, + .ops = &si476x_dai_ops, +}; + +static struct snd_soc_codec_driver soc_codec_dev_si476x = { + .probe = si476x_codec_probe, + .read = si476x_codec_read, + .write = si476x_codec_write, +}; + +static int __devinit si476x_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_si476x, + &si476x_dai, 1); +} + +static int __devexit si476x_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +MODULE_ALIAS("platform:si476x-codec"); + +static struct platform_driver si476x_platform_driver = { + .driver = { + .name = "si476x-codec", + .owner = THIS_MODULE, + }, + .probe = si476x_platform_probe, + .remove = __devexit_p(si476x_platform_remove), +}; +module_platform_driver(si476x_platform_driver); + +MODULE_AUTHOR("Andrey Smirnov <andrey.smirnov@convergeddevices.net>"); +MODULE_DESCRIPTION("ASoC Si4761/64 codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index f230292ba96b..e39e08d5d8e4 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -28,6 +28,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/cdev.h> #include <linux/slab.h> @@ -65,6 +66,7 @@ struct aic32x4_priv { u32 power_cfg; u32 micpga_routing; bool swapdacs; + int rstn_gpio; }; /* 0dB min, 1dB steps */ @@ -627,10 +629,20 @@ static int aic32x4_probe(struct snd_soc_codec *codec) { struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); u32 tmp_reg; + int ret; codec->hw_write = (hw_write_t) i2c_master_send; codec->control_data = aic32x4->control_data; + if (aic32x4->rstn_gpio >= 0) { + ret = devm_gpio_request_one(codec->dev, aic32x4->rstn_gpio, + GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); + if (ret != 0) + return ret; + ndelay(10); + gpio_set_value(aic32x4->rstn_gpio, 1); + } + snd_soc_write(codec, AIC32X4_RESET, 0x01); /* Power platform configuration */ @@ -675,6 +687,16 @@ static int aic32x4_probe(struct snd_soc_codec *codec) ARRAY_SIZE(aic32x4_snd_controls)); aic32x4_add_widgets(codec); + /* + * Workaround: for an unknown reason, the ADC needs to be powered up + * and down for the first capture to work properly. It seems related to + * a HW BUG or some kind of behavior not documented in the datasheet. + */ + tmp_reg = snd_soc_read(codec, AIC32X4_ADCSETUP); + snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg | + AIC32X4_LADC_EN | AIC32X4_RADC_EN); + snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg); + return 0; } @@ -713,10 +735,12 @@ static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->power_cfg = pdata->power_cfg; aic32x4->swapdacs = pdata->swapdacs; aic32x4->micpga_routing = pdata->micpga_routing; + aic32x4->rstn_gpio = pdata->rstn_gpio; } else { aic32x4->power_cfg = 0; aic32x4->swapdacs = false; aic32x4->micpga_routing = 0; + aic32x4->rstn_gpio = -1; } ret = snd_soc_register_codec(&i2c->dev, diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index aae2b2440398..35774223fd91 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -94,6 +94,9 @@ #define AIC32X4_WORD_LEN_24BITS 0x02 #define AIC32X4_WORD_LEN_32BITS 0x03 +#define AIC32X4_LADC_EN (1 << 7) +#define AIC32X4_RADC_EN (1 << 6) + #define AIC32X4_I2S_MODE 0x00 #define AIC32X4_DSP_MODE 0x01 #define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02 diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 99afc003a084..40256b526259 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -31,6 +31,9 @@ #define DEVICE_ID_WM0010 10 +/* We only support v1 of the .dfw INFO record */ +#define INFO_VERSION 1 + enum dfw_cmd { DFW_CMD_FUSE = 0x01, DFW_CMD_CODE_HDR, @@ -46,6 +49,13 @@ struct dfw_binrec { uint8_t data[0]; } __packed; +struct dfw_inforec { + u8 info_version; + u8 tool_major_version; + u8 tool_minor_version; + u8 dsp_target; +}; + struct dfw_pllrec { u8 command; u32 length:24; @@ -97,7 +107,6 @@ struct wm0010_priv { enum wm0010_state state; bool boot_failed; - int boot_done; bool ready; bool pll_running; int max_spi_freq; @@ -234,7 +243,7 @@ static void wm0010_boot_xfer_complete(void *data) break; case 0x55555555: - if (wm0010->boot_done == 0) + if (wm0010->state < WM0010_STAGE2) break; dev_err(codec->dev, "%d: ROM bootloader running in stage 2\n", i); @@ -321,7 +330,6 @@ static void wm0010_boot_xfer_complete(void *data) break; } - wm0010->boot_done++; if (xfer->done) complete(xfer->done); } @@ -334,94 +342,198 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len) data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i])); } -static int wm0010_boot(struct snd_soc_codec *codec) +static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec) { struct spi_device *spi = to_spi_device(codec->dev); struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); - unsigned long flags; struct list_head xfer_list; struct wm0010_boot_xfer *xfer; int ret; struct completion done; const struct firmware *fw; const struct dfw_binrec *rec; - struct spi_message m; - struct spi_transfer t; - struct dfw_pllrec pll_rec; - u32 *img, *p; - u64 *img_swap; - u8 *out; + const struct dfw_inforec *inforec; + u64 *img; + u8 *out, dsp; u32 len, offset; - int i; - spin_lock_irqsave(&wm0010->irq_lock, flags); - if (wm0010->state != WM0010_POWER_OFF) - dev_warn(wm0010->dev, "DSP already powered up!\n"); - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + INIT_LIST_HEAD(&xfer_list); - if (wm0010->sysclk > 26000000) { - dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n"); - ret = -ECANCELED; - goto err; + ret = request_firmware(&fw, name, codec->dev); + if (ret != 0) { + dev_err(codec->dev, "Failed to request application: %d\n", + ret); + return ret; } - INIT_LIST_HEAD(&xfer_list); + rec = (const struct dfw_binrec *)fw->data; + inforec = (const struct dfw_inforec *)rec->data; + offset = 0; + dsp = inforec->dsp_target; + wm0010->boot_failed = false; + BUG_ON(!list_empty(&xfer_list)); + init_completion(&done); - mutex_lock(&wm0010->lock); - wm0010->pll_running = false; + /* First record should be INFO */ + if (rec->command != DFW_CMD_INFO) { + dev_err(codec->dev, "First record not INFO\r\n"); + ret = -EINVAL; + goto abort; + } - dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq); + if (inforec->info_version != INFO_VERSION) { + dev_err(codec->dev, + "Unsupported version (%02d) of INFO record\r\n", + inforec->info_version); + ret = -EINVAL; + goto abort; + } - ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies), - wm0010->core_supplies); - if (ret != 0) { - dev_err(&spi->dev, "Failed to enable core supplies: %d\n", - ret); - mutex_unlock(&wm0010->lock); - goto err; + dev_dbg(codec->dev, "Version v%02d INFO record found\r\n", + inforec->info_version); + + /* Check it's a DSP file */ + if (dsp != DEVICE_ID_WM0010) { + dev_err(codec->dev, "Not a WM0010 firmware file.\r\n"); + ret = -EINVAL; + goto abort; } - ret = regulator_enable(wm0010->dbvdd); - if (ret != 0) { - dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret); - goto err_core; + /* Skip the info record as we don't need to send it */ + offset += ((rec->length) + 8); + rec = (void *)&rec->data[rec->length]; + + while (offset < fw->size) { + dev_dbg(codec->dev, + "Packet: command %d, data length = 0x%x\r\n", + rec->command, rec->length); + len = rec->length + 8; + + out = kzalloc(len, GFP_KERNEL); + if (!out) { + dev_err(codec->dev, + "Failed to allocate RX buffer\n"); + ret = -ENOMEM; + goto abort1; + } + + img = kzalloc(len, GFP_KERNEL); + if (!img) { + dev_err(codec->dev, + "Failed to allocate image buffer\n"); + ret = -ENOMEM; + goto abort1; + } + + byte_swap_64((u64 *)&rec->command, img, len); + + xfer = kzalloc(sizeof(*xfer), GFP_KERNEL); + if (!xfer) { + dev_err(codec->dev, "Failed to allocate xfer\n"); + ret = -ENOMEM; + goto abort1; + } + + xfer->codec = codec; + list_add_tail(&xfer->list, &xfer_list); + + spi_message_init(&xfer->m); + xfer->m.complete = wm0010_boot_xfer_complete; + xfer->m.context = xfer; + xfer->t.tx_buf = img; + xfer->t.rx_buf = out; + xfer->t.len = len; + xfer->t.bits_per_word = 8; + + if (!wm0010->pll_running) { + xfer->t.speed_hz = wm0010->sysclk / 6; + } else { + xfer->t.speed_hz = wm0010->max_spi_freq; + + if (wm0010->board_max_spi_speed && + (wm0010->board_max_spi_speed < wm0010->max_spi_freq)) + xfer->t.speed_hz = wm0010->board_max_spi_speed; + } + + /* Store max usable spi frequency for later use */ + wm0010->max_spi_freq = xfer->t.speed_hz; + + spi_message_add_tail(&xfer->t, &xfer->m); + + offset += ((rec->length) + 8); + rec = (void *)&rec->data[rec->length]; + + if (offset >= fw->size) { + dev_dbg(codec->dev, "All transfers scheduled\n"); + xfer->done = &done; + } + + ret = spi_async(spi, &xfer->m); + if (ret != 0) { + dev_err(codec->dev, "Write failed: %d\n", ret); + goto abort1; + } + + if (wm0010->boot_failed) { + dev_dbg(codec->dev, "Boot fail!\n"); + ret = -EINVAL; + goto abort1; + } } - /* Release reset */ - gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value); - spin_lock_irqsave(&wm0010->irq_lock, flags); - wm0010->state = WM0010_OUT_OF_RESET; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + wait_for_completion(&done); + + ret = 0; + +abort1: + while (!list_empty(&xfer_list)) { + xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer, + list); + kfree(xfer->t.rx_buf); + kfree(xfer->t.tx_buf); + list_del(&xfer->list); + kfree(xfer); + } + +abort: + release_firmware(fw); + return ret; +} + +static int wm0010_stage2_load(struct snd_soc_codec *codec) +{ + struct spi_device *spi = to_spi_device(codec->dev); + struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); + const struct firmware *fw; + struct spi_message m; + struct spi_transfer t; + u32 *img; + u8 *out; + int i; + int ret = 0; - /* First the bootloader */ ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev); if (ret != 0) { dev_err(codec->dev, "Failed to request stage2 loader: %d\n", ret); - goto abort; + return ret; } - if (!wait_for_completion_timeout(&wm0010->boot_completion, - msecs_to_jiffies(10))) - dev_err(codec->dev, "Failed to get interrupt from DSP\n"); - - spin_lock_irqsave(&wm0010->irq_lock, flags); - wm0010->state = WM0010_BOOTROM; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); - dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size); /* Copy to local buffer first as vmalloc causes problems for dma */ img = kzalloc(fw->size, GFP_KERNEL); if (!img) { dev_err(codec->dev, "Failed to allocate image buffer\n"); - goto abort; + ret = -ENOMEM; + goto abort2; } out = kzalloc(fw->size, GFP_KERNEL); if (!out) { dev_err(codec->dev, "Failed to allocate output buffer\n"); - goto abort; + ret = -ENOMEM; + goto abort1; } memcpy(img, &fw->data[0], fw->size); @@ -447,20 +559,97 @@ static int wm0010_boot(struct snd_soc_codec *codec) /* Look for errors from the boot ROM */ for (i = 0; i < fw->size; i++) { if (out[i] != 0x55) { - ret = -EBUSY; dev_err(codec->dev, "Boot ROM error: %x in %d\n", out[i], i); wm0010_mark_boot_failure(wm0010); + ret = -EBUSY; goto abort; } } - - release_firmware(fw); - kfree(img); +abort: kfree(out); +abort1: + kfree(img); +abort2: + release_firmware(fw); + + return ret; +} + +static int wm0010_boot(struct snd_soc_codec *codec) +{ + struct spi_device *spi = to_spi_device(codec->dev); + struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); + unsigned long flags; + int ret; + const struct firmware *fw; + struct spi_message m; + struct spi_transfer t; + struct dfw_pllrec pll_rec; + u32 *p, len; + u64 *img_swap; + u8 *out; + int i; + + spin_lock_irqsave(&wm0010->irq_lock, flags); + if (wm0010->state != WM0010_POWER_OFF) + dev_warn(wm0010->dev, "DSP already powered up!\n"); + spin_unlock_irqrestore(&wm0010->irq_lock, flags); + + if (wm0010->sysclk > 26000000) { + dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n"); + ret = -ECANCELED; + goto err; + } + + mutex_lock(&wm0010->lock); + wm0010->pll_running = false; + + dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq); + + ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies), + wm0010->core_supplies); + if (ret != 0) { + dev_err(&spi->dev, "Failed to enable core supplies: %d\n", + ret); + mutex_unlock(&wm0010->lock); + goto err; + } + + ret = regulator_enable(wm0010->dbvdd); + if (ret != 0) { + dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret); + goto err_core; + } + + /* Release reset */ + gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value); + spin_lock_irqsave(&wm0010->irq_lock, flags); + wm0010->state = WM0010_OUT_OF_RESET; + spin_unlock_irqrestore(&wm0010->irq_lock, flags); + + /* First the bootloader */ + ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev); + if (ret != 0) { + dev_err(codec->dev, "Failed to request stage2 loader: %d\n", + ret); + goto abort; + } + + if (!wait_for_completion_timeout(&wm0010->boot_completion, + msecs_to_jiffies(20))) + dev_err(codec->dev, "Failed to get interrupt from DSP\n"); + + spin_lock_irqsave(&wm0010->irq_lock, flags); + wm0010->state = WM0010_BOOTROM; + spin_unlock_irqrestore(&wm0010->irq_lock, flags); + + ret = wm0010_stage2_load(codec); + if (ret) + goto abort; if (!wait_for_completion_timeout(&wm0010->boot_completion, - msecs_to_jiffies(10))) + msecs_to_jiffies(20))) dev_err(codec->dev, "Failed to get interrupt from DSP loader.\n"); spin_lock_irqsave(&wm0010->irq_lock, flags); @@ -535,110 +724,10 @@ static int wm0010_boot(struct snd_soc_codec *codec) } else dev_dbg(codec->dev, "Not enabling DSP PLL."); - ret = request_firmware(&fw, "wm0010.dfw", codec->dev); - if (ret != 0) { - dev_err(codec->dev, "Failed to request application: %d\n", - ret); - goto abort; - } - - rec = (const struct dfw_binrec *)fw->data; - offset = 0; - wm0010->boot_done = 0; - wm0010->boot_failed = false; - BUG_ON(!list_empty(&xfer_list)); - init_completion(&done); + ret = wm0010_firmware_load("wm0010.dfw", codec); - /* First record should be INFO */ - if (rec->command != DFW_CMD_INFO) { - dev_err(codec->dev, "First record not INFO\r\n"); - goto abort; - } - - /* Check it's a 0010 file */ - if (rec->data[0] != DEVICE_ID_WM0010) { - dev_err(codec->dev, "Not a WM0010 firmware file.\r\n"); + if (ret != 0) goto abort; - } - - /* Skip the info record as we don't need to send it */ - offset += ((rec->length) + 8); - rec = (void *)&rec->data[rec->length]; - - while (offset < fw->size) { - dev_dbg(codec->dev, - "Packet: command %d, data length = 0x%x\r\n", - rec->command, rec->length); - len = rec->length + 8; - - out = kzalloc(len, GFP_KERNEL); - if (!out) { - dev_err(codec->dev, - "Failed to allocate RX buffer\n"); - goto abort; - } - - img_swap = kzalloc(len, GFP_KERNEL); - if (!img_swap) { - dev_err(codec->dev, - "Failed to allocate image buffer\n"); - goto abort; - } - - /* We need to re-order for 0010 */ - byte_swap_64((u64 *)&rec->command, img_swap, len); - - xfer = kzalloc(sizeof(*xfer), GFP_KERNEL); - if (!xfer) { - dev_err(codec->dev, "Failed to allocate xfer\n"); - goto abort; - } - - xfer->codec = codec; - list_add_tail(&xfer->list, &xfer_list); - - spi_message_init(&xfer->m); - xfer->m.complete = wm0010_boot_xfer_complete; - xfer->m.context = xfer; - xfer->t.tx_buf = img_swap; - xfer->t.rx_buf = out; - xfer->t.len = len; - xfer->t.bits_per_word = 8; - - if (!wm0010->pll_running) { - xfer->t.speed_hz = wm0010->sysclk / 6; - } else { - xfer->t.speed_hz = wm0010->max_spi_freq; - - if (wm0010->board_max_spi_speed && - (wm0010->board_max_spi_speed < wm0010->max_spi_freq)) - xfer->t.speed_hz = wm0010->board_max_spi_speed; - } - - /* Store max usable spi frequency for later use */ - wm0010->max_spi_freq = xfer->t.speed_hz; - - spi_message_add_tail(&xfer->t, &xfer->m); - - offset += ((rec->length) + 8); - rec = (void *)&rec->data[rec->length]; - - if (offset >= fw->size) { - dev_dbg(codec->dev, "All transfers scheduled\n"); - xfer->done = &done; - } - - ret = spi_async(spi, &xfer->m); - if (ret != 0) { - dev_err(codec->dev, "Write failed: %d\n", ret); - goto abort; - } - - if (wm0010->boot_failed) - goto abort; - } - - wait_for_completion(&done); spin_lock_irqsave(&wm0010->irq_lock, flags); wm0010->state = WM0010_FIRMWARE; @@ -646,17 +735,6 @@ static int wm0010_boot(struct snd_soc_codec *codec) mutex_unlock(&wm0010->lock); - release_firmware(fw); - - while (!list_empty(&xfer_list)) { - xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer, - list); - kfree(xfer->t.rx_buf); - kfree(xfer->t.tx_buf); - list_del(&xfer->list); - kfree(xfer); - } - return 0; abort: @@ -784,7 +862,6 @@ static irqreturn_t wm0010_irq(int irq, void *data) struct wm0010_priv *wm0010 = data; switch (wm0010->state) { - case WM0010_POWER_OFF: case WM0010_OUT_OF_RESET: case WM0010_BOOTROM: case WM0010_STAGE2: diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 683dc43b1d87..02750ab020de 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -646,7 +646,7 @@ static const struct snd_kcontrol_new wm2000_controls[] = { static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = w->codec; struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); if (SND_SOC_DAPM_EVENT_ON(event)) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index eab64a193989..ff45b02a9dff 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/firmware.h> #include <linux/gcd.h> #include <linux/gpio.h> #include <linux/i2c.h> @@ -32,6 +33,40 @@ #include <sound/wm2200.h> #include "wm2200.h" +#include "wmfw.h" +#include "wm_adsp.h" + +#define WM2200_DSP_CONTROL_1 0x00 +#define WM2200_DSP_CONTROL_2 0x02 +#define WM2200_DSP_CONTROL_3 0x03 +#define WM2200_DSP_CONTROL_4 0x04 +#define WM2200_DSP_CONTROL_5 0x06 +#define WM2200_DSP_CONTROL_6 0x07 +#define WM2200_DSP_CONTROL_7 0x08 +#define WM2200_DSP_CONTROL_8 0x09 +#define WM2200_DSP_CONTROL_9 0x0A +#define WM2200_DSP_CONTROL_10 0x0B +#define WM2200_DSP_CONTROL_11 0x0C +#define WM2200_DSP_CONTROL_12 0x0D +#define WM2200_DSP_CONTROL_13 0x0F +#define WM2200_DSP_CONTROL_14 0x10 +#define WM2200_DSP_CONTROL_15 0x11 +#define WM2200_DSP_CONTROL_16 0x12 +#define WM2200_DSP_CONTROL_17 0x13 +#define WM2200_DSP_CONTROL_18 0x14 +#define WM2200_DSP_CONTROL_19 0x16 +#define WM2200_DSP_CONTROL_20 0x17 +#define WM2200_DSP_CONTROL_21 0x18 +#define WM2200_DSP_CONTROL_22 0x1A +#define WM2200_DSP_CONTROL_23 0x1B +#define WM2200_DSP_CONTROL_24 0x1C +#define WM2200_DSP_CONTROL_25 0x1E +#define WM2200_DSP_CONTROL_26 0x20 +#define WM2200_DSP_CONTROL_27 0x21 +#define WM2200_DSP_CONTROL_28 0x22 +#define WM2200_DSP_CONTROL_29 0x23 +#define WM2200_DSP_CONTROL_30 0x24 +#define WM2200_DSP_CONTROL_31 0x26 /* The code assumes DCVDD is generated internally */ #define WM2200_NUM_CORE_SUPPLIES 2 @@ -49,6 +84,7 @@ struct wm2200_fll { /* codec private data */ struct wm2200_priv { + struct wm_adsp dsp[2]; struct regmap *regmap; struct device *dev; struct snd_soc_codec *codec; @@ -64,6 +100,72 @@ struct wm2200_priv { int sysclk; }; +#define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1) +#define WM2200_DSP_SPACING 12288 + +#define WM2200_DSP1_DM_BASE (WM2200_DSP_RANGE_BASE + (0 * WM2200_DSP_SPACING)) +#define WM2200_DSP1_PM_BASE (WM2200_DSP_RANGE_BASE + (1 * WM2200_DSP_SPACING)) +#define WM2200_DSP1_ZM_BASE (WM2200_DSP_RANGE_BASE + (2 * WM2200_DSP_SPACING)) +#define WM2200_DSP2_DM_BASE (WM2200_DSP_RANGE_BASE + (3 * WM2200_DSP_SPACING)) +#define WM2200_DSP2_PM_BASE (WM2200_DSP_RANGE_BASE + (4 * WM2200_DSP_SPACING)) +#define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING)) + +static const struct regmap_range_cfg wm2200_ranges[] = { + { .name = "DSP1DM", .range_min = WM2200_DSP1_DM_BASE, + .range_max = WM2200_DSP1_DM_BASE + 12287, + .selector_reg = WM2200_DSP1_CONTROL_3, + .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK, + .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT, + .window_start = WM2200_DSP1_DM_0, .window_len = 2048, }, + + { .name = "DSP1PM", .range_min = WM2200_DSP1_PM_BASE, + .range_max = WM2200_DSP1_PM_BASE + 12287, + .selector_reg = WM2200_DSP1_CONTROL_2, + .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK, + .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT, + .window_start = WM2200_DSP1_PM_0, .window_len = 768, }, + + { .name = "DSP1ZM", .range_min = WM2200_DSP1_ZM_BASE, + .range_max = WM2200_DSP1_ZM_BASE + 2047, + .selector_reg = WM2200_DSP1_CONTROL_4, + .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK, + .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT, + .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, }, + + { .name = "DSP2DM", .range_min = WM2200_DSP2_DM_BASE, + .range_max = WM2200_DSP2_DM_BASE + 4095, + .selector_reg = WM2200_DSP2_CONTROL_3, + .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK, + .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT, + .window_start = WM2200_DSP2_DM_0, .window_len = 2048, }, + + { .name = "DSP2PM", .range_min = WM2200_DSP2_PM_BASE, + .range_max = WM2200_DSP2_PM_BASE + 11287, + .selector_reg = WM2200_DSP2_CONTROL_2, + .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK, + .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT, + .window_start = WM2200_DSP2_PM_0, .window_len = 768, }, + + { .name = "DSP2ZM", .range_min = WM2200_DSP2_ZM_BASE, + .range_max = WM2200_DSP2_ZM_BASE + 2047, + .selector_reg = WM2200_DSP2_CONTROL_4, + .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK, + .selector_shift = WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT, + .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, }, +}; + +static const struct wm_adsp_region wm2200_dsp1_regions[] = { + { .type = WMFW_ADSP1_PM, .base = WM2200_DSP1_PM_BASE }, + { .type = WMFW_ADSP1_DM, .base = WM2200_DSP1_DM_BASE }, + { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP1_ZM_BASE }, +}; + +static const struct wm_adsp_region wm2200_dsp2_regions[] = { + { .type = WMFW_ADSP1_PM, .base = WM2200_DSP2_PM_BASE }, + { .type = WMFW_ADSP1_DM, .base = WM2200_DSP2_DM_BASE }, + { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE }, +}; + static struct reg_default wm2200_reg_defaults[] = { { 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */ { 0x0102, 0x0000 }, /* R258 - Clocking 3 */ @@ -407,6 +509,16 @@ static struct reg_default wm2200_reg_defaults[] = { static bool wm2200_volatile_register(struct device *dev, unsigned int reg) { + int i; + + for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++) + if ((reg >= wm2200_ranges[i].window_start && + reg <= wm2200_ranges[i].window_start + + wm2200_ranges[i].window_len) || + (reg >= wm2200_ranges[i].range_min && + reg <= wm2200_ranges[i].range_max)) + return true; + switch (reg) { case WM2200_SOFTWARE_RESET: case WM2200_DEVICE_REVISION: @@ -423,6 +535,16 @@ static bool wm2200_volatile_register(struct device *dev, unsigned int reg) static bool wm2200_readable_register(struct device *dev, unsigned int reg) { + int i; + + for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++) + if ((reg >= wm2200_ranges[i].window_start && + reg <= wm2200_ranges[i].window_start + + wm2200_ranges[i].window_len) || + (reg >= wm2200_ranges[i].range_min && + reg <= wm2200_ranges[i].range_max)) + return true; + switch (reg) { case WM2200_SOFTWARE_RESET: case WM2200_DEVICE_REVISION: @@ -880,7 +1002,7 @@ static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); static const char *wm2200_mixer_texts[] = { "None", "Tone Generator", - "AEC loopback", + "AEC Loopback", "IN1L", "IN1R", "IN2L", @@ -976,6 +1098,20 @@ static int wm2200_mixer_values[] = { static WM2200_MUX_CTL_DECL(name##_in3); \ static WM2200_MUX_CTL_DECL(name##_in4) +#define WM2200_DSP_ENUMS(name, base_reg) \ + static WM2200_MUX_ENUM_DECL(name##_aux1_enum, base_reg); \ + static WM2200_MUX_ENUM_DECL(name##_aux2_enum, base_reg + 1); \ + static WM2200_MUX_ENUM_DECL(name##_aux3_enum, base_reg + 2); \ + static WM2200_MUX_ENUM_DECL(name##_aux4_enum, base_reg + 3); \ + static WM2200_MUX_ENUM_DECL(name##_aux5_enum, base_reg + 4); \ + static WM2200_MUX_ENUM_DECL(name##_aux6_enum, base_reg + 5); \ + static WM2200_MUX_CTL_DECL(name##_aux1); \ + static WM2200_MUX_CTL_DECL(name##_aux2); \ + static WM2200_MUX_CTL_DECL(name##_aux3); \ + static WM2200_MUX_CTL_DECL(name##_aux4); \ + static WM2200_MUX_CTL_DECL(name##_aux5); \ + static WM2200_MUX_CTL_DECL(name##_aux6); + static const struct snd_kcontrol_new wm2200_snd_controls[] = { SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL, WM2200_IN1_OSR_SHIFT, 1, 0), @@ -1051,6 +1187,9 @@ WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE); +WM2200_DSP_ENUMS(DSP1, WM2200_DSP1AUX1MIX_INPUT_1_SOURCE); +WM2200_DSP_ENUMS(DSP2, WM2200_DSP2AUX1MIX_INPUT_1_SOURCE); + WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); @@ -1064,8 +1203,19 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); WM2200_MUX(name_str " Input 4", &name##_in4_mux), \ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) +#define WM2200_DSP_WIDGETS(name, name_str) \ + WM2200_MIXER_WIDGETS(name##L, name_str "L"), \ + WM2200_MIXER_WIDGETS(name##R, name_str "R"), \ + WM2200_MUX(name_str " Aux 1", &name##_aux1_mux), \ + WM2200_MUX(name_str " Aux 2", &name##_aux2_mux), \ + WM2200_MUX(name_str " Aux 3", &name##_aux3_mux), \ + WM2200_MUX(name_str " Aux 4", &name##_aux4_mux), \ + WM2200_MUX(name_str " Aux 5", &name##_aux5_mux), \ + WM2200_MUX(name_str " Aux 6", &name##_aux6_mux) + #define WM2200_MIXER_INPUT_ROUTES(name) \ { name, "Tone Generator", "Tone Generator" }, \ + { name, "AEC Loopback", "AEC Loopback" }, \ { name, "IN1L", "IN1L PGA" }, \ { name, "IN1R", "IN1R PGA" }, \ { name, "IN2L", "IN2L PGA" }, \ @@ -1106,6 +1256,33 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \ WM2200_MIXER_INPUT_ROUTES(name " Input 4") +#define WM2200_DSP_AUX_ROUTES(name) \ + { name, NULL, name " Aux 1" }, \ + { name, NULL, name " Aux 2" }, \ + { name, NULL, name " Aux 3" }, \ + { name, NULL, name " Aux 4" }, \ + { name, NULL, name " Aux 5" }, \ + { name, NULL, name " Aux 6" }, \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 1"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 2"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 3"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 4"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 5"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 6") + +static const char *wm2200_aec_loopback_texts[] = { + "OUT1L", "OUT1R", "OUT2L", "OUT2R", +}; + +static const struct soc_enum wm2200_aec_loopback = + SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1, + WM2200_AEC_LOOPBACK_SRC_SHIFT, + ARRAY_SIZE(wm2200_aec_loopback_texts), + wm2200_aec_loopback_texts); + +static const struct snd_kcontrol_new wm2200_aec_loopback_mux = + SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback); + static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0, NULL, 0), @@ -1165,8 +1342,8 @@ SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0, SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_PGA_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), -SND_SOC_DAPM_PGA_E("DSP2", SND_SOC_NOPM, 1, 0, NULL, 0, NULL, 0), +WM_ADSP1("DSP1", 0), +WM_ADSP1("DSP2", 1), SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0), @@ -1181,6 +1358,9 @@ SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4, SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5, WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_MUX("AEC Loopback", WM2200_DAC_AEC_CONTROL_1, + WM2200_AEC_LOOPBACK_ENA_SHIFT, 0, &wm2200_aec_loopback_mux), + SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES, WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES, @@ -1231,10 +1411,8 @@ WM2200_MIXER_WIDGETS(EQR, "EQR"), WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"), WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"), -WM2200_MIXER_WIDGETS(DSP1L, "DSP1L"), -WM2200_MIXER_WIDGETS(DSP1R, "DSP1R"), -WM2200_MIXER_WIDGETS(DSP2L, "DSP2L"), -WM2200_MIXER_WIDGETS(DSP2R, "DSP2R"), +WM2200_DSP_WIDGETS(DSP1, "DSP1"), +WM2200_DSP_WIDGETS(DSP2, "DSP2"), WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), @@ -1326,11 +1504,19 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = { { "SPK", NULL, "OUT2L" }, { "SPK", NULL, "OUT2R" }, + { "AEC Loopback", "OUT1L", "OUT1L" }, + { "AEC Loopback", "OUT1R", "OUT1R" }, + { "AEC Loopback", "OUT2L", "OUT2L" }, + { "AEC Loopback", "OUT2R", "OUT2R" }, + WM2200_MIXER_ROUTES("DSP1", "DSP1L"), WM2200_MIXER_ROUTES("DSP1", "DSP1R"), WM2200_MIXER_ROUTES("DSP2", "DSP2L"), WM2200_MIXER_ROUTES("DSP2", "DSP2R"), + WM2200_DSP_AUX_ROUTES("DSP1"), + WM2200_DSP_AUX_ROUTES("DSP2"), + WM2200_MIXER_ROUTES("OUT1L", "OUT1L"), WM2200_MIXER_ROUTES("OUT1R", "OUT1R"), WM2200_MIXER_ROUTES("OUT2L", "OUT2L"), @@ -1968,12 +2154,15 @@ static const struct regmap_config wm2200_regmap = { .reg_bits = 16, .val_bits = 16, - .max_register = WM2200_MAX_REGISTER, + .max_register = WM2200_MAX_REGISTER + (ARRAY_SIZE(wm2200_ranges) * + WM2200_DSP_SPACING), .reg_defaults = wm2200_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults), .volatile_reg = wm2200_volatile_register, .readable_reg = wm2200_readable_register, .cache_type = REGCACHE_RBTREE, + .ranges = wm2200_ranges, + .num_ranges = ARRAY_SIZE(wm2200_ranges), }; static const unsigned int wm2200_dig_vu[] = { @@ -2011,14 +2200,30 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, wm2200->dev = &i2c->dev; init_completion(&wm2200->fll_lock); - wm2200->regmap = regmap_init_i2c(i2c, &wm2200_regmap); + wm2200->regmap = devm_regmap_init_i2c(i2c, &wm2200_regmap); if (IS_ERR(wm2200->regmap)) { ret = PTR_ERR(wm2200->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; + } + + for (i = 0; i < 2; i++) { + wm2200->dsp[i].type = WMFW_ADSP1; + wm2200->dsp[i].part = "wm2200"; + wm2200->dsp[i].num = i + 1; + wm2200->dsp[i].dev = &i2c->dev; + wm2200->dsp[i].regmap = wm2200->regmap; } + wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1; + wm2200->dsp[0].mem = wm2200_dsp1_regions; + wm2200->dsp[0].num_mems = ARRAY_SIZE(wm2200_dsp1_regions); + + wm2200->dsp[1].base = WM2200_DSP2_CONTROL_1; + wm2200->dsp[1].mem = wm2200_dsp2_regions; + wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions); + if (pdata) wm2200->pdata = *pdata; @@ -2027,12 +2232,13 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++) wm2200->core_supplies[i].supply = wm2200_core_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm2200->core_supplies), - wm2200->core_supplies); + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request core supplies: %d\n", ret); - goto err_regmap; + return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies), @@ -2040,12 +2246,13 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, if (ret != 0) { dev_err(&i2c->dev, "Failed to enable core supplies: %d\n", ret); - goto err_core; + return ret; } if (wm2200->pdata.ldo_ena) { - ret = gpio_request_one(wm2200->pdata.ldo_ena, - GPIOF_OUT_INIT_HIGH, "WM2200 LDOENA"); + ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena, + GPIOF_OUT_INIT_HIGH, + "WM2200 LDOENA"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n", wm2200->pdata.ldo_ena, ret); @@ -2055,8 +2262,9 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, } if (wm2200->pdata.reset) { - ret = gpio_request_one(wm2200->pdata.reset, - GPIOF_OUT_INIT_HIGH, "WM2200 /RESET"); + ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset, + GPIOF_OUT_INIT_HIGH, + "WM2200 /RESET"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n", wm2200->pdata.reset, ret); @@ -2166,24 +2374,14 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, err_pm_runtime: pm_runtime_disable(&i2c->dev); err_reset: - if (wm2200->pdata.reset) { + if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); - gpio_free(wm2200->pdata.reset); - } err_ldo: - if (wm2200->pdata.ldo_ena) { + if (wm2200->pdata.ldo_ena) gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); - gpio_free(wm2200->pdata.ldo_ena); - } err_enable: regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), wm2200->core_supplies); -err_core: - regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies), - wm2200->core_supplies); -err_regmap: - regmap_exit(wm2200->regmap); -err: return ret; } @@ -2194,17 +2392,10 @@ static __devexit int wm2200_i2c_remove(struct i2c_client *i2c) snd_soc_unregister_codec(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm2200); - if (wm2200->pdata.reset) { + if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); - gpio_free(wm2200->pdata.reset); - } - if (wm2200->pdata.ldo_ena) { + if (wm2200->pdata.ldo_ena) gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); - gpio_free(wm2200->pdata.ldo_ena); - } - regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies), - wm2200->core_supplies); - regmap_exit(wm2200->regmap); return 0; } diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 7f567585832e..9f57996ff272 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1233,7 +1233,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { { "PWM2", NULL, "PWM2 Driver" }, }; -static const __devinitconst struct reg_default wm5100_reva_patches[] = { +static const struct reg_default wm5100_reva_patches[] = { { WM5100_AUDIO_IF_1_10, 0 }, { WM5100_AUDIO_IF_1_11, 1 }, { WM5100_AUDIO_IF_1_12, 2 }, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 7394e73fa43c..27f7e38e7eca 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -31,6 +31,7 @@ #include "arizona.h" #include "wm5102.h" +#include "wm_adsp.h" struct wm5102_priv { struct arizona_priv core; @@ -42,6 +43,13 @@ 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 const struct wm_adsp_region wm5102_dsp1_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x100000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x180000 }, + { .type = WMFW_ADSP2_XM, .base = 0x190000 }, + { .type = WMFW_ADSP2_YM, .base = 0x1a8000 }, +}; + static const struct reg_default wm5102_sysclk_reva_patch[] = { { 0x3000, 0x2225 }, { 0x3001, 0x3a03 }, @@ -627,11 +635,23 @@ 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), + ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, + ARIZONA_EQ1_ENA_MASK), +SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, + ARIZONA_EQ2_ENA_MASK), +SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, + ARIZONA_EQ3_ENA_MASK), +SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, + ARIZONA_EQ4_ENA_MASK), + SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -687,6 +707,14 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), +SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), +SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), +SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), + +ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), + SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), @@ -708,14 +736,6 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), -SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L, - ARIZONA_OUT1_OSR_SHIFT, 1, 0), -SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L, - ARIZONA_OUT2_OSR_SHIFT, 1, 0), -SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L, - ARIZONA_OUT3_OSR_SHIFT, 1, 0), -SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, - ARIZONA_OUT4_OSR_SHIFT, 1, 0), SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, ARIZONA_OUT5_OSR_SHIFT, 1, 0), @@ -745,16 +765,8 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L, - ARIZONA_OUTPUT_PATH_CONFIG_1R, - ARIZONA_OUT1L_PGA_VOL_SHIFT, - 0x34, 0x40, 0, ana_tlv), -SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L, - ARIZONA_OUTPUT_PATH_CONFIG_2R, - ARIZONA_OUT2L_PGA_VOL_SHIFT, - 0x34, 0x40, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L, - ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv), +SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), +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), @@ -819,11 +831,15 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); +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_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE); static const char *wm5102_aec_loopback_texts[] = { "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT", @@ -864,6 +880,7 @@ SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0), SND_SOC_DAPM_SIGGEN("TONE"), SND_SOC_DAPM_SIGGEN("NOISE"), +SND_SOC_DAPM_SIGGEN("HAPTICS"), SND_SOC_DAPM_INPUT("IN1L"), SND_SOC_DAPM_INPUT("IN1R"), @@ -894,9 +911,9 @@ SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2, - ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), + ARIZONA_MICB2_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3, - ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), + ARIZONA_MICB3_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR, ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), @@ -996,6 +1013,8 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), +ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), + SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux), @@ -1071,10 +1090,12 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), -ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"), -ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"), -ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"), -ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"), +ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"), +ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"), +ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), +ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), + +WM_ADSP2("DSP1", 0), SND_SOC_DAPM_OUTPUT("HPOUT1L"), SND_SOC_DAPM_OUTPUT("HPOUT1R"), @@ -1094,6 +1115,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"), { name, "Noise Generator", "Noise Generator" }, \ { name, "Tone Generator 1", "Tone Generator 1" }, \ { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ { name, "AEC", "AEC Loopback" }, \ { name, "IN1L", "IN1L PGA" }, \ { name, "IN1R", "IN1R PGA" }, \ @@ -1127,7 +1149,13 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"), { name, "ASRC1L", "ASRC1L" }, \ { name, "ASRC1R", "ASRC1R" }, \ { name, "ASRC2L", "ASRC2L" }, \ - { name, "ASRC2R", "ASRC2R" } + { name, "ASRC2R", "ASRC2R" }, \ + { name, "DSP1.1", "DSP1" }, \ + { name, "DSP1.2", "DSP1" }, \ + { name, "DSP1.3", "DSP1" }, \ + { name, "DSP1.4", "DSP1" }, \ + { name, "DSP1.5", "DSP1" }, \ + { name, "DSP1.6", "DSP1" } static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "AIF2 Capture", NULL, "DBVDD2" }, @@ -1213,6 +1241,11 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "IN3L PGA", NULL, "IN3L" }, { "IN3R PGA", NULL, "IN3R" }, + { "ASRC1L", NULL, "ASRC1L Input" }, + { "ASRC1R", NULL, "ASRC1R Input" }, + { "ASRC2L", NULL, "ASRC2L Input" }, + { "ASRC2R", NULL, "ASRC2R Input" }, + ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"), @@ -1255,10 +1288,12 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), - ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"), - ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"), - ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"), - ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"), + ARIZONA_MUX_ROUTES("ASRC1L"), + ARIZONA_MUX_ROUTES("ASRC1R"), + ARIZONA_MUX_ROUTES("ASRC2L"), + ARIZONA_MUX_ROUTES("ASRC2R"), + + ARIZONA_DSP_ROUTES("DSP1"), { "AEC Loopback", "HPOUT1L", "OUT1L" }, { "AEC Loopback", "HPOUT1R", "OUT1R" }, @@ -1377,9 +1412,28 @@ static struct snd_soc_dai_driver wm5102_dai[] = { static int wm5102_codec_probe(struct snd_soc_codec *codec) { struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; codec->control_data = priv->core.arizona->regmap; - return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + + ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + if (ret != 0) + return ret; + + snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); + + priv->core.arizona->dapm = &codec->dapm; + + return 0; +} + +static int wm5102_codec_remove(struct snd_soc_codec *codec) +{ + struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); + + priv->core.arizona->dapm = NULL; + + return 0; } #define WM5102_DIG_VU 0x0200 @@ -1406,6 +1460,7 @@ static unsigned int wm5102_digital_vu[] = { static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .probe = wm5102_codec_probe, + .remove = wm5102_codec_remove, .idle_bias_off = true, @@ -1424,7 +1479,7 @@ static int __devinit wm5102_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct wm5102_priv *wm5102; - int i; + int i, ret; wm5102 = devm_kzalloc(&pdev->dev, sizeof(struct wm5102_priv), GFP_KERNEL); @@ -1434,6 +1489,19 @@ static int __devinit wm5102_probe(struct platform_device *pdev) wm5102->core.arizona = arizona; + wm5102->core.adsp[0].part = "wm5102"; + wm5102->core.adsp[0].num = 1; + wm5102->core.adsp[0].type = WMFW_ADSP2; + wm5102->core.adsp[0].base = ARIZONA_DSP1_CONTROL_1; + wm5102->core.adsp[0].dev = arizona->dev; + wm5102->core.adsp[0].regmap = arizona->regmap; + wm5102->core.adsp[0].mem = wm5102_dsp1_regions; + wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions); + + ret = wm_adsp2_init(&wm5102->core.adsp[0], true); + if (ret != 0) + return ret; + for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++) wm5102->fll[i].vco_mult = 1; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 9211e4192f71..c57dc7468300 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -84,11 +84,23 @@ 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), + ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, + ARIZONA_EQ1_ENA_MASK), +SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, + ARIZONA_EQ2_ENA_MASK), +SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, + ARIZONA_EQ3_ENA_MASK), +SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, + ARIZONA_EQ4_ENA_MASK), + SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -148,6 +160,11 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), +SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), +SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), +SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), + SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), @@ -243,6 +260,9 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT, ARIZONA_SPK2R_MUTE_SHIFT, 1, 1), +SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), +SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), + 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), @@ -308,10 +328,10 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); +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); static const char *wm5110_aec_loopback_texts[] = { "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R", @@ -352,6 +372,7 @@ SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0), SND_SOC_DAPM_SIGGEN("TONE"), SND_SOC_DAPM_SIGGEN("NOISE"), +SND_SOC_DAPM_SIGGEN("HAPTICS"), SND_SOC_DAPM_INPUT("IN1L"), SND_SOC_DAPM_INPUT("IN1R"), @@ -585,10 +606,10 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), -ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"), -ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"), -ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"), -ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"), +ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"), +ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"), +ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), +ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), SND_SOC_DAPM_OUTPUT("HPOUT1L"), SND_SOC_DAPM_OUTPUT("HPOUT1R"), @@ -610,6 +631,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT2R"), { name, "Noise Generator", "Noise Generator" }, \ { name, "Tone Generator 1", "Tone Generator 1" }, \ { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ { name, "AEC", "AEC Loopback" }, \ { name, "IN1L", "IN1L PGA" }, \ { name, "IN1R", "IN1R PGA" }, \ @@ -786,10 +808,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), - ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"), - ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"), - ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"), - ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"), + ARIZONA_MUX_ROUTES("ASRC1L"), + ARIZONA_MUX_ROUTES("ASRC1R"), + ARIZONA_MUX_ROUTES("ASRC2L"), + ARIZONA_MUX_ROUTES("ASRC2R"), { "HPOUT1L", NULL, "OUT1L" }, { "HPOUT1R", NULL, "OUT1R" }, @@ -902,9 +924,29 @@ static struct snd_soc_dai_driver wm5110_dai[] = { static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; codec->control_data = priv->core.arizona->regmap; - return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + priv->core.arizona->dapm = &codec->dapm; + + ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + if (ret != 0) + return ret; + + snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); + + priv->core.arizona->dapm = &codec->dapm; + + return 0; +} + +static int wm5110_codec_remove(struct snd_soc_codec *codec) +{ + struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + + priv->core.arizona->dapm = NULL; + + return 0; } #define WM5110_DIG_VU 0x0200 @@ -935,6 +977,7 @@ static unsigned int wm5110_digital_vu[] = { static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .probe = wm5110_codec_probe, + .remove = wm5110_codec_remove, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index a4cae060bf26..32b8f0852f6e 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1500,7 +1500,7 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(supply_names); i++) priv->supplies[i].supply = supply_names[i]; - ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies), + ret = devm_regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies), priv->supplies); if (ret != 0) return ret; @@ -1607,8 +1607,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); - regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies); - return 0; } diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 5d277a915f81..262c44082eb0 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1373,7 +1373,7 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) codec->control_data = priv->wm8400 = wm8400; priv->codec = codec; - ret = regulator_bulk_get(wm8400->dev, + ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); if (ret != 0) { dev_err(codec->dev, "Failed to get regulators: %d\n", ret); @@ -1398,15 +1398,9 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); - if (!schedule_work(&priv->work)) { - ret = -EINVAL; - goto err_regulator; - } + if (!schedule_work(&priv->work)) + return -EINVAL; return 0; - -err_regulator: - regulator_bulk_free(ARRAY_SIZE(power), power); - return ret; } static int wm8400_codec_remove(struct snd_soc_codec *codec) @@ -1417,8 +1411,6 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec) snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, reg & (~WM8400_CODEC_ENA)); - regulator_bulk_free(ARRAY_SIZE(power), power); - return 0; } diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index c12a54e72e89..923e7e1f6704 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -608,10 +608,7 @@ static int wm8510_probe(struct snd_soc_codec *codec) /* power down chip */ static int wm8510_remove(struct snd_soc_codec *codec) { - struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec); - wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); - kfree(wm8510); return 0; } diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 4281a0802138..99b8ebe93424 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -522,7 +522,7 @@ static int wm8741_i2c_probe(struct i2c_client *i2c, return ret; } - wm8741->regmap = regmap_init_i2c(i2c, &wm8741_regmap); + wm8741->regmap = devm_regmap_init_i2c(i2c, &wm8741_regmap); if (IS_ERR(wm8741->regmap)) { ret = PTR_ERR(wm8741->regmap); dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); @@ -582,7 +582,7 @@ static int __devinit wm8741_spi_probe(struct spi_device *spi) return ret; } - wm8741->regmap = regmap_init_spi(spi, &wm8741_regmap); + wm8741->regmap = devm_regmap_init_spi(spi, &wm8741_regmap); if (IS_ERR(wm8741->regmap)) { ret = PTR_ERR(wm8741->regmap); dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 89151ca5e776..7665d68c4558 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/slab.h> #include <linux/of_device.h> @@ -34,24 +35,55 @@ * We can't read the WM8750 register space when we * are using 2 wire for device control, so we cache them instead. */ -static const u16 wm8750_reg[] = { - 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ - 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ - 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ - 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ - 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ - 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ - 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ - 0x0079, 0x0079, 0x0079, /* 40 */ +static const struct reg_default wm8750_reg_defaults[] = { + { 0, 0x0097 }, + { 1, 0x0097 }, + { 2, 0x0079 }, + { 3, 0x0079 }, + { 4, 0x0000 }, + { 5, 0x0008 }, + { 6, 0x0000 }, + { 7, 0x000a }, + { 8, 0x0000 }, + { 9, 0x0000 }, + { 10, 0x00ff }, + { 11, 0x00ff }, + { 12, 0x000f }, + { 13, 0x000f }, + { 14, 0x0000 }, + { 15, 0x0000 }, + { 16, 0x0000 }, + { 17, 0x007b }, + { 18, 0x0000 }, + { 19, 0x0032 }, + { 20, 0x0000 }, + { 21, 0x00c3 }, + { 22, 0x00c3 }, + { 23, 0x00c0 }, + { 24, 0x0000 }, + { 25, 0x0000 }, + { 26, 0x0000 }, + { 27, 0x0000 }, + { 28, 0x0000 }, + { 29, 0x0000 }, + { 30, 0x0000 }, + { 31, 0x0000 }, + { 32, 0x0000 }, + { 33, 0x0000 }, + { 34, 0x0050 }, + { 35, 0x0050 }, + { 36, 0x0050 }, + { 37, 0x0050 }, + { 38, 0x0050 }, + { 39, 0x0050 }, + { 40, 0x0079 }, + { 41, 0x0079 }, + { 42, 0x0079 }, }; /* codec private data */ struct wm8750_priv { unsigned int sysclk; - enum snd_soc_control_type control_type; }; #define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0) @@ -668,10 +700,9 @@ static int wm8750_resume(struct snd_soc_codec *codec) static int wm8750_probe(struct snd_soc_codec *codec) { - struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); return ret; @@ -711,9 +742,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { .suspend = wm8750_suspend, .resume = wm8750_resume, .set_bias_level = wm8750_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8750_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8750_reg, .controls = wm8750_snd_controls, .num_controls = ARRAY_SIZE(wm8750_snd_controls), @@ -730,10 +758,21 @@ static const struct of_device_id wm8750_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8750_of_match); +static const struct regmap_config wm8750_regmap = { + .reg_bits = 7, + .val_bits = 9, + .max_register = WM8750_MOUTV, + + .reg_defaults = wm8750_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + #if defined(CONFIG_SPI_MASTER) static int __devinit wm8750_spi_probe(struct spi_device *spi) { struct wm8750_priv *wm8750; + struct regmap *regmap; int ret; wm8750 = devm_kzalloc(&spi->dev, sizeof(struct wm8750_priv), @@ -741,7 +780,10 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi) if (wm8750 == NULL) return -ENOMEM; - wm8750->control_type = SND_SOC_SPI; + regmap = devm_regmap_init_spi(spi, &wm8750_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + spi_set_drvdata(spi, wm8750); ret = snd_soc_register_codec(&spi->dev, @@ -779,6 +821,7 @@ static __devinit int wm8750_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8750_priv *wm8750; + struct regmap *regmap; int ret; wm8750 = devm_kzalloc(&i2c->dev, sizeof(struct wm8750_priv), @@ -787,7 +830,10 @@ static __devinit int wm8750_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, wm8750); - wm8750->control_type = SND_SOC_I2C; + + regmap = devm_regmap_init_i2c(i2c, &wm8750_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8750, &wm8750_dai, 1); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 2e4a775ae560..50a5dc7974e1 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1562,36 +1562,25 @@ static int __devinit wm8753_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, wm8753); - wm8753->regmap = regmap_init_spi(spi, &wm8753_regmap); + wm8753->regmap = devm_regmap_init_spi(spi, &wm8753_regmap); if (IS_ERR(wm8753->regmap)) { ret = PTR_ERR(wm8753->regmap); dev_err(&spi->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret != 0) { + if (ret != 0) dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); - goto err_regmap; - } - return 0; - -err_regmap: - regmap_exit(wm8753->regmap); -err: return ret; } static int __devexit wm8753_spi_remove(struct spi_device *spi) { - struct wm8753_priv *wm8753 = spi_get_drvdata(spi); - snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8753->regmap); - kfree(wm8753); return 0; } @@ -1620,35 +1609,25 @@ static __devinit int wm8753_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8753); - wm8753->regmap = regmap_init_i2c(i2c, &wm8753_regmap); + wm8753->regmap = devm_regmap_init_i2c(i2c, &wm8753_regmap); if (IS_ERR(wm8753->regmap)) { ret = PTR_ERR(wm8753->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret != 0) { + if (ret != 0) dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - goto err_regmap; - } - return 0; - -err_regmap: - regmap_exit(wm8753->regmap); -err: return ret; } static __devexit int wm8753_i2c_remove(struct i2c_client *client) { - struct wm8753_priv *wm8753 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8753->regmap); return 0; } diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index c7c0034d3966..0b690ba875f8 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -17,6 +17,7 @@ #include <linux/of_device.h> #include <linux/pm.h> #include <linux/spi/spi.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> @@ -35,19 +36,52 @@ static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = { "DVDD" }; -static const u16 wm8770_reg_defs[WM8770_CACHEREGNUM] = { - 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0, 0x90, 0, - 0, 0x22, 0x22, 0x3e, - 0xc, 0xc, 0x100, 0x189, - 0x189, 0x8770 +static const struct reg_default wm8770_reg_defaults[] = { + { 0, 0x7f }, + { 1, 0x7f }, + { 2, 0x7f }, + { 3, 0x7f }, + { 4, 0x7f }, + { 5, 0x7f }, + { 6, 0x7f }, + { 7, 0x7f }, + { 8, 0x7f }, + { 9, 0xff }, + { 10, 0xff }, + { 11, 0xff }, + { 12, 0xff }, + { 13, 0xff }, + { 14, 0xff }, + { 15, 0xff }, + { 16, 0xff }, + { 17, 0xff }, + { 18, 0 }, + { 19, 0x90 }, + { 20, 0 }, + { 21, 0 }, + { 22, 0x22 }, + { 23, 0x22 }, + { 24, 0x3e }, + { 25, 0xc }, + { 26, 0xc }, + { 27, 0x100 }, + { 28, 0x189 }, + { 29, 0x189 }, + { 30, 0x8770 }, }; +static bool wm8770_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8770_RESET: + return true; + default: + return false; + } +} + struct wm8770_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES]; struct notifier_block disable_nb[WM8770_NUM_SUPPLIES]; struct snd_soc_codec *codec; @@ -71,7 +105,7 @@ static int wm8770_regulator_event_##n(struct notifier_block *nb, \ struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \ disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \ - wm8770->codec->cache_sync = 1; \ + regcache_mark_dirty(wm8770->regmap); \ } \ return 0; \ } @@ -466,24 +500,6 @@ static int wm8770_set_sysclk(struct snd_soc_dai *dai, return 0; } -static void wm8770_sync_cache(struct snd_soc_codec *codec) -{ - int i; - u16 *cache; - - if (!codec->cache_sync) - return; - - codec->cache_only = 0; - cache = codec->reg_cache; - for (i = 0; i < codec->driver->reg_cache_size; i++) { - if (i == WM8770_RESET || cache[i] == wm8770_reg_defs[i]) - continue; - snd_soc_write(codec, i, cache[i]); - } - codec->cache_sync = 0; -} - static int wm8770_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -507,7 +523,9 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec, ret); return ret; } - wm8770_sync_cache(codec); + + regcache_sync(wm8770->regmap); + /* global powerup */ snd_soc_write(codec, WM8770_PWDNCTRL, 0); } @@ -554,68 +572,25 @@ static struct snd_soc_dai_driver wm8770_dai = { .symmetric_rates = 1 }; -#ifdef CONFIG_PM -static int wm8770_suspend(struct snd_soc_codec *codec) -{ - wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8770_resume(struct snd_soc_codec *codec) -{ - wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8770_suspend NULL -#define wm8770_resume NULL -#endif - static int wm8770_probe(struct snd_soc_codec *codec) { struct wm8770_priv *wm8770; int ret; - int i; wm8770 = snd_soc_codec_get_drvdata(codec); wm8770->codec = codec; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) - wm8770->supplies[i].supply = wm8770_supply_names[i]; - - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8770->supplies), - wm8770->supplies); - if (ret) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - return ret; - } - - wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0; - wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1; - wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2; - - /* This should really be moved into the regulator core */ - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { - ret = regulator_register_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); - if (ret) { - dev_err(codec->dev, - "Failed to register regulator notifier: %d\n", - ret); - } - } - ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); if (ret) { dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_get; + return ret; } ret = wm8770_reset(codec); @@ -624,8 +599,6 @@ static int wm8770_probe(struct snd_soc_codec *codec) goto err_reg_enable; } - wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* latch the volume update bits */ snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100); snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100); @@ -641,46 +614,22 @@ static int wm8770_probe(struct snd_soc_codec *codec) /* mute all DACs */ snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10); - snd_soc_add_codec_controls(codec, wm8770_snd_controls, - ARRAY_SIZE(wm8770_snd_controls)); - snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets, - ARRAY_SIZE(wm8770_dapm_widgets)); - snd_soc_dapm_add_routes(&codec->dapm, wm8770_intercon, - ARRAY_SIZE(wm8770_intercon)); - return 0; - err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); -err_reg_get: - regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); return ret; } -static int wm8770_remove(struct snd_soc_codec *codec) -{ - struct wm8770_priv *wm8770; - int i; - - wm8770 = snd_soc_codec_get_drvdata(codec); - wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF); - - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) - regulator_unregister_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); - regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8770 = { .probe = wm8770_probe, - .remove = wm8770_remove, - .suspend = wm8770_suspend, - .resume = wm8770_resume, .set_bias_level = wm8770_set_bias_level, .idle_bias_off = true, - .reg_cache_size = ARRAY_SIZE(wm8770_reg_defs), - .reg_word_size = sizeof (u16), - .reg_cache_default = wm8770_reg_defs + + .controls = wm8770_snd_controls, + .num_controls = ARRAY_SIZE(wm8770_snd_controls), + .dapm_widgets = wm8770_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8770_dapm_widgets), + .dapm_routes = wm8770_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8770_intercon), }; static const struct of_device_id wm8770_of_match[] = { @@ -689,17 +638,57 @@ static const struct of_device_id wm8770_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8770_of_match); +static const struct regmap_config wm8770_regmap = { + .reg_bits = 7, + .val_bits = 9, + .max_register = WM8770_RESET, + + .reg_defaults = wm8770_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = wm8770_volatile_reg, +}; + static int __devinit wm8770_spi_probe(struct spi_device *spi) { struct wm8770_priv *wm8770; - int ret; + int ret, i; wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv), GFP_KERNEL); if (!wm8770) return -ENOMEM; - wm8770->control_type = SND_SOC_SPI; + for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) + wm8770->supplies[i].supply = wm8770_supply_names[i]; + + ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8770->supplies), + wm8770->supplies); + if (ret) { + dev_err(&spi->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0; + wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1; + wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2; + + /* This should really be moved into the regulator core */ + for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { + ret = regulator_register_notifier(wm8770->supplies[i].consumer, + &wm8770->disable_nb[i]); + if (ret) { + dev_err(&spi->dev, + "Failed to register regulator notifier: %d\n", + ret); + } + } + + wm8770->regmap = devm_regmap_init_spi(spi, &wm8770_regmap); + if (IS_ERR(wm8770->regmap)) + return PTR_ERR(wm8770->regmap); + spi_set_drvdata(spi, wm8770); ret = snd_soc_register_codec(&spi->dev, @@ -710,7 +699,15 @@ static int __devinit wm8770_spi_probe(struct spi_device *spi) static int __devexit wm8770_spi_remove(struct spi_device *spi) { + struct wm8770_priv *wm8770 = spi_get_drvdata(spi); + int i; + + for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) + regulator_unregister_notifier(wm8770->supplies[i].consumer, + &wm8770->disable_nb[i]); + snd_soc_unregister_codec(&spi->dev); + return 0; } diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index c088020172ab..837bfb51cebf 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -711,7 +711,7 @@ static int __devinit wm8804_spi_probe(struct spi_device *spi) if (!wm8804) return -ENOMEM; - wm8804->regmap = regmap_init_spi(spi, &wm8804_regmap_config); + wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); if (IS_ERR(wm8804->regmap)) { ret = PTR_ERR(wm8804->regmap); return ret; @@ -727,9 +727,7 @@ static int __devinit wm8804_spi_probe(struct spi_device *spi) static int __devexit wm8804_spi_remove(struct spi_device *spi) { - struct wm8804_priv *wm8804 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8804->regmap); return 0; } @@ -755,7 +753,7 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c, if (!wm8804) return -ENOMEM; - wm8804->regmap = regmap_init_i2c(i2c, &wm8804_regmap_config); + wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); if (IS_ERR(wm8804->regmap)) { ret = PTR_ERR(wm8804->regmap); return ret; @@ -765,23 +763,12 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8804, &wm8804_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(wm8804->regmap); return ret; } static __devexit int wm8804_i2c_remove(struct i2c_client *i2c) { - struct wm8804_priv *wm8804 = i2c_get_clientdata(i2c); - snd_soc_unregister_codec(&i2c->dev); - regmap_exit(wm8804->regmap); - return 0; } diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 2f1c075755b1..7a82b7d28dcd 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1023,7 +1023,7 @@ static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, if (wm8955 == NULL) return -ENOMEM; - wm8955->regmap = regmap_init_i2c(i2c, &wm8955_regmap); + wm8955->regmap = devm_regmap_init_i2c(i2c, &wm8955_regmap); if (IS_ERR(wm8955->regmap)) { ret = PTR_ERR(wm8955->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -1035,22 +1035,13 @@ static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8955, &wm8955_dai, 1); - if (ret != 0) - goto err; return ret; - -err: - regmap_exit(wm8955->regmap); - return ret; } static __devexit int wm8955_i2c_remove(struct i2c_client *client) { - struct wm8955_priv *wm8955 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8955->regmap); return 0; } diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f0f6f6601785..cf09cb625a7b 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1040,7 +1040,7 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, if (wm8960 == NULL) return -ENOMEM; - wm8960->regmap = regmap_init_i2c(i2c, &wm8960_regmap); + wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index ce6720073798..8fd38cb4ba48 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3610,7 +3610,7 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) wm8962->supplies[i].supply = wm8962_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8962->supplies), + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8962->supplies), wm8962->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); @@ -3621,10 +3621,10 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, wm8962->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; + return ret; } - wm8962->regmap = regmap_init_i2c(i2c, &wm8962_regmap); + wm8962->regmap = devm_regmap_init_i2c(i2c, &wm8962_regmap); if (IS_ERR(wm8962->regmap)) { ret = PTR_ERR(wm8962->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -3641,20 +3641,20 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, ret = regmap_read(wm8962->regmap, WM8962_SOFTWARE_RESET, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read ID register\n"); - goto err_regmap; + goto err_enable; } if (reg != 0x6243) { dev_err(&i2c->dev, "Device is not a WM8962, ID %x != 0x6243\n", reg); ret = -EINVAL; - goto err_regmap; + goto err_enable; } ret = regmap_read(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read device revision: %d\n", ret); - goto err_regmap; + goto err_enable; } dev_info(&i2c->dev, "customer id %x revision %c\n", @@ -3667,7 +3667,7 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, ret = wm8962_reset(wm8962); if (ret < 0) { dev_err(&i2c->dev, "Failed to issue reset\n"); - goto err_regmap; + goto err_enable; } if (pdata && pdata->in4_dc_measure) { @@ -3686,30 +3686,22 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8962, &wm8962_dai, 1); if (ret < 0) - goto err_regmap; + goto err_enable; /* The drivers should power up as needed */ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); return 0; -err_regmap: - regmap_exit(wm8962->regmap); err_enable: regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); err: return ret; } static __devexit int wm8962_i2c_remove(struct i2c_client *client) { - struct wm8962_priv *wm8962 = dev_get_drvdata(&client->dev); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8962->regmap); - regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); return 0; } diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 5ce647758443..70dd27e94514 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -34,7 +35,6 @@ static struct workqueue_struct *wm8971_workq = NULL; /* codec private data */ struct wm8971_priv { - enum snd_soc_control_type control_type; unsigned int sysclk; }; @@ -43,18 +43,50 @@ struct wm8971_priv { * We can't read the WM8971 register space when we * are using 2 wire for device control, so we cache them instead. */ -static const u16 wm8971_reg[] = { - 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ - 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ - 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ - 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ - 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ - 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ - 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ - 0x0079, 0x0079, 0x0079, /* 40 */ +static const struct reg_default wm8971_reg_defaults[] = { + { 0, 0x0097 }, + { 1, 0x0097 }, + { 2, 0x0079 }, + { 3, 0x0079 }, + { 4, 0x0000 }, + { 5, 0x0008 }, + { 6, 0x0000 }, + { 7, 0x000a }, + { 8, 0x0000 }, + { 9, 0x0000 }, + { 10, 0x00ff }, + { 11, 0x00ff }, + { 12, 0x000f }, + { 13, 0x000f }, + { 14, 0x0000 }, + { 15, 0x0000 }, + { 16, 0x0000 }, + { 17, 0x007b }, + { 18, 0x0000 }, + { 19, 0x0032 }, + { 20, 0x0000 }, + { 21, 0x00c3 }, + { 22, 0x00c3 }, + { 23, 0x00c0 }, + { 24, 0x0000 }, + { 25, 0x0000 }, + { 26, 0x0000 }, + { 27, 0x0000 }, + { 28, 0x0000 }, + { 29, 0x0000 }, + { 30, 0x0000 }, + { 31, 0x0000 }, + { 32, 0x0000 }, + { 33, 0x0000 }, + { 34, 0x0050 }, + { 35, 0x0050 }, + { 36, 0x0050 }, + { 37, 0x0050 }, + { 38, 0x0050 }, + { 39, 0x0050 }, + { 40, 0x0079 }, + { 41, 0x0079 }, + { 42, 0x0079 }, }; #define wm8971_reset(c) snd_soc_write(c, WM8971_RESET, 0) @@ -613,11 +645,10 @@ static int wm8971_resume(struct snd_soc_codec *codec) static int wm8971_probe(struct snd_soc_codec *codec) { - struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); int ret = 0; u16 reg; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); return ret; @@ -667,9 +698,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { .suspend = wm8971_suspend, .resume = wm8971_resume, .set_bias_level = wm8971_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8971_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8971_reg, .controls = wm8971_snd_controls, .num_controls = ARRAY_SIZE(wm8971_snd_controls), @@ -679,10 +707,21 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { .num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes), }; +static const struct regmap_config wm8971_regmap = { + .reg_bits = 7, + .val_bits = 9, + .max_register = WM8971_MOUTV, + + .reg_defaults = wm8971_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8971_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + static __devinit int wm8971_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8971_priv *wm8971; + struct regmap *regmap; int ret; wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv), @@ -690,7 +729,10 @@ static __devinit int wm8971_i2c_probe(struct i2c_client *i2c, if (wm8971 == NULL) return -ENOMEM; - wm8971->control_type = SND_SOC_I2C; + regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + i2c_set_clientdata(i2c, wm8971); ret = snd_soc_register_codec(&i2c->dev, diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 4c0a8e496131..ef467001c3d5 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -527,9 +527,6 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec) return idx; wm8978->mclk_idx = idx; - - /* GPIO1 into default mode as input - before configuring PLL */ - snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0); } else { return -EINVAL; } @@ -1049,7 +1046,7 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, if (wm8978 == NULL) return -ENOMEM; - wm8978->regmap = regmap_init_i2c(i2c, &wm8978_regmap_config); + wm8978->regmap = devm_regmap_init_i2c(i2c, &wm8978_regmap_config); if (IS_ERR(wm8978->regmap)) { ret = PTR_ERR(wm8978->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -1062,29 +1059,22 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, ret = regmap_write(wm8978->regmap, WM8978_RESET, 0); if (ret != 0) { dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8978, &wm8978_dai, 1); if (ret != 0) { dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - goto err; + return ret; } return 0; - -err: - regmap_exit(wm8978->regmap); - return ret; } static __devexit int wm8978_i2c_remove(struct i2c_client *client) { - struct wm8978_priv *wm8978 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8978->regmap); return 0; } diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 14f666398d0c..7b3f4097609b 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1122,33 +1122,22 @@ static int __devinit wm8985_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, wm8985); - wm8985->regmap = regmap_init_spi(spi, &wm8985_regmap); + wm8985->regmap = devm_regmap_init_spi(spi, &wm8985_regmap); if (IS_ERR(wm8985->regmap)) { ret = PTR_ERR(wm8985->regmap); dev_err(&spi->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8985, &wm8985_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(wm8985->regmap); return ret; } static int __devexit wm8985_spi_remove(struct spi_device *spi) { - struct wm8985_priv *wm8985 = spi_get_drvdata(spi); - snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8985->regmap); - return 0; } @@ -1175,33 +1164,22 @@ static __devinit int wm8985_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8985); - wm8985->regmap = regmap_init_i2c(i2c, &wm8985_regmap); + wm8985->regmap = devm_regmap_init_i2c(i2c, &wm8985_regmap); if (IS_ERR(wm8985->regmap)) { ret = PTR_ERR(wm8985->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8985, &wm8985_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(wm8985->regmap); return ret; } static __devexit int wm8985_i2c_remove(struct i2c_client *i2c) { - struct wm8985_priv *wm8985 = i2c_get_clientdata(i2c); - snd_soc_unregister_codec(&i2c->dev); - regmap_exit(wm8985->regmap); - return 0; } diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c new file mode 100644 index 000000000000..ffc89fab96fb --- /dev/null +++ b/sound/soc/codecs/wm_adsp.c @@ -0,0 +1,699 @@ +/* + * wm_adsp.c -- Wolfson ADSP support + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include <linux/mfd/arizona/registers.h> + +#include "wm_adsp.h" + +#define adsp_crit(_dsp, fmt, ...) \ + dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_err(_dsp, fmt, ...) \ + dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_warn(_dsp, fmt, ...) \ + dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_info(_dsp, fmt, ...) \ + dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_dbg(_dsp, fmt, ...) \ + dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) + +#define ADSP1_CONTROL_1 0x00 +#define ADSP1_CONTROL_2 0x02 +#define ADSP1_CONTROL_3 0x03 +#define ADSP1_CONTROL_4 0x04 +#define ADSP1_CONTROL_5 0x06 +#define ADSP1_CONTROL_6 0x07 +#define ADSP1_CONTROL_7 0x08 +#define ADSP1_CONTROL_8 0x09 +#define ADSP1_CONTROL_9 0x0A +#define ADSP1_CONTROL_10 0x0B +#define ADSP1_CONTROL_11 0x0C +#define ADSP1_CONTROL_12 0x0D +#define ADSP1_CONTROL_13 0x0F +#define ADSP1_CONTROL_14 0x10 +#define ADSP1_CONTROL_15 0x11 +#define ADSP1_CONTROL_16 0x12 +#define ADSP1_CONTROL_17 0x13 +#define ADSP1_CONTROL_18 0x14 +#define ADSP1_CONTROL_19 0x16 +#define ADSP1_CONTROL_20 0x17 +#define ADSP1_CONTROL_21 0x18 +#define ADSP1_CONTROL_22 0x1A +#define ADSP1_CONTROL_23 0x1B +#define ADSP1_CONTROL_24 0x1C +#define ADSP1_CONTROL_25 0x1E +#define ADSP1_CONTROL_26 0x20 +#define ADSP1_CONTROL_27 0x21 +#define ADSP1_CONTROL_28 0x22 +#define ADSP1_CONTROL_29 0x23 +#define ADSP1_CONTROL_30 0x24 +#define ADSP1_CONTROL_31 0x26 + +/* + * ADSP1 Control 19 + */ +#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ + + +/* + * ADSP1 Control 30 + */ +#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ +#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ +#define ADSP1_START 0x0001 /* DSP1_START */ +#define ADSP1_START_MASK 0x0001 /* DSP1_START */ +#define ADSP1_START_SHIFT 0 /* DSP1_START */ +#define ADSP1_START_WIDTH 1 /* DSP1_START */ + +#define ADSP2_CONTROL 0 +#define ADSP2_CLOCKING 1 +#define ADSP2_STATUS1 4 + +/* + * ADSP2 Control + */ + +#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */ +#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ +#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ +#define ADSP2_START 0x0001 /* DSP1_START */ +#define ADSP2_START_MASK 0x0001 /* DSP1_START */ +#define ADSP2_START_SHIFT 0 /* DSP1_START */ +#define ADSP2_START_WIDTH 1 /* DSP1_START */ + +/* + * ADSP2 clocking + */ +#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ +#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ +#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ + +/* + * ADSP2 Status 1 + */ +#define ADSP2_RAM_RDY 0x0001 +#define ADSP2_RAM_RDY_MASK 0x0001 +#define ADSP2_RAM_RDY_SHIFT 0 +#define ADSP2_RAM_RDY_WIDTH 1 + + +static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, + int type) +{ + int i; + + for (i = 0; i < dsp->num_mems; i++) + if (dsp->mem[i].type == type) + return &dsp->mem[i]; + + return NULL; +} + +static int wm_adsp_load(struct wm_adsp *dsp) +{ + const struct firmware *firmware; + struct regmap *regmap = dsp->regmap; + unsigned int pos = 0; + const struct wmfw_header *header; + const struct wmfw_adsp1_sizes *adsp1_sizes; + const struct wmfw_adsp2_sizes *adsp2_sizes; + const struct wmfw_footer *footer; + const struct wmfw_region *region; + const struct wm_adsp_region *mem; + const char *region_name; + char *file, *text; + unsigned int reg; + int regions = 0; + int ret, offset, type, sizes; + + file = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (file == NULL) + return -ENOMEM; + + snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num); + file[PAGE_SIZE - 1] = '\0'; + + ret = request_firmware(&firmware, file, dsp->dev); + if (ret != 0) { + adsp_err(dsp, "Failed to request '%s'\n", file); + goto out; + } + ret = -EINVAL; + + pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); + if (pos >= firmware->size) { + adsp_err(dsp, "%s: file too short, %zu bytes\n", + file, firmware->size); + goto out_fw; + } + + header = (void*)&firmware->data[0]; + + if (memcmp(&header->magic[0], "WMFW", 4) != 0) { + adsp_err(dsp, "%s: invalid magic\n", file); + goto out_fw; + } + + if (header->ver != 0) { + adsp_err(dsp, "%s: unknown file format %d\n", + file, header->ver); + goto out_fw; + } + + if (header->core != dsp->type) { + adsp_err(dsp, "%s: invalid core %d != %d\n", + file, header->core, dsp->type); + goto out_fw; + } + + switch (dsp->type) { + case WMFW_ADSP1: + pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); + adsp1_sizes = (void *)&(header[1]); + footer = (void *)&(adsp1_sizes[1]); + sizes = sizeof(*adsp1_sizes); + + adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", + file, le32_to_cpu(adsp1_sizes->dm), + le32_to_cpu(adsp1_sizes->pm), + le32_to_cpu(adsp1_sizes->zm)); + break; + + case WMFW_ADSP2: + pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer); + adsp2_sizes = (void *)&(header[1]); + footer = (void *)&(adsp2_sizes[1]); + sizes = sizeof(*adsp2_sizes); + + adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", + file, le32_to_cpu(adsp2_sizes->xm), + le32_to_cpu(adsp2_sizes->ym), + le32_to_cpu(adsp2_sizes->pm), + le32_to_cpu(adsp2_sizes->zm)); + break; + + default: + BUG_ON(NULL == "Unknown DSP type"); + goto out_fw; + } + + if (le32_to_cpu(header->len) != sizeof(*header) + + sizes + sizeof(*footer)) { + adsp_err(dsp, "%s: unexpected header length %d\n", + file, le32_to_cpu(header->len)); + goto out_fw; + } + + adsp_dbg(dsp, "%s: timestamp %llu\n", file, + le64_to_cpu(footer->timestamp)); + + while (pos < firmware->size && + pos - firmware->size > sizeof(*region)) { + region = (void *)&(firmware->data[pos]); + region_name = "Unknown"; + reg = 0; + text = NULL; + offset = le32_to_cpu(region->offset) & 0xffffff; + type = be32_to_cpu(region->type) & 0xff; + mem = wm_adsp_find_region(dsp, type); + + switch (type) { + case WMFW_NAME_TEXT: + region_name = "Firmware name"; + text = kzalloc(le32_to_cpu(region->len) + 1, + GFP_KERNEL); + break; + case WMFW_INFO_TEXT: + region_name = "Information"; + text = kzalloc(le32_to_cpu(region->len) + 1, + GFP_KERNEL); + break; + case WMFW_ABSOLUTE: + region_name = "Absolute"; + reg = offset; + break; + case WMFW_ADSP1_PM: + BUG_ON(!mem); + region_name = "PM"; + reg = mem->base + (offset * 3); + break; + case WMFW_ADSP1_DM: + BUG_ON(!mem); + region_name = "DM"; + reg = mem->base + (offset * 2); + break; + case WMFW_ADSP2_XM: + BUG_ON(!mem); + region_name = "XM"; + reg = mem->base + (offset * 2); + break; + case WMFW_ADSP2_YM: + BUG_ON(!mem); + region_name = "YM"; + reg = mem->base + (offset * 2); + break; + case WMFW_ADSP1_ZM: + BUG_ON(!mem); + region_name = "ZM"; + reg = mem->base + (offset * 2); + break; + default: + adsp_warn(dsp, + "%s.%d: Unknown region type %x at %d(%x)\n", + file, regions, type, pos, pos); + break; + } + + adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, + regions, le32_to_cpu(region->len), offset, + region_name); + + if (text) { + memcpy(text, region->data, le32_to_cpu(region->len)); + adsp_info(dsp, "%s: %s\n", file, text); + kfree(text); + } + + if (reg) { + ret = regmap_raw_write(regmap, reg, region->data, + le32_to_cpu(region->len)); + if (ret != 0) { + adsp_err(dsp, + "%s.%d: Failed to write %d bytes at %d in %s: %d\n", + file, regions, + le32_to_cpu(region->len), offset, + region_name, ret); + goto out_fw; + } + } + + pos += le32_to_cpu(region->len) + sizeof(*region); + regions++; + } + + if (pos > firmware->size) + adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", + file, regions, pos - firmware->size); + +out_fw: + release_firmware(firmware); +out: + kfree(file); + + return ret; +} + +static int wm_adsp_load_coeff(struct wm_adsp *dsp) +{ + struct regmap *regmap = dsp->regmap; + struct wmfw_coeff_hdr *hdr; + struct wmfw_coeff_item *blk; + const struct firmware *firmware; + const char *region_name; + int ret, pos, blocks, type, offset, reg; + char *file; + + file = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (file == NULL) + return -ENOMEM; + + snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num); + file[PAGE_SIZE - 1] = '\0'; + + ret = request_firmware(&firmware, file, dsp->dev); + if (ret != 0) { + adsp_warn(dsp, "Failed to request '%s'\n", file); + ret = 0; + goto out; + } + ret = -EINVAL; + + if (sizeof(*hdr) >= firmware->size) { + adsp_err(dsp, "%s: file too short, %zu bytes\n", + file, firmware->size); + goto out_fw; + } + + hdr = (void*)&firmware->data[0]; + if (memcmp(hdr->magic, "WMDR", 4) != 0) { + adsp_err(dsp, "%s: invalid magic\n", file); + return -EINVAL; + } + + adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, + (le32_to_cpu(hdr->ver) >> 16) & 0xff, + (le32_to_cpu(hdr->ver) >> 8) & 0xff, + le32_to_cpu(hdr->ver) & 0xff); + + pos = le32_to_cpu(hdr->len); + + blocks = 0; + while (pos < firmware->size && + pos - firmware->size > sizeof(*blk)) { + blk = (void*)(&firmware->data[pos]); + + 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), + (le32_to_cpu(blk->ver) >> 16) & 0xff, + (le32_to_cpu(blk->ver) >> 8) & 0xff, + le32_to_cpu(blk->ver) & 0xff); + adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", + file, blocks, le32_to_cpu(blk->len), offset, type); + + reg = 0; + region_name = "Unknown"; + switch (type) { + case WMFW_NAME_TEXT: + case WMFW_INFO_TEXT: + break; + case WMFW_ABSOLUTE: + region_name = "register"; + reg = offset; + break; + default: + adsp_err(dsp, "Unknown region type %x\n", type); + break; + } + + if (reg) { + 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); + } + } + + pos += le32_to_cpu(blk->len) + sizeof(*blk); + blocks++; + } + + 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); +out: + kfree(file); + return 0; +} + +int wm_adsp1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, ADSP1_SYS_ENA); + + ret = wm_adsp_load(dsp); + if (ret != 0) + goto err; + + ret = wm_adsp_load_coeff(dsp); + if (ret != 0) + goto err; + + /* Start the core running */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, + ADSP1_CORE_ENA | ADSP1_START); + break; + + case SND_SOC_DAPM_PRE_PMD: + /* Halt the core */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, 0); + + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, + ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); + + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, 0); + break; + + default: + break; + } + + return 0; + +err: + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, 0); + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp1_event); + +static int wm_adsp2_ena(struct wm_adsp *dsp) +{ + unsigned int val; + int ret, count; + + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, ADSP2_SYS_ENA); + if (ret != 0) + return ret; + + /* Wait for the RAM to start, should be near instantaneous */ + count = 0; + do { + ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, + &val); + if (ret != 0) + return ret; + } while (!(val & ADSP2_RAM_RDY) && ++count < 10); + + if (!(val & ADSP2_RAM_RDY)) { + adsp_err(dsp, "Failed to start DSP RAM\n"); + return -EBUSY; + } + + adsp_dbg(dsp, "RAM ready after %d polls\n", count); + adsp_info(dsp, "RAM ready after %d polls\n", count); + + return 0; +} + +int wm_adsp2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + unsigned int val; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* + * For simplicity set the DSP clock rate to be the + * SYSCLK rate rather than making it configurable. + */ + ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); + if (ret != 0) { + adsp_err(dsp, "Failed to read SYSCLK state: %d\n", + ret); + return ret; + } + val = (val & ARIZONA_SYSCLK_FREQ_MASK) + >> ARIZONA_SYSCLK_FREQ_SHIFT; + + ret = regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CLOCKING, + ADSP2_CLK_SEL_MASK, val); + if (ret != 0) { + adsp_err(dsp, "Failed to set clock rate: %d\n", + ret); + return ret; + } + + if (dsp->dvfs) { + ret = regmap_read(dsp->regmap, + dsp->base + ADSP2_CLOCKING, &val); + if (ret != 0) { + dev_err(dsp->dev, + "Failed to read clocking: %d\n", ret); + return ret; + } + + if ((val & ADSP2_CLK_SEL_MASK) >= 3) { + ret = regulator_enable(dsp->dvfs); + if (ret != 0) { + dev_err(dsp->dev, + "Failed to enable supply: %d\n", + ret); + return ret; + } + + ret = regulator_set_voltage(dsp->dvfs, + 1800000, + 1800000); + if (ret != 0) { + dev_err(dsp->dev, + "Failed to raise supply: %d\n", + ret); + return ret; + } + } + } + + ret = wm_adsp2_ena(dsp); + if (ret != 0) + return ret; + + ret = wm_adsp_load(dsp); + if (ret != 0) + goto err; + + ret = wm_adsp_load_coeff(dsp); + if (ret != 0) + goto err; + + ret = regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_CORE_ENA | ADSP2_START, + ADSP2_CORE_ENA | ADSP2_START); + if (ret != 0) + goto err; + break; + + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA | ADSP2_CORE_ENA | + ADSP2_START, 0); + + if (dsp->dvfs) { + ret = regulator_set_voltage(dsp->dvfs, 1200000, + 1800000); + if (ret != 0) + dev_warn(dsp->dev, + "Failed to lower supply: %d\n", + ret); + + ret = regulator_disable(dsp->dvfs); + if (ret != 0) + dev_err(dsp->dev, + "Failed to enable supply: %d\n", + ret); + } + break; + + default: + break; + } + + return 0; +err: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp2_event); + +int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) +{ + int ret; + + /* + * Disable the DSP memory by default when in reset for a small + * power saving. + */ + ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); + if (ret != 0) { + adsp_err(adsp, "Failed to clear memory retention: %d\n", ret); + return ret; + } + + if (dvfs) { + adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); + if (IS_ERR(adsp->dvfs)) { + ret = PTR_ERR(adsp->dvfs); + dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); + return ret; + } + + ret = regulator_enable(adsp->dvfs); + if (ret != 0) { + dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", + ret); + return ret; + } + + ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); + if (ret != 0) { + dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", + ret); + return ret; + } + + ret = regulator_disable(adsp->dvfs); + if (ret != 0) { + dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", + ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_init); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h new file mode 100644 index 000000000000..ffd29a4609e2 --- /dev/null +++ b/sound/soc/codecs/wm_adsp.h @@ -0,0 +1,59 @@ +/* + * wm_adsp.h -- Wolfson ADSP support + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __WM_ADSP_H +#define __WM_ADSP_H + +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include "wmfw.h" + +struct regulator; + +struct wm_adsp_region { + int type; + unsigned int base; +}; + +struct wm_adsp { + const char *part; + int num; + int type; + struct device *dev; + struct regmap *regmap; + + int base; + + const struct wm_adsp_region *mem; + int num_mems; + + struct regulator *dvfs; +}; + +#define WM_ADSP1(wname, num) \ + { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ + .shift = num, .event = wm_adsp1_event, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } + +#define WM_ADSP2(wname, num) \ +{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ + .shift = num, .event = wm_adsp2_event, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } + +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); +int wm_adsp2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); + +#endif diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h new file mode 100644 index 000000000000..5632ded67fdd --- /dev/null +++ b/sound/soc/codecs/wmfw.h @@ -0,0 +1,128 @@ +/* + * wmfw.h - Wolfson firmware format information + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __WMFW_H +#define __WMFW_H + +#include <linux/types.h> + +struct wmfw_header { + char magic[4]; + __le32 len; + __le16 rev; + u8 core; + u8 ver; +} __packed; + +struct wmfw_footer { + __le64 timestamp; + __le32 checksum; +} __packed; + +struct wmfw_adsp1_sizes { + __le32 dm; + __le32 pm; + __le32 zm; +} __packed; + +struct wmfw_adsp2_sizes { + __le32 xm; + __le32 ym; + __le32 pm; + __le32 zm; +} __packed; + +struct wmfw_region { + union { + __be32 type; + __le32 offset; + }; + __le32 len; + u8 data[]; +} __packed; + +struct wmfw_id_hdr { + __be32 core_id; + __be32 core_rev; + __be32 id; + __be32 ver; +} __packed; + +struct wmfw_adsp1_id_hdr { + struct wmfw_id_hdr fw; + __be32 zm; + __be32 dm; + __be32 algs; +} __packed; + +struct wmfw_adsp2_id_hdr { + struct wmfw_id_hdr fw; + __be32 zm; + __be32 xm; + __be32 ym; + __be32 algs; +} __packed; + +struct wmfw_alg_hdr { + __be32 id; + __be32 ver; +} __packed; + +struct wmfw_adsp1_alg_hdr { + struct wmfw_alg_hdr alg; + __be32 zm; + __be32 dm; +} __packed; + +struct wmfw_adsp2_alg_hdr { + struct wmfw_alg_hdr alg; + __be32 zm; + __be32 xm; + __be32 ym; +} __packed; + +struct wmfw_coeff_hdr { + u8 magic[4]; + __le32 len; + __le32 ver; + u8 data[]; +} __packed; + +struct wmfw_coeff_item { + union { + __be32 type; + __le32 offset; + }; + __le32 id; + __le32 ver; + __le32 sr; + __le32 len; + u8 data[]; +} __packed; + +#define WMFW_ADSP1 1 +#define WMFW_ADSP2 2 + +#define WMFW_ABSOLUTE 0xf0 +#define WMFW_NAME_TEXT 0xfe +#define WMFW_INFO_TEXT 0xff + +#define WMFW_ADSP1_PM 2 +#define WMFW_ADSP1_DM 3 +#define WMFW_ADSP1_ZM 4 + +#define WMFW_ADSP2_PM 2 +#define WMFW_ADSP2_ZM 4 +#define WMFW_ADSP2_XM 5 +#define WMFW_ADSP2_YM 6 + +#endif diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 6fac5af13298..d55e6477bff0 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -71,6 +71,11 @@ static int evm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + /* set the CPU system clock */ + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + return 0; } diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 714e51e5be5b..55e2bf652bef 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -199,6 +199,7 @@ #define ACLKXE BIT(5) #define TX_ASYNC BIT(6) #define ACLKXPOL BIT(7) +#define ACLKXDIV_MASK 0x1f /* * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits @@ -207,6 +208,7 @@ #define ACLKRE BIT(5) #define RX_ASYNC BIT(6) #define ACLKRPOL BIT(7) +#define ACLKRDIV_MASK 0x1f /* * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control @@ -215,6 +217,7 @@ #define AHCLKXDIV(val) (val) #define AHCLKXPOL BIT(14) #define AHCLKXE BIT(15) +#define AHCLKXDIV_MASK 0xfff /* * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control @@ -223,6 +226,7 @@ #define AHCLKRDIV(val) (val) #define AHCLKRPOL BIT(14) #define AHCLKRE BIT(15) +#define AHCLKRDIV_MASK 0xfff /* * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits @@ -473,6 +477,23 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); void __iomem *base = dev->base; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_AC97: + mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + break; + default: + /* configure a full-word SYNC pulse (LRCLK) */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + + /* make 1st data bit occur one ACLK cycle after the frame sync */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, FSXDLY(1)); + mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, FSRDLY(1)); + break; + } + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* codec is clock and frame slave */ @@ -482,8 +503,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, - ACLKX | AHCLKX | AFSX); + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, ACLKX | AFSX); break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ @@ -554,59 +574,75 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static int davinci_config_channel_size(struct davinci_audio_dev *dev, - int channel_size) +static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - u32 fmt = 0; - u32 mask, rotate; - - switch (channel_size) { - case DAVINCI_AUDIO_WORD_8: - fmt = 0x03; - rotate = 6; - mask = 0x000000ff; - break; + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); - case DAVINCI_AUDIO_WORD_12: - fmt = 0x05; - rotate = 5; - mask = 0x00000fff; + switch (div_id) { + case 0: /* MCLK divider */ + mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, + AHCLKXDIV(div - 1), AHCLKXDIV_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, + AHCLKRDIV(div - 1), AHCLKRDIV_MASK); break; - case DAVINCI_AUDIO_WORD_16: - fmt = 0x07; - rotate = 4; - mask = 0x0000ffff; + case 1: /* BCLK divider */ + mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, + ACLKXDIV(div - 1), ACLKXDIV_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKRCTL_REG, + ACLKRDIV(div - 1), ACLKRDIV_MASK); break; - case DAVINCI_AUDIO_WORD_20: - fmt = 0x09; - rotate = 3; - mask = 0x000fffff; + case 2: /* BCLK/LRCLK ratio */ + dev->bclk_lrclk_ratio = div; break; - case DAVINCI_AUDIO_WORD_24: - fmt = 0x0B; - rotate = 2; - mask = 0x00ffffff; - break; + default: + return -EINVAL; + } - case DAVINCI_AUDIO_WORD_28: - fmt = 0x0D; - rotate = 1; - mask = 0x0fffffff; - break; + return 0; +} - case DAVINCI_AUDIO_WORD_32: - fmt = 0x0F; - rotate = 0; - mask = 0xffffffff; - break; +static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); - default: - return -EINVAL; + if (dir == SND_SOC_CLOCK_OUT) { + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); + mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX); + } else { + mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX); } + return 0; +} + +static int davinci_config_channel_size(struct davinci_audio_dev *dev, + int word_length) +{ + u32 fmt; + u32 rotate = (32 - word_length) / 4; + u32 mask = (1ULL << word_length) - 1; + + /* + * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() + * callback, take it into account here. That allows us to for example + * send 32 bits per channel to the codec, while only 16 of them carry + * audio payload. + * The clock ratio is given for a full period of data (both left and + * right channels), so it has to be divided by 2. + */ + if (dev->bclk_lrclk_ratio) + word_length = dev->bclk_lrclk_ratio / 2; + + /* mapping of the XSSZ bit-field as described in the datasheet */ + fmt = (word_length >> 1) - 1; + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), RXSSZ(0x0F)); mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, @@ -709,8 +745,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) if (stream == SNDRV_PCM_STREAM_PLAYBACK) { /* bit stream is MSB first with no delay */ /* DSP_B mode */ - mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, - AHCLKXE); mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask); mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD); @@ -720,14 +754,10 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) else printk(KERN_ERR "playback tdm slot %d not supported\n", dev->tdm_slots); - - mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); } else { /* bit stream is MSB first with no delay */ /* DSP_B mode */ mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD); - mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, - AHCLKRE); mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask); if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32)) @@ -736,8 +766,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) else printk(KERN_ERR "capture tdm slot %d not supported\n", dev->tdm_slots); - - mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); } } @@ -800,19 +828,27 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8: dma_params->data_type = 1; - word_length = DAVINCI_AUDIO_WORD_8; + word_length = 8; break; case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE: dma_params->data_type = 2; - word_length = DAVINCI_AUDIO_WORD_16; + word_length = 16; + break; + + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + dma_params->data_type = 3; + word_length = 24; break; + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_U32_LE: case SNDRV_PCM_FORMAT_S32_LE: dma_params->data_type = 4; - word_length = DAVINCI_AUDIO_WORD_32; + word_length = 32; break; default: @@ -880,13 +916,18 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, - + .set_clkdiv = davinci_mcasp_set_clkdiv, + .set_sysclk = davinci_mcasp_set_sysclk, }; #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_U8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_U24_3LE | \ SNDRV_PCM_FMTBIT_S32_LE | \ SNDRV_PCM_FMTBIT_U32_LE) @@ -1089,7 +1130,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev->tdm_slots = pdata->tdm_slots; dev->num_serializer = pdata->num_serializer; dev->serial_dir = pdata->serial_dir; - dev->codec_fmt = pdata->codec_fmt; dev->version = pdata->version; dev->txnumevt = pdata->txnumevt; dev->rxnumevt = pdata->rxnumevt; @@ -1098,6 +1138,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_playback; dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + mem->start); @@ -1115,6 +1156,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_capture; dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + mem->start); diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 0de9ed6ce038..0edd3b5a37fd 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -23,26 +23,14 @@ #include "davinci-pcm.h" -#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000 +#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_I2S_DAI 0 #define DAVINCI_MCASP_DIT_DAI 1 -enum { - DAVINCI_AUDIO_WORD_8 = 0, - DAVINCI_AUDIO_WORD_12, - DAVINCI_AUDIO_WORD_16, - DAVINCI_AUDIO_WORD_20, - DAVINCI_AUDIO_WORD_24, - DAVINCI_AUDIO_WORD_32, - DAVINCI_AUDIO_WORD_28, /* This is only valid for McASP */ -}; - struct davinci_audio_dev { struct davinci_pcm_dma_params dma_params[2]; void __iomem *base; - int sample_rate; struct device *dev; - unsigned int codec_fmt; /* McASP specific data */ int tdm_slots; @@ -50,6 +38,7 @@ struct davinci_audio_dev { u8 num_serializer; u8 *serial_dir; u8 version; + u8 bclk_lrclk_ratio; /* McASP FIFO related */ u8 txnumevt; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 93ea3bf567e1..afab81f844ae 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/dma-mapping.h> #include <linux/kernel.h> +#include <linux/genalloc.h> #include <sound/core.h> #include <sound/pcm.h> @@ -23,7 +24,6 @@ #include <sound/soc.h> #include <asm/dma.h> -#include <mach/sram.h> #include "davinci-pcm.h" @@ -67,13 +67,9 @@ static struct snd_pcm_hardware pcm_hardware_playback = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| SNDRV_PCM_INFO_BATCH), .formats = DAVINCI_PCM_FMTBITS, - .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_KNOT), + .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 2, .channels_max = 384, .buffer_bytes_max = 128 * 1024, @@ -90,13 +86,9 @@ static struct snd_pcm_hardware pcm_hardware_capture = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_BATCH), .formats = DAVINCI_PCM_FMTBITS, - .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_KNOT), + .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 2, .channels_max = 384, .buffer_bytes_max = 128 * 1024, @@ -259,7 +251,9 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) } } -static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, +#ifdef CONFIG_GENERIC_ALLOCATOR +static int allocate_sram(struct snd_pcm_substream *substream, + struct gen_pool *sram_pool, unsigned size, struct snd_pcm_hardware *ppcm) { struct snd_dma_buffer *buf = &substream->dma_buffer; @@ -271,9 +265,10 @@ static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, return 0; ppcm->period_bytes_max = size; - iram_virt = sram_alloc(size, &iram_phys); + iram_virt = (void *)gen_pool_alloc(sram_pool, size); if (!iram_virt) goto exit1; + iram_phys = gen_pool_virt_to_phys(sram_pool, (unsigned)iram_virt); iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); if (!iram_dma) goto exit2; @@ -285,11 +280,33 @@ static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, return 0; exit2: if (iram_virt) - sram_free(iram_virt, size); + gen_pool_free(sram_pool, (unsigned)iram_virt, size); exit1: return -ENOMEM; } +static void davinci_free_sram(struct snd_pcm_substream *substream, + struct snd_dma_buffer *iram_dma) +{ + struct davinci_runtime_data *prtd = substream->runtime->private_data; + struct gen_pool *sram_pool = prtd->params->sram_pool; + + gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes); +} +#else +static int allocate_sram(struct snd_pcm_substream *substream, + struct gen_pool *sram_pool, unsigned size, + struct snd_pcm_hardware *ppcm) +{ + return 0; +} + +static void davinci_free_sram(struct snd_pcm_substream *substream, + struct snd_dma_buffer *iram_dma) +{ +} +#endif + /* * Only used with ping/pong. * This is called after runtime->dma_addr, period_bytes and data_type are valid @@ -676,7 +693,7 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? &pcm_hardware_playback : &pcm_hardware_capture; - allocate_sram(substream, params->sram_size, ppcm); + allocate_sram(substream, params->sram_pool, params->sram_size, ppcm); snd_soc_set_runtime_hwparams(substream, ppcm); /* ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, @@ -819,7 +836,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) buf->area = NULL; iram_dma = buf->private_data; if (iram_dma) { - sram_free(iram_dma->area, iram_dma->bytes); + davinci_free_sram(substream, iram_dma); kfree(iram_dma); } } diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index fc4d01cdd8c9..b6ef7039dd09 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -12,6 +12,7 @@ #ifndef _DAVINCI_PCM_H #define _DAVINCI_PCM_H +#include <linux/genalloc.h> #include <linux/platform_data/davinci_asp.h> #include <mach/edma.h> @@ -20,6 +21,7 @@ struct davinci_pcm_dma_params { unsigned short acnt; dma_addr_t dma_addr; /* device physical address for DMA */ unsigned sram_size; + struct gen_pool *sram_pool; /* SRAM gen_pool for ping pong */ enum dma_event_q asp_chan_q; /* event queue number for ASP channel */ enum dma_event_q ram_chan_q; /* event queue number for RAM channel */ unsigned char data_type; /* xfer data type */ diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 4563b28bd625..3b98159d9645 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -46,6 +46,20 @@ config SND_SOC_P1022_DS This will also include the Wolfson Microelectronics WM8776 codec driver. +config SND_SOC_P1022_RDK + tristate "ALSA SoC support for the Freescale / iVeia P1022 RDK board" + # I2C is necessary for the WM8960 driver + depends on P1022_RDK && I2C + select SND_SOC_FSL_SSI + select SND_SOC_FSL_UTILS + select SND_SOC_POWERPC_DMA + select SND_SOC_WM8960 + default y if P1022_RDK + help + Say Y if you want to enable audio on the Freescale / iVeia + P1022 RDK board. This will also include the Wolfson + Microelectronics WM8960 codec driver. + config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" depends on PPC_MPC52xx && PPC_BESTCOMM @@ -98,12 +112,12 @@ config SND_SOC_IMX_PCM tristate config SND_SOC_IMX_PCM_FIQ - tristate + bool select FIQ select SND_SOC_IMX_PCM config SND_SOC_IMX_PCM_DMA - tristate + bool select SND_SOC_DMAENGINE_PCM select SND_SOC_IMX_PCM @@ -112,7 +126,7 @@ config SND_SOC_IMX_AUDMUX config SND_MXC_SOC_WM1133_EV1 tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted" - depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL + depends on MACH_MX31ADS_WM1133_EV1 select SND_SOC_WM8350 select SND_SOC_IMX_PCM_FIQ select SND_SOC_IMX_AUDMUX diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 5f3cf3f52ea0..afd34794db53 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -6,6 +6,10 @@ obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o snd-soc-p1022-ds-objs := p1022_ds.o obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o +# P1022 RDK Machine Support +snd-soc-p1022-rdk-objs := p1022_rdk.o +obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o + # Freescale PowerPC SSI/DMA Platform Support snd-soc-fsl-ssi-objs := fsl_ssi.o snd-soc-fsl-utils-objs := fsl_utils.o @@ -26,14 +30,18 @@ obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o # i.MX Platform Support snd-soc-imx-ssi-objs := imx-ssi.o snd-soc-imx-audmux-objs := imx-audmux.o +snd-soc-imx-pcm-objs := imx-pcm.o +ifneq ($(CONFIG_SND_SOC_IMX_PCM_FIQ),) + snd-soc-imx-pcm-objs += imx-pcm-fiq.o +endif +ifneq ($(CONFIG_SND_SOC_IMX_PCM_DMA),) + snd-soc-imx-pcm-objs += imx-pcm-dma.o +endif obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o -snd-soc-imx-pcm-y := imx-pcm.o -snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o -snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c index 93dc360b1777..d5cd9eff3b48 100644 --- a/sound/soc/fsl/imx-pcm.c +++ b/sound/soc/fsl/imx-pcm.c @@ -103,3 +103,7 @@ void imx_pcm_free(struct snd_pcm *pcm) } } EXPORT_SYMBOL_GPL(imx_pcm_free); + +MODULE_DESCRIPTION("Freescale i.MX PCM driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 199408ec4261..3d9b1c427ce9 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -162,6 +162,7 @@ static int __devinit imx_sgtl5000_probe(struct platform_device *pdev) if (ret) goto clk_fail; data->card.num_links = 1; + data->card.owner = THIS_MODULE; data->card.dai_link = &data->dai; data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c new file mode 100644 index 000000000000..897e32ffdc42 --- /dev/null +++ b/sound/soc/fsl/p1022_rdk.c @@ -0,0 +1,392 @@ +/** + * Freescale P1022RDK ALSA SoC Machine driver + * + * Author: Timur Tabi <timur@freescale.com> + * + * Copyright 2012 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * Note: in order for audio to work correctly, the output controls need + * to be enabled, because they control the clock. So for playback, for + * example: + * + * amixer sset 'Left Output Mixer PCM' on + * amixer sset 'Right Output Mixer PCM' on + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <sound/soc.h> +#include <asm/fsl_guts.h> + +#include "fsl_dma.h" +#include "fsl_ssi.h" +#include "fsl_utils.h" + +/* P1022-specific PMUXCR and DMUXCR bit definitions */ + +#define CCSR_GUTS_PMUXCR_UART0_I2C1_MASK 0x0001c000 +#define CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI 0x00010000 +#define CCSR_GUTS_PMUXCR_UART0_I2C1_SSI 0x00018000 + +#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK 0x00000c00 +#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI 0x00000000 + +#define CCSR_GUTS_DMUXCR_PAD 1 /* DMA controller/channel set to pad */ +#define CCSR_GUTS_DMUXCR_SSI 2 /* DMA controller/channel set to SSI */ + +/* + * Set the DMACR register in the GUTS + * + * The DMACR register determines the source of initiated transfers for each + * channel on each DMA controller. Rather than have a bunch of repetitive + * macros for the bit patterns, we just have a function that calculates + * them. + * + * guts: Pointer to GUTS structure + * co: The DMA controller (0 or 1) + * ch: The channel on the DMA controller (0, 1, 2, or 3) + * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx) + */ +static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts, + unsigned int co, unsigned int ch, unsigned int device) +{ + unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch)); + + clrsetbits_be32(&guts->dmuxcr, 3 << shift, device << shift); +} + +/* There's only one global utilities register */ +static phys_addr_t guts_phys; + +/** + * machine_data: machine-specific ASoC device data + * + * This structure contains data for a single sound platform device on an + * P1022 RDK. Some of the data is taken from the device tree. + */ +struct machine_data { + struct snd_soc_dai_link dai[2]; + struct snd_soc_card card; + unsigned int dai_format; + unsigned int codec_clk_direction; + unsigned int cpu_clk_direction; + unsigned int clk_frequency; + unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */ + unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ + char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ +}; + +/** + * p1022_rdk_machine_probe: initialize the board + * + * This function is used to initialize the board-specific hardware. + * + * Here we program the DMACR and PMUXCR registers. + */ +static int p1022_rdk_machine_probe(struct snd_soc_card *card) +{ + struct machine_data *mdata = + container_of(card, struct machine_data, card); + struct ccsr_guts __iomem *guts; + + guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); + if (!guts) { + dev_err(card->dev, "could not map global utilities\n"); + return -ENOMEM; + } + + /* Enable SSI Tx signal */ + clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK, + CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI); + + /* Enable SSI Rx signal */ + clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK, + CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI); + + /* Enable DMA Channel for SSI */ + guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], + CCSR_GUTS_DMUXCR_SSI); + + guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], + CCSR_GUTS_DMUXCR_SSI); + + iounmap(guts); + + return 0; +} + +/** + * p1022_rdk_startup: program the board with various hardware parameters + * + * This function takes board-specific information, like clock frequencies + * and serial data formats, and passes that information to the codec and + * transport drivers. + */ +static int p1022_rdk_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct machine_data *mdata = + container_of(rtd->card, struct machine_data, card); + struct device *dev = rtd->card->dev; + int ret = 0; + + /* Tell the codec driver what the serial protocol is. */ + ret = snd_soc_dai_set_fmt(rtd->codec_dai, mdata->dai_format); + if (ret < 0) { + dev_err(dev, "could not set codec driver audio format (ret=%i)\n", + ret); + return ret; + } + + ret = snd_soc_dai_set_pll(rtd->codec_dai, 0, 0, mdata->clk_frequency, + mdata->clk_frequency); + if (ret < 0) { + dev_err(dev, "could not set codec PLL frequency (ret=%i)\n", + ret); + return ret; + } + + return 0; +} + +/** + * p1022_rdk_machine_remove: Remove the sound device + * + * This function is called to remove the sound device for one SSI. We + * de-program the DMACR and PMUXCR register. + */ +static int p1022_rdk_machine_remove(struct snd_soc_card *card) +{ + struct machine_data *mdata = + container_of(card, struct machine_data, card); + struct ccsr_guts __iomem *guts; + + guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); + if (!guts) { + dev_err(card->dev, "could not map global utilities\n"); + return -ENOMEM; + } + + /* Restore the signal routing */ + clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK); + clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK); + guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], 0); + guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], 0); + + iounmap(guts); + + return 0; +} + +/** + * p1022_rdk_ops: ASoC machine driver operations + */ +static struct snd_soc_ops p1022_rdk_ops = { + .startup = p1022_rdk_startup, +}; + +/** + * p1022_rdk_probe: platform probe function for the machine driver + * + * Although this is a machine driver, the SSI node is the "master" node with + * respect to audio hardware connections. Therefore, we create a new ASoC + * device for each new SSI node that has a codec attached. + */ +static int p1022_rdk_probe(struct platform_device *pdev) +{ + struct device *dev = pdev->dev.parent; + /* ssi_pdev is the platform device for the SSI node that probed us */ + struct platform_device *ssi_pdev = + container_of(dev, struct platform_device, dev); + struct device_node *np = ssi_pdev->dev.of_node; + struct device_node *codec_np = NULL; + struct machine_data *mdata; + const u32 *iprop; + int ret; + + /* Find the codec node for this SSI. */ + codec_np = of_parse_phandle(np, "codec-handle", 0); + if (!codec_np) { + dev_err(dev, "could not find codec node\n"); + return -EINVAL; + } + + mdata = kzalloc(sizeof(struct machine_data), GFP_KERNEL); + if (!mdata) { + ret = -ENOMEM; + goto error_put; + } + + mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev); + mdata->dai[0].ops = &p1022_rdk_ops; + + /* ASoC core can match codec with device node */ + mdata->dai[0].codec_of_node = codec_np; + + /* + * We register two DAIs per SSI, one for playback and the other for + * capture. We support codecs that have separate DAIs for both playback + * and capture. + */ + memcpy(&mdata->dai[1], &mdata->dai[0], sizeof(struct snd_soc_dai_link)); + + /* The DAI names from the codec (snd_soc_dai_driver.name) */ + mdata->dai[0].codec_dai_name = "wm8960-hifi"; + mdata->dai[1].codec_dai_name = mdata->dai[0].codec_dai_name; + + /* + * Configure the SSI for I2S slave mode. Older device trees have + * an fsl,mode property, but we ignore that since there's really + * only one way to configure the SSI. + */ + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM; + mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; + mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; + + /* + * In i2s-slave mode, the codec has its own clock source, so we + * need to get the frequency from the device tree and pass it to + * the codec driver. + */ + iprop = of_get_property(codec_np, "clock-frequency", NULL); + if (!iprop || !*iprop) { + dev_err(&pdev->dev, "codec bus-frequency property is missing or invalid\n"); + ret = -EINVAL; + goto error; + } + mdata->clk_frequency = be32_to_cpup(iprop); + + if (!mdata->clk_frequency) { + dev_err(&pdev->dev, "unknown clock frequency\n"); + ret = -EINVAL; + goto error; + } + + /* Find the playback DMA channel to use. */ + mdata->dai[0].platform_name = mdata->platform_name[0]; + ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], + &mdata->dma_channel_id[0], + &mdata->dma_id[0]); + if (ret) { + dev_err(&pdev->dev, "missing/invalid playback DMA phandle (ret=%i)\n", + ret); + goto error; + } + + /* Find the capture DMA channel to use. */ + mdata->dai[1].platform_name = mdata->platform_name[1]; + ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1], + &mdata->dma_channel_id[1], + &mdata->dma_id[1]); + if (ret) { + dev_err(&pdev->dev, "missing/invalid capture DMA phandle (ret=%i)\n", + ret); + goto error; + } + + /* Initialize our DAI data structure. */ + mdata->dai[0].stream_name = "playback"; + mdata->dai[1].stream_name = "capture"; + mdata->dai[0].name = mdata->dai[0].stream_name; + mdata->dai[1].name = mdata->dai[1].stream_name; + + mdata->card.probe = p1022_rdk_machine_probe; + mdata->card.remove = p1022_rdk_machine_remove; + mdata->card.name = pdev->name; /* The platform driver name */ + mdata->card.owner = THIS_MODULE; + mdata->card.dev = &pdev->dev; + mdata->card.num_links = 2; + mdata->card.dai_link = mdata->dai; + + /* Register with ASoC */ + ret = snd_soc_register_card(&mdata->card); + if (ret) { + dev_err(&pdev->dev, "could not register card (ret=%i)\n", ret); + goto error; + } + + return 0; + +error: + kfree(mdata); +error_put: + of_node_put(codec_np); + return ret; +} + +/** + * p1022_rdk_remove: remove the platform device + * + * This function is called when the platform device is removed. + */ +static int __devexit p1022_rdk_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct machine_data *mdata = + container_of(card, struct machine_data, card); + + snd_soc_unregister_card(card); + kfree(mdata); + + return 0; +} + +static struct platform_driver p1022_rdk_driver = { + .probe = p1022_rdk_probe, + .remove = __devexit_p(p1022_rdk_remove), + .driver = { + /* + * The name must match 'compatible' property in the device tree, + * in lowercase letters. + */ + .name = "snd-soc-p1022rdk", + .owner = THIS_MODULE, + }, +}; + +/** + * p1022_rdk_init: machine driver initialization. + * + * This function is called when this module is loaded. + */ +static int __init p1022_rdk_init(void) +{ + struct device_node *guts_np; + struct resource res; + + /* Get the physical address of the global utilities registers */ + guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); + if (of_address_to_resource(guts_np, 0, &res)) { + pr_err("snd-soc-p1022rdk: missing/invalid global utils node\n"); + of_node_put(guts_np); + return -EINVAL; + } + guts_phys = res.start; + of_node_put(guts_np); + + return platform_driver_register(&p1022_rdk_driver); +} + +/** + * p1022_rdk_exit: machine driver exit + * + * This function is called when this driver is unloaded. + */ +static void __exit p1022_rdk_exit(void) +{ + platform_driver_unregister(&p1022_rdk_driver); +} + +late_initcall(p1022_rdk_init); +module_exit(p1022_rdk_exit); + +MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); +MODULE_DESCRIPTION("Freescale / iVeia P1022 RDK ALSA SoC machine driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 4b63ec8eb372..4d261927662f 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -29,14 +29,14 @@ struct pcm030_audio_data { static struct snd_soc_dai_link pcm030_fabric_dai[] = { { - .name = "AC97", + .name = "AC97.0", .stream_name = "AC97 Analog", .codec_dai_name = "wm9712-hifi", .cpu_dai_name = "mpc5200-psc-ac97.0", .codec_name = "wm9712-codec", }, { - .name = "AC97", + .name = "AC97.1", .stream_name = "AC97 IEC958", .codec_dai_name = "wm9712-aux", .cpu_dai_name = "mpc5200-psc-ac97.1", diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index b9f16598324c..58d5a96b366f 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -22,12 +22,16 @@ #include "kirkwood.h" #define KIRKWOOD_RATES \ - (SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) + (SNDRV_PCM_RATE_8000_192000 | \ + SNDRV_PCM_RATE_CONTINUOUS | \ + SNDRV_PCM_RATE_KNOT) + #define KIRKWOOD_FORMATS \ (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE) struct kirkwood_dma_priv { struct snd_pcm_substream *play_stream; @@ -43,10 +47,10 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = { SNDRV_PCM_INFO_PAUSE), .formats = KIRKWOOD_FORMATS, .rates = KIRKWOOD_RATES, - .rate_min = 44100, - .rate_max = 96000, + .rate_min = 8000, + .rate_max = 384000, .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .buffer_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS, .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, @@ -71,7 +75,6 @@ static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) printk(KERN_WARNING "%s: got err interrupt 0x%lx\n", __func__, cause); writel(cause, priv->io + KIRKWOOD_ERR_CAUSE); - return IRQ_HANDLED; } /* we've enabled only bytes interrupts ... */ @@ -178,7 +181,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) } dram = mv_mbus_dram_info(); - addr = virt_to_phys(substream->dma_buffer.area); + addr = substream->dma_buffer.addr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prdata->play_stream = substream; kirkwood_dma_conf_mbus_windows(priv->io, diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 542538d10ab7..d3629d5927e9 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -95,10 +95,33 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate) do { cpu_relax(); value = readl(io + KIRKWOOD_DCO_SPCR_STATUS); - value &= KIRKWOOD_DCO_SPCR_STATUS; + value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK; } while (value == 0); } +static void kirkwood_set_rate(struct snd_soc_dai *dai, + struct kirkwood_dma_data *priv, unsigned long rate) +{ + uint32_t clks_ctrl; + + if (rate == 44100 || rate == 48000 || rate == 96000) { + /* use internal dco for supported rates */ + dev_dbg(dai->dev, "%s: dco set rate = %lu\n", + __func__, rate); + kirkwood_set_dco(priv->io, rate); + + clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO; + } else if (!IS_ERR(priv->extclk)) { + /* use optional external clk for other rates */ + dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n", + __func__, rate, 256 * rate); + clk_set_rate(priv->extclk, 256 * rate); + + clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK; + } + writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL); +} + static int kirkwood_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -113,26 +136,21 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); - unsigned int i2s_reg, reg; - unsigned long i2s_value, value; + uint32_t ctl_play, ctl_rec; + unsigned int i2s_reg; + unsigned long i2s_value; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { i2s_reg = KIRKWOOD_I2S_PLAYCTL; - reg = KIRKWOOD_PLAYCTL; } else { i2s_reg = KIRKWOOD_I2S_RECCTL; - reg = KIRKWOOD_RECCTL; } - /* set dco conf */ - kirkwood_set_dco(priv->io, params_rate(params)); + kirkwood_set_rate(dai, priv, params_rate(params)); i2s_value = readl(priv->io+i2s_reg); i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; - value = readl(priv->io+reg); - value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK; - /* * Size settings in play/rec i2s control regs and play/rec control * regs must be the same. @@ -140,38 +158,57 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; - value |= KIRKWOOD_PLAYCTL_SIZE_16_C; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C | + KIRKWOOD_RECCTL_I2S_EN; break; /* * doesn't work... S20_3LE != kirkwood 20bit format ? * case SNDRV_PCM_FORMAT_S20_3LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20; - value |= KIRKWOOD_PLAYCTL_SIZE_20; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_20 | + KIRKWOOD_RECCTL_I2S_EN; break; */ case SNDRV_PCM_FORMAT_S24_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; - value |= KIRKWOOD_PLAYCTL_SIZE_24; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_24 | + KIRKWOOD_RECCTL_I2S_EN; break; case SNDRV_PCM_FORMAT_S32_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; - value |= KIRKWOOD_PLAYCTL_SIZE_32; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_32 | + KIRKWOOD_RECCTL_I2S_EN; break; default: return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - value &= ~KIRKWOOD_PLAYCTL_MONO_MASK; if (params_channels(params) == 1) - value |= KIRKWOOD_PLAYCTL_MONO_BOTH; + ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH; else - value |= KIRKWOOD_PLAYCTL_MONO_OFF; + ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF; + + priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK | + KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN | + KIRKWOOD_PLAYCTL_SIZE_MASK); + priv->ctl_play |= ctl_play; + } else { + priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK; + priv->ctl_rec |= ctl_rec; } writel(i2s_value, priv->io+i2s_reg); - writel(value, priv->io+reg); return 0; } @@ -180,67 +217,70 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); - unsigned long value; - - /* - * specs says KIRKWOOD_PLAYCTL must be read 2 times before - * changing it. So read 1 time here and 1 later. - */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); + uint32_t ctl, value; + + ctl = readl(priv->io + KIRKWOOD_PLAYCTL); + if (ctl & KIRKWOOD_PLAYCTL_PAUSE) { + unsigned timeout = 5000; + /* + * The Armada510 spec says that if we enter pause mode, the + * busy bit must be read back as clear _twice_. Make sure + * we respect that otherwise we get DMA underruns. + */ + do { + value = ctl; + ctl = readl(priv->io + KIRKWOOD_PLAYCTL); + if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)) + break; + udelay(1); + } while (timeout--); + + if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY) + dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n", + ctl); + } switch (cmd) { case SNDRV_PCM_TRIGGER_START: - /* stop audio, enable interrupts */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE; + /* configure */ + ctl = priv->ctl_play; + value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN); writel(value, priv->io + KIRKWOOD_PLAYCTL); + /* enable interrupts */ value = readl(priv->io + KIRKWOOD_INT_MASK); value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); - /* configure audio & enable i2s playback */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~KIRKWOOD_PLAYCTL_BURST_MASK; - value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE - | KIRKWOOD_PLAYCTL_SPDIF_EN); - - if (priv->burst == 32) - value |= KIRKWOOD_PLAYCTL_BURST_32; - else - value |= KIRKWOOD_PLAYCTL_BURST_128; - value |= KIRKWOOD_PLAYCTL_I2S_EN; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + /* enable playback */ + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_STOP: /* stop audio, disable interrupts */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); value = readl(priv->io + KIRKWOOD_INT_MASK); value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); /* disable all playbacks */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; default: @@ -254,35 +294,24 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); - unsigned long value; + uint32_t ctl, value; value = readl(priv->io + KIRKWOOD_RECCTL); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - /* stop audio, enable interrupts */ - value = readl(priv->io + KIRKWOOD_RECCTL); - value |= KIRKWOOD_RECCTL_PAUSE; + /* configure */ + ctl = priv->ctl_rec; + value = ctl & ~KIRKWOOD_RECCTL_I2S_EN; writel(value, priv->io + KIRKWOOD_RECCTL); + /* enable interrupts */ value = readl(priv->io + KIRKWOOD_INT_MASK); value |= KIRKWOOD_INT_CAUSE_REC_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); - /* configure audio & enable i2s record */ - value = readl(priv->io + KIRKWOOD_RECCTL); - value &= ~KIRKWOOD_RECCTL_BURST_MASK; - value &= ~KIRKWOOD_RECCTL_MONO; - value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE - | KIRKWOOD_RECCTL_SPDIF_EN); - - if (priv->burst == 32) - value |= KIRKWOOD_RECCTL_BURST_32; - else - value |= KIRKWOOD_RECCTL_BURST_128; - value |= KIRKWOOD_RECCTL_I2S_EN; - - writel(value, priv->io + KIRKWOOD_RECCTL); + /* enable record */ + writel(ctl, priv->io + KIRKWOOD_RECCTL); break; case SNDRV_PCM_TRIGGER_STOP: @@ -389,90 +418,125 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { .channels_min = 1, .channels_max = 2, .rates = KIRKWOOD_I2S_RATES, - .formats = KIRKWOOD_I2S_FORMATS,}, + .formats = KIRKWOOD_I2S_FORMATS, + }, .capture = { .channels_min = 1, .channels_max = 2, .rates = KIRKWOOD_I2S_RATES, - .formats = KIRKWOOD_I2S_FORMATS,}, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .ops = &kirkwood_i2s_dai_ops, +}; + +static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { + .probe = kirkwood_i2s_probe, + .remove = kirkwood_i2s_remove, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, .ops = &kirkwood_i2s_dai_ops, }; static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) { - struct resource *mem; - struct kirkwood_asoc_platform_data *data = - pdev->dev.platform_data; + struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; + struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai; struct kirkwood_dma_data *priv; + struct resource *mem; int err; - priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "allocation failed\n"); - err = -ENOMEM; - goto error; + return -ENOMEM; } dev_set_drvdata(&pdev->dev, priv); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "platform_get_resource failed\n"); - err = -ENXIO; - goto err_alloc; - } - - priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME); - if (!priv->mem) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -EBUSY; - goto err_alloc; + return -ENXIO; } - priv->io = ioremap(priv->mem->start, SZ_16K); + priv->io = devm_request_and_ioremap(&pdev->dev, mem); if (!priv->io) { - dev_err(&pdev->dev, "ioremap failed\n"); - err = -ENOMEM; - goto err_iomem; + dev_err(&pdev->dev, "devm_request_and_ioremap failed\n"); + return -ENOMEM; } priv->irq = platform_get_irq(pdev, 0); if (priv->irq <= 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); - err = -ENXIO; - goto err_ioremap; + return -ENXIO; } if (!data) { dev_err(&pdev->dev, "no platform data ?!\n"); - err = -EINVAL; - goto err_ioremap; + return -EINVAL; } priv->burst = data->burst; - priv->clk = clk_get(&pdev->dev, NULL); + priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "no clock\n"); - err = PTR_ERR(priv->clk); - goto err_ioremap; + return PTR_ERR(priv->clk); + } + + err = clk_prepare_enable(priv->clk); + if (err < 0) + return err; + + priv->extclk = clk_get(&pdev->dev, "extclk"); + if (!IS_ERR(priv->extclk)) { + if (priv->extclk == priv->clk) { + clk_put(priv->extclk); + priv->extclk = ERR_PTR(-EINVAL); + } else { + dev_info(&pdev->dev, "found external clock\n"); + clk_prepare_enable(priv->extclk); + soc_dai = &kirkwood_i2s_dai_extclk; + } + } + + /* Some sensible defaults - this reflects the powerup values */ + priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24; + priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24; + + /* Select the burst size */ + if (data->burst == 32) { + priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32; + priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32; + } else { + priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128; + priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128; } - clk_prepare_enable(priv->clk); - err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); + err = snd_soc_register_dai(&pdev->dev, soc_dai); if (!err) return 0; dev_err(&pdev->dev, "snd_soc_register_dai failed\n"); + if (!IS_ERR(priv->extclk)) { + clk_disable_unprepare(priv->extclk); + clk_put(priv->extclk); + } clk_disable_unprepare(priv->clk); - clk_put(priv->clk); - -err_ioremap: - iounmap(priv->io); -err_iomem: - release_mem_region(priv->mem->start, SZ_16K); -err_alloc: - kfree(priv); -error: + return err; } @@ -482,12 +546,11 @@ static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev) snd_soc_unregister_dai(&pdev->dev); + if (!IS_ERR(priv->extclk)) { + clk_disable_unprepare(priv->extclk); + clk_put(priv->extclk); + } clk_disable_unprepare(priv->clk); - clk_put(priv->clk); - - iounmap(priv->io); - release_mem_region(priv->mem->start, SZ_16K); - kfree(priv); return 0; } diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index f9084d83e6bd..4d92637ddb3f 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h @@ -77,6 +77,11 @@ #define KIRKWOOD_DCO_SPCR_STATUS 0x120c #define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16) +#define KIRKWOOD_CLOCKS_CTRL 0x1230 +#define KIRKWOOD_MCLK_SOURCE_MASK (3<<0) +#define KIRKWOOD_MCLK_SOURCE_DCO (0<<0) +#define KIRKWOOD_MCLK_SOURCE_EXTCLK (3<<0) + #define KIRKWOOD_ERR_CAUSE 0x1300 #define KIRKWOOD_ERR_MASK 0x1304 @@ -119,11 +124,13 @@ #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000 struct kirkwood_dma_data { - struct resource *mem; void __iomem *io; + struct clk *clk; + struct clk *extclk; + uint32_t ctl_play; + uint32_t ctl_rec; int irq; int burst; - struct clk *clk; }; #endif diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index c294fbb523fc..b304e375568a 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -229,6 +229,7 @@ int mxs_saif_put_mclk(unsigned int saif_id) saif->mclk_in_use = 0; return 0; } +EXPORT_SYMBOL_GPL(mxs_saif_put_mclk); /* * Get MCLK and set clock rate, then enable it @@ -282,6 +283,7 @@ int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk, return 0; } +EXPORT_SYMBOL_GPL(mxs_saif_get_mclk); /* * SAIF DAI format configuration. diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index afb8d4f1bedf..a9a243860428 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -28,8 +28,6 @@ #include <linux/platform_data/asoc-ti-mcbsp.h> -#include <plat/cpu.h> - #include "mcbsp.h" static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) @@ -612,7 +610,7 @@ void omap_mcbsp_free(struct omap_mcbsp *mcbsp) * system will refuse to enter idle if the CLKS pin source is not reset * back to internal source. */ - if (!cpu_class_is_omap1()) + if (!mcbsp_omap1()) omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); spin_lock(&mcbsp->lock); diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h index 49a67259ce5a..a89791c239a5 100644 --- a/sound/soc/omap/mcbsp.h +++ b/sound/soc/omap/mcbsp.h @@ -26,6 +26,12 @@ #include "omap-pcm.h" +#ifdef CONFIG_ARCH_OMAP1 +#define mcbsp_omap1() 1 +#else +#define mcbsp_omap1() 0 +#endif + /* McBSP register numbers. Register address offset = num * reg_step */ enum { /* Common registers */ diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index a57a4e68dcc6..1d6ea8609d28 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -331,8 +331,8 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) num_links = 1; } - of_property_read_u32(node, "ti,jack-detection", - &priv->jack_detection); + priv->jack_detection = of_property_read_bool(node, + "ti,jack-detection"); of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq); if (!priv->mclk_freq) { diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index a6ee15747859..09167609c93e 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -34,7 +34,6 @@ #include <sound/initval.h> #include <sound/soc.h> -#include <plat/cpu.h> #include <linux/platform_data/asoc-ti-mcbsp.h> #include "mcbsp.h" #include "omap-mcbsp.h" @@ -512,7 +511,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, regs->srgr2 |= CLKSM; break; case OMAP_MCBSP_SYSCLK_CLKS_FCLK: - if (cpu_class_is_omap1()) { + if (mcbsp_omap1()) { err = -EINVAL; break; } @@ -520,7 +519,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, MCBSP_CLKS_PRCM_SRC); break; case OMAP_MCBSP_SYSCLK_CLKS_EXT: - if (cpu_class_is_omap1()) { + if (mcbsp_omap1()) { err = 0; break; } diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 1ff6bb9ade5c..771bff27ac3e 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -37,8 +37,6 @@ #include "omap-mcbsp.h" #include "omap-pcm.h" -#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15) - static int zoom2_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -187,9 +185,6 @@ static int __init zoom2_soc_init(void) if (ret) goto err1; - BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0); - gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0); - return 0; err1: @@ -202,8 +197,6 @@ module_init(zoom2_soc_init); static void __exit zoom2_soc_exit(void) { - gpio_free(ZOOM2_HEADSET_MUX_GPIO); - platform_device_unregister(zoom2_snd_device); } module_exit(zoom2_soc_exit); diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 14fbcd30cae5..cd6c7073c50d 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -442,7 +442,7 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev) ret = -ENODEV; goto err2; } - clk_enable(s3c_ac97.ac97_clk); + clk_prepare_enable(s3c_ac97.ac97_clk); if (ac97_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); @@ -462,13 +462,20 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev) if (ret) goto err5; - return 0; + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); + goto err6; + } + return 0; +err6: + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); err5: free_irq(irq_res->start, NULL); err4: err3: - clk_disable(s3c_ac97.ac97_clk); + clk_disable_unprepare(s3c_ac97.ac97_clk); clk_put(s3c_ac97.ac97_clk); err2: iounmap(s3c_ac97.regs); @@ -482,13 +489,14 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev) { struct resource *mem_res, *irq_res; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (irq_res) free_irq(irq_res->start, NULL); - clk_disable(s3c_ac97.ac97_clk); + clk_disable_unprepare(s3c_ac97.ac97_clk); clk_put(s3c_ac97.ac97_clk); iounmap(s3c_ac97.regs); diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index b56b9a3c6169..01c1c5a2d321 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -18,15 +18,6 @@ #include "../codecs/wm5102.h" #include "../codecs/wm9081.h" -/* - * 44.1kHz based clocks for the SYSCLK domain, use a very high clock - * to allow all the DSP functionality to be enabled if desired. - */ -#define SYSCLK_RATE (44100 * 1024) - -/* 48kHz based clocks for the ASYNC domain */ -#define ASYNCCLK_RATE (48000 * 512) - /* BCLK2 is fixed at this currently */ #define BCLK2_RATE (64 * 8000) @@ -36,15 +27,40 @@ */ #define MCLK_RATE 24576000 -#define WM9081_AUDIO_RATE 44100 -#define WM9081_MCLK_RATE (WM9081_AUDIO_RATE * 256) +#define SYS_AUDIO_RATE 44100 +#define SYS_MCLK_RATE (SYS_AUDIO_RATE * 512) + +#define DAI_AP_DSP 0 +#define DAI_DSP_CODEC 1 +#define DAI_CODEC_CP 2 +#define DAI_CODEC_SUB 3 + +struct bells_drvdata { + int sysclk_rate; + int asyncclk_rate; +}; + +static struct bells_drvdata wm2200_drvdata = { + .sysclk_rate = 22579200, +}; + +static struct bells_drvdata wm5102_drvdata = { + .sysclk_rate = 45158400, + .asyncclk_rate = 49152000, +}; + +static struct bells_drvdata wm5110_drvdata = { + .sysclk_rate = 135475200, + .asyncclk_rate = 147456000, +}; static int bells_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; struct snd_soc_codec *codec = codec_dai->codec; + struct bells_drvdata *bells = card->drvdata; int ret; if (dapm->dev != codec_dai->dev) @@ -52,18 +68,21 @@ static int bells_set_bias_level(struct snd_soc_card *card, switch (level) { case SND_SOC_BIAS_PREPARE: - if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { - ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, - ARIZONA_FLL_SRC_MCLK1, - MCLK_RATE, - SYSCLK_RATE); - if (ret < 0) - pr_err("Failed to start FLL: %d\n", ret); + if (dapm->bias_level != SND_SOC_BIAS_STANDBY) + break; + + ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + bells->sysclk_rate); + if (ret < 0) + pr_err("Failed to start FLL: %d\n", ret); + if (bells->asyncclk_rate) { ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, ARIZONA_FLL_SRC_AIF2BCLK, BCLK2_RATE, - ASYNCCLK_RATE); + bells->asyncclk_rate); if (ret < 0) pr_err("Failed to start FLL: %d\n", ret); } @@ -80,8 +99,9 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; struct snd_soc_codec *codec = codec_dai->codec; + struct bells_drvdata *bells = card->drvdata; int ret; if (dapm->dev != codec_dai->dev) @@ -95,10 +115,13 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, return ret; } - ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 0, 0, 0); - if (ret < 0) { - pr_err("Failed to stop FLL: %d\n", ret); - return ret; + if (bells->asyncclk_rate) { + ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, + 0, 0, 0); + if (ret < 0) { + pr_err("Failed to stop FLL: %d\n", ret); + return ret; + } } break; @@ -113,56 +136,73 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, static int bells_late_probe(struct snd_soc_card *card) { - struct snd_soc_codec *codec = card->rtd[0].codec; - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; - struct snd_soc_dai *aif3_dai = card->rtd[2].cpu_dai; - struct snd_soc_dai *wm9081_dai = card->rtd[2].codec_dai; + struct bells_drvdata *bells = card->drvdata; + struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec; + struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec; + struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai; + struct snd_soc_dai *aif2_dai; + struct snd_soc_dai *aif3_dai; + struct snd_soc_dai *wm9081_dai; int ret; - ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, + bells->sysclk_rate, + SND_SOC_CLOCK_IN); if (ret != 0) { - dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); + dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); return ret; } - ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); + ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); if (ret != 0) { - dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); + dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret); return ret; } - ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); - if (ret != 0) { + ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret != 0) dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); - return ret; - } - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, - ARIZONA_CLK_SRC_FLL1, SYSCLK_RATE, + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, + SYS_MCLK_RATE, SND_SOC_CLOCK_OUT); + if (ret != 0) + dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); + + if (card->num_rtd == DAI_CODEC_CP) + return 0; + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, + ARIZONA_CLK_SRC_FLL2, + bells->asyncclk_rate, SND_SOC_CLOCK_IN); if (ret != 0) { - dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret); return ret; } - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, - WM9081_MCLK_RATE, SND_SOC_CLOCK_OUT); + aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai; + + ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); if (ret != 0) { - dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); + dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); return ret; } - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, - ARIZONA_CLK_SRC_FLL2, ASYNCCLK_RATE, - SND_SOC_CLOCK_IN); + if (card->num_rtd == DAI_CODEC_SUB) + return 0; + + aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai; + wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai; + + ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); if (ret != 0) { - dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); return ret; } ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK, - 0, WM9081_MCLK_RATE, 0); + 0, SYS_MCLK_RATE, 0); if (ret != 0) { dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); return ret; @@ -181,22 +221,57 @@ static const struct snd_soc_pcm_stream baseband_params = { static const struct snd_soc_pcm_stream sub_params = { .formats = SNDRV_PCM_FMTBIT_S32_LE, - .rate_min = WM9081_AUDIO_RATE, - .rate_max = WM9081_AUDIO_RATE, + .rate_min = SYS_AUDIO_RATE, + .rate_max = SYS_AUDIO_RATE, .channels_min = 2, .channels_max = 2, }; +static struct snd_soc_dai_link bells_dai_wm2200[] = { + { + .name = "CPU-DSP", + .stream_name = "CPU-DSP", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", + .codec_dai_name = "wm2200", + .codec_name = "wm2200.1-003a", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link bells_dai_wm5102[] = { { - .name = "CPU", - .stream_name = "CPU", + .name = "CPU-DSP", + .stream_name = "CPU-DSP", .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", .codec_dai_name = "wm5102-aif1", - .platform_name = "samsung-audio", .codec_name = "wm5102-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, }, { .name = "Baseband", @@ -212,7 +287,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5110-aif3", + .cpu_dai_name = "wm5102-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF @@ -224,14 +299,25 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { static struct snd_soc_dai_link bells_dai_wm5110[] = { { - .name = "CPU", - .stream_name = "CPU", + .name = "CPU-DSP", + .stream_name = "CPU-DSP", .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", .codec_dai_name = "wm5110-aif1", - .platform_name = "samsung-audio", .codec_name = "wm5110-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, }, { .name = "Baseband", @@ -247,7 +333,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5102-aif3", + .cpu_dai_name = "wm5110-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF @@ -270,6 +356,24 @@ static struct snd_soc_dapm_route bells_routes[] = { static struct snd_soc_card bells_cards[] = { { + .name = "Bells WM2200", + .owner = THIS_MODULE, + .dai_link = bells_dai_wm2200, + .num_links = ARRAY_SIZE(bells_dai_wm2200), + .codec_conf = bells_codec_conf, + .num_configs = ARRAY_SIZE(bells_codec_conf), + + .late_probe = bells_late_probe, + + .dapm_routes = bells_routes, + .num_dapm_routes = ARRAY_SIZE(bells_routes), + + .set_bias_level = bells_set_bias_level, + .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm2200_drvdata, + }, + { .name = "Bells WM5102", .owner = THIS_MODULE, .dai_link = bells_dai_wm5102, @@ -284,6 +388,8 @@ static struct snd_soc_card bells_cards[] = { .set_bias_level = bells_set_bias_level, .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm5102_drvdata, }, { .name = "Bells WM5110", @@ -300,6 +406,8 @@ static struct snd_soc_card bells_cards[] = { .set_bias_level = bells_set_bias_level, .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm5110_drvdata, }, }; diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index b70964ea448c..64529904a95f 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -432,30 +432,18 @@ static struct snd_soc_platform_driver samsung_asoc_platform = { .pcm_free = dma_free_dma_buffers, }; -static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev) +int __devinit asoc_dma_platform_register(struct device *dev) { - return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform); + return snd_soc_register_platform(dev, &samsung_asoc_platform); } +EXPORT_SYMBOL_GPL(asoc_dma_platform_register); -static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev) +void __devexit asoc_dma_platform_unregister(struct device *dev) { - snd_soc_unregister_platform(&pdev->dev); - return 0; + snd_soc_unregister_platform(dev); } - -static struct platform_driver asoc_dma_driver = { - .driver = { - .name = "samsung-audio", - .owner = THIS_MODULE, - }, - - .probe = samsung_asoc_platform_probe, - .remove = __devexit_p(samsung_asoc_platform_remove), -}; - -module_platform_driver(asoc_dma_driver); +EXPORT_SYMBOL_GPL(asoc_dma_platform_unregister); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-audio"); diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 7d1ead77ef21..73d8c7c8a1e8 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -21,4 +21,7 @@ struct s3c_dma_params { struct samsung_dma_ops *ops; }; +int asoc_dma_platform_register(struct device *dev); +void asoc_dma_platform_unregister(struct device *dev); + #endif diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index c23c2ae91f58..d37ede58e0a8 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -228,7 +228,7 @@ static struct snd_soc_dai_link goni_dai[] = { .stream_name = "WM8994 HiFi", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec.0-001a", .init = goni_wm8994_init, .ops = &goni_hifi_ops, diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index 6e3257717c54..3870e9678b5d 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -207,7 +207,7 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = { .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "uda1380-hifi", .init = h1940_uda1380_init, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", .ops = &h1940_ops, }, diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 40b00a13dcd1..0aa0451823ce 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -49,8 +49,6 @@ struct i2s_dai { struct clk *clk; /* Clock for generating I2S signals */ struct clk *op_clk; - /* Array of clock names for op_clk */ - const char **src_clk; /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ struct i2s_dai *pri_dai; /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */ @@ -423,7 +421,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, if (i2s->op_clk) { if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || (!clk_id && (mod & MOD_IMS_SYSMUX))) { - clk_disable(i2s->op_clk); + clk_disable_unprepare(i2s->op_clk); clk_put(i2s->op_clk); } else { i2s->rclk_srcrate = @@ -432,9 +430,13 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, } } - i2s->op_clk = clk_get(&i2s->pdev->dev, - i2s->src_clk[clk_id]); - clk_enable(i2s->op_clk); + if (clk_id) + i2s->op_clk = clk_get(&i2s->pdev->dev, + "i2s_opclk1"); + else + i2s->op_clk = clk_get(&i2s->pdev->dev, + "i2s_opclk0"); + clk_prepare_enable(i2s->op_clk); i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); /* Over-ride the other's */ @@ -880,7 +882,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) iounmap(i2s->addr); return -ENOENT; } - clk_enable(i2s->clk); + clk_prepare_enable(i2s->clk); if (other) { other->addr = i2s->addr; @@ -922,7 +924,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (i2s->quirks & QUIRK_NEED_RSTCLR) writel(0, i2s->addr + I2SCON); - clk_disable(i2s->clk); + clk_disable_unprepare(i2s->clk); clk_put(i2s->clk); iounmap(i2s->addr); @@ -1007,6 +1009,7 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) sec_dai = dev_get_drvdata(&pdev->dev); snd_soc_register_dai(&sec_dai->pdev->dev, &sec_dai->i2s_dai_drv); + asoc_dma_platform_register(&pdev->dev); return 0; } @@ -1067,7 +1070,6 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) (struct s3c2410_dma_client *)&pri_dai->dma_capture; pri_dai->dma_playback.channel = dma_pl_chan; pri_dai->dma_capture.channel = dma_cp_chan; - pri_dai->src_clk = i2s_cfg->src_clk; pri_dai->dma_playback.dma_size = 4; pri_dai->dma_capture.dma_size = 4; pri_dai->base = regs_base; @@ -1088,7 +1090,6 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) (struct s3c2410_dma_client *)&sec_dai->dma_playback; /* Use iDMA always if SysDMA not provided */ sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1; - sec_dai->src_clk = i2s_cfg->src_clk; sec_dai->dma_playback.dma_size = 4; sec_dai->base = regs_base; sec_dai->quirks = quirks; @@ -1107,6 +1108,8 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); + asoc_dma_platform_register(&pdev->dev); + return 0; err: release_mem_region(regs_base, resource_size(res)); @@ -1135,6 +1138,7 @@ static __devexit int samsung_i2s_remove(struct platform_device *pdev) i2s->pri_dai = NULL; i2s->sec_dai = NULL; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); return 0; diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c index 1578663a1faa..b5f6abd9d221 100644 --- a/sound/soc/samsung/jive_wm8750.c +++ b/sound/soc/samsung/jive_wm8750.c @@ -118,7 +118,7 @@ static struct snd_soc_dai_link jive_dai = { .stream_name = "WM8750", .cpu_dai_name = "s3c2412-i2s", .codec_dai_name = "wm8750-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c2412-i2s", .codec_name = "wm8750.0-001a", .init = jive_wm8750_init, .ops = &jive_ops, diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index ee52c8a00779..0908bb05a5e7 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -145,7 +145,7 @@ static struct snd_soc_dai_link littlemill_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c index 69c4a5934a4d..9342fc270c2b 100644 --- a/sound/soc/samsung/ln2440sbc_alc650.c +++ b/sound/soc/samsung/ln2440sbc_alc650.c @@ -28,7 +28,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { .cpu_dai_name = "samsung-ac97", .codec_dai_name = "ac97-hifi", .codec_name = "ac97-codec", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", }, }; diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 6abf341c4a2a..a71c31af4e0e 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -99,7 +99,7 @@ static struct snd_soc_dai_link lowland_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm5100-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm5100.1-001a", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 321d51134e47..c7e965f80d2e 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -364,7 +364,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { { /* Hifi Playback - for similatious use with voice below */ .name = "WM8753", .stream_name = "WM8753 HiFi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "wm8753-hifi", .codec_name = "wm8753.0-001a", diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index c86081992dfd..ecd509048771 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -543,7 +543,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) ret = PTR_ERR(pcm->cclk); goto err1; } - clk_enable(pcm->cclk); + clk_prepare_enable(pcm->cclk); /* record our pcm structure for later use in the callbacks */ dev_set_drvdata(&pdev->dev, pcm); @@ -568,7 +568,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) ret = -ENOENT; goto err4; } - clk_enable(pcm->pclk); + clk_prepare_enable(pcm->pclk); s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start + S3C_PCM_RXFIFO; @@ -589,17 +589,25 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) goto err5; } + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); + goto err6; + } + return 0; +err6: + snd_soc_unregister_dai(&pdev->dev); err5: - clk_disable(pcm->pclk); + clk_disable_unprepare(pcm->pclk); clk_put(pcm->pclk); err4: iounmap(pcm->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: - clk_disable(pcm->cclk); + clk_disable_unprepare(pcm->cclk); clk_put(pcm->cclk); err1: return ret; @@ -610,6 +618,7 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; struct resource *mem_res; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -619,8 +628,8 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable(pcm->cclk); - clk_disable(pcm->pclk); + clk_disable_unprepare(pcm->cclk); + clk_disable_unprepare(pcm->pclk); clk_put(pcm->pclk); clk_put(pcm->cclk); diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 21e12361a9cd..a5826ea9cad6 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -85,7 +85,7 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = { .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "uda1380-hifi", .init = rx1950_uda1380_init, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", .ops = &rx1950_ops, }, diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index ac7701b3c5dc..edf5f527c5a2 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -162,11 +162,29 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = { static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev) { - return s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + int ret = 0; + + ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + if (ret) { + pr_err("failed to register the dai\n"); + return ret; + } + + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + pr_err("failed to register the DMA: %d\n", ret); + goto err; + } + + return 0; +err: + snd_soc_unregister_dai(&pdev->dev); + return ret; } static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev) { + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); return 0; } diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 0aae3a3883dc..0022d51fd160 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -467,11 +467,29 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = { static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai); + int ret = 0; + + ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + if (ret) { + pr_err("failed to register the dai\n"); + return ret; + } + + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + pr_err("failed to register the dma: %d\n", ret); + goto err; + } + + return 0; +err: + snd_soc_unregister_dai(&pdev->dev); + return ret; } static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev) { + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); return 0; } diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c index 7ace6a87f41b..befabe8979f7 100644 --- a/sound/soc/samsung/s3c24xx_simtec_hermes.c +++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c @@ -82,7 +82,7 @@ static struct snd_soc_dai_link simtec_dai_aic33 = { .codec_name = "tlv320aic3x-codec.0-001a", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .init = simtec_hermes_init, }; diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c index c42d5f00b0e1..5552f82c92a7 100644 --- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c +++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c @@ -71,7 +71,7 @@ static struct snd_soc_dai_link simtec_dai_aic23 = { .codec_name = "tlv320aic3x-codec.0-001a", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .init = simtec_tlv320aic23_init, }; diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index d731042e51b0..333e1b7f06c7 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -224,7 +224,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { .codec_dai_name = "uda134x-hifi", .cpu_dai_name = "s3c24xx-iis", .ops = &s3c24xx_uda134x_ops, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", }; static struct snd_soc_card snd_soc_s3c24xx_uda134x = { diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index f2dcb424ea25..58ae3237ef69 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c @@ -189,7 +189,7 @@ static struct snd_soc_dai_link smartq_dai[] = { .stream_name = "SmartQ Hi-Fi", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8750-hifi", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8750.0-0x1a", .init = smartq_wm8987_init, .ops = &smartq_hifi_ops, diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c index 720ba29bb7e4..c390aad68cfb 100644 --- a/sound/soc/samsung/smdk2443_wm9710.c +++ b/sound/soc/samsung/smdk2443_wm9710.c @@ -24,7 +24,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = { .cpu_dai_name = "samsung-ac97", .codec_dai_name = "ac97-hifi", .codec_name = "ac97-codec", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", }, }; diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c index beaa9c15d697..a2f2363fe1c2 100644 --- a/sound/soc/samsung/smdk_spdif.c +++ b/sound/soc/samsung/smdk_spdif.c @@ -151,7 +151,7 @@ static struct snd_soc_ops smdk_spdif_ops = { static struct snd_soc_dai_link smdk_dai = { .name = "S/PDIF", .stream_name = "S/PDIF PCM Playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-spdif", .cpu_dai_name = "samsung-spdif", .codec_dai_name = "dit-hifi", .codec_name = "spdif-dit", diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index ade2809cf393..7e2b710763be 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -176,7 +176,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Playback", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", .ops = &smdk_ops, }, @@ -185,7 +185,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Capture", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", .init = smdk_wm8580_init_paiftx, .ops = &smdk_ops, @@ -195,7 +195,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Playback", .cpu_dai_name = "samsung-i2s.x", .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.x", .codec_name = "wm8580.0-001b", .ops = &smdk_ops, }, diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c index fab5322e9f05..34239fe9afde 100644 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -135,7 +135,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Capture", .cpu_dai_name = "samsung-pcm.0", .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-audio", + .platform_name = "samsung-pcm.0", .codec_name = "wm8580.0-001b", .ops = &smdk_wm8580_pcm_ops, }, diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 48dd4dd9ee08..dd0aa8cb1a9e 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -127,7 +127,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Pri_Dai", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec", .init = smdk_wm8994_init_paiftx, .ops = &smdk_ops, @@ -136,7 +136,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Sec_Dai", .cpu_dai_name = "samsung-i2s.4", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.4", .codec_name = "wm8994-codec", .ops = &smdk_ops, }, diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index 77ecba935119..15f6b44e9de3 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -116,7 +116,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Primary PCM", .cpu_dai_name = "samsung-pcm.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-pcm.0", .codec_name = "wm8994-codec", .ops = &smdk_wm8994_pcm_ops, }, diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c index 55b2ca7f3290..0d20e4ed27aa 100644 --- a/sound/soc/samsung/smdk_wm9713.c +++ b/sound/soc/samsung/smdk_wm9713.c @@ -42,7 +42,7 @@ static struct snd_soc_card smdk; static struct snd_soc_dai_link smdk_dai = { .name = "AC97", .stream_name = "AC97 PCM", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", .cpu_dai_name = "samsung-ac97", .codec_dai_name = "wm9713-hifi", .codec_name = "wm9713-codec", diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index bc24c7af02b2..8606fc6cb37d 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -397,7 +397,7 @@ static __devinit int spdif_probe(struct platform_device *pdev) ret = -ENOENT; goto err0; } - clk_enable(spdif->pclk); + clk_prepare_enable(spdif->pclk); spdif->sclk = clk_get(&pdev->dev, "sclk_spdif"); if (IS_ERR(spdif->sclk)) { @@ -405,7 +405,7 @@ static __devinit int spdif_probe(struct platform_device *pdev) ret = -ENOENT; goto err1; } - clk_enable(spdif->sclk); + clk_prepare_enable(spdif->sclk); /* Request S/PDIF Register's memory region */ if (!request_mem_region(mem_res->start, @@ -437,17 +437,24 @@ static __devinit int spdif_probe(struct platform_device *pdev) spdif->dma_playback = &spdif_stereo_out; - return 0; + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); + goto err5; + } + return 0; +err5: + snd_soc_unregister_dai(&pdev->dev); err4: iounmap(spdif->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: - clk_disable(spdif->sclk); + clk_disable_unprepare(spdif->sclk); clk_put(spdif->sclk); err1: - clk_disable(spdif->pclk); + clk_disable_unprepare(spdif->pclk); clk_put(spdif->pclk); err0: return ret; @@ -458,6 +465,7 @@ static __devexit int spdif_remove(struct platform_device *pdev) struct samsung_spdif_info *spdif = &spdif_info; struct resource *mem_res; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); iounmap(spdif->regs); @@ -466,9 +474,9 @@ static __devexit int spdif_remove(struct platform_device *pdev) if (mem_res) release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable(spdif->sclk); + clk_disable_unprepare(spdif->sclk); clk_put(spdif->sclk); - clk_disable(spdif->pclk); + clk_disable_unprepare(spdif->pclk); clk_put(spdif->pclk); return 0; diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index c7e1c28528a4..d7906a144195 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -198,7 +198,7 @@ static struct snd_soc_dai_link speyside_dai[] = { .stream_name = "CPU-DSP", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm0010-sdi1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "spi0.0", .init = speyside_wm0010_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 9199649bf786..42e4c8e6b03e 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -110,7 +110,7 @@ static struct snd_soc_dai_link tobermory_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8962", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8962.1-001a", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 9d7f30774a44..a606d0f93d1c 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/workqueue.h> #include <sound/soc.h> +#include <sound/pcm_params.h> #include <sound/sh_fsi.h> /* PortA/PortB register */ @@ -189,6 +190,14 @@ typedef int (*set_rate_func)(struct device *dev, int rate, int enable); */ /* + * FSI clock + * + * FSIxCLK [CPG] (ick) -------> | + * |-> FSI_DIV (div)-> FSI2 + * FSIxCK [external] (xck) ---> | + */ + +/* * struct */ @@ -228,6 +237,20 @@ struct fsi_stream { dma_addr_t dma; }; +struct fsi_clk { + /* see [FSI clock] */ + struct clk *own; + struct clk *xck; + struct clk *ick; + struct clk *div; + int (*set_rate)(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate); + + unsigned long rate; + unsigned int count; +}; + struct fsi_priv { void __iomem *base; struct fsi_master *master; @@ -236,11 +259,17 @@ struct fsi_priv { struct fsi_stream playback; struct fsi_stream capture; + struct fsi_clk clock; + u32 fmt; int chan_num:16; int clk_master:1; + int clk_cpg:1; int spdif:1; + int enable_stream:1; + int bit_clk_inv:1; + int lr_clk_inv:1; long rate; }; @@ -370,6 +399,11 @@ static int fsi_is_spdif(struct fsi_priv *fsi) return fsi->spdif; } +static int fsi_is_enable_stream(struct fsi_priv *fsi) +{ + return fsi->enable_stream; +} + static int fsi_is_play(struct snd_pcm_substream *substream) { return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; @@ -717,14 +751,335 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) /* * clock function */ +static int fsi_clk_init(struct device *dev, + struct fsi_priv *fsi, + int xck, + int ick, + int div, + int (*set_rate)(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate)) +{ + struct fsi_clk *clock = &fsi->clock; + int is_porta = fsi_is_port_a(fsi); + + clock->xck = NULL; + clock->ick = NULL; + clock->div = NULL; + clock->rate = 0; + clock->count = 0; + clock->set_rate = set_rate; + + clock->own = devm_clk_get(dev, NULL); + if (IS_ERR(clock->own)) + return -EINVAL; + + /* external clock */ + if (xck) { + clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb"); + if (IS_ERR(clock->xck)) { + dev_err(dev, "can't get xck clock\n"); + return -EINVAL; + } + if (clock->xck == clock->own) { + dev_err(dev, "cpu doesn't support xck clock\n"); + return -EINVAL; + } + } + + /* FSIACLK/FSIBCLK */ + if (ick) { + clock->ick = devm_clk_get(dev, is_porta ? "icka" : "ickb"); + if (IS_ERR(clock->ick)) { + dev_err(dev, "can't get ick clock\n"); + return -EINVAL; + } + if (clock->ick == clock->own) { + dev_err(dev, "cpu doesn't support ick clock\n"); + return -EINVAL; + } + } + + /* FSI-DIV */ + if (div) { + clock->div = devm_clk_get(dev, is_porta ? "diva" : "divb"); + if (IS_ERR(clock->div)) { + dev_err(dev, "can't get div clock\n"); + return -EINVAL; + } + if (clock->div == clock->own) { + dev_err(dev, "cpu doens't support div clock\n"); + return -EINVAL; + } + } + + return 0; +} + +#define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0) +static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate) +{ + fsi->clock.rate = rate; +} + +static int fsi_clk_is_valid(struct fsi_priv *fsi) +{ + return fsi->clock.set_rate && + fsi->clock.rate; +} + +static int fsi_clk_enable(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate) +{ + struct fsi_clk *clock = &fsi->clock; + int ret = -EINVAL; + + if (!fsi_clk_is_valid(fsi)) + return ret; + + if (0 == clock->count) { + ret = clock->set_rate(dev, fsi, rate); + if (ret < 0) { + fsi_clk_invalid(fsi); + return ret; + } + + if (clock->xck) + clk_enable(clock->xck); + if (clock->ick) + clk_enable(clock->ick); + if (clock->div) + clk_enable(clock->div); + + clock->count++; + } + + return ret; +} + +static int fsi_clk_disable(struct device *dev, + struct fsi_priv *fsi) +{ + struct fsi_clk *clock = &fsi->clock; + + if (!fsi_clk_is_valid(fsi)) + return -EINVAL; + + if (1 == clock->count--) { + if (clock->xck) + clk_disable(clock->xck); + if (clock->ick) + clk_disable(clock->ick); + if (clock->div) + clk_disable(clock->div); + } + + return 0; +} + +static int fsi_clk_set_ackbpf(struct device *dev, + struct fsi_priv *fsi, + int ackmd, int bpfmd) +{ + u32 data = 0; + + /* check ackmd/bpfmd relationship */ + if (bpfmd > ackmd) { + dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd); + return -EINVAL; + } + + /* ACKMD */ + switch (ackmd) { + case 512: + data |= (0x0 << 12); + break; + case 256: + data |= (0x1 << 12); + break; + case 128: + data |= (0x2 << 12); + break; + case 64: + data |= (0x3 << 12); + break; + case 32: + data |= (0x4 << 12); + break; + default: + dev_err(dev, "unsupported ackmd (%d)\n", ackmd); + return -EINVAL; + } + + /* BPFMD */ + switch (bpfmd) { + case 32: + data |= (0x0 << 8); + break; + case 64: + data |= (0x1 << 8); + break; + case 128: + data |= (0x2 << 8); + break; + case 256: + data |= (0x3 << 8); + break; + case 512: + data |= (0x4 << 8); + break; + case 16: + data |= (0x7 << 8); + break; + default: + dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd); + return -EINVAL; + } + + dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd); + + fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); + udelay(10); + + return 0; +} + +static int fsi_clk_set_rate_external(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate) +{ + struct clk *xck = fsi->clock.xck; + struct clk *ick = fsi->clock.ick; + unsigned long xrate; + int ackmd, bpfmd; + int ret = 0; + + /* check clock rate */ + xrate = clk_get_rate(xck); + if (xrate % rate) { + dev_err(dev, "unsupported clock rate\n"); + return -EINVAL; + } + + clk_set_parent(ick, xck); + clk_set_rate(ick, xrate); + + bpfmd = fsi->chan_num * 32; + ackmd = xrate / rate; + + dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate); + + ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); + if (ret < 0) + dev_err(dev, "%s failed", __func__); + + return ret; +} + +static int fsi_clk_set_rate_cpg(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate) +{ + struct clk *ick = fsi->clock.ick; + struct clk *div = fsi->clock.div; + unsigned long target = 0; /* 12288000 or 11289600 */ + unsigned long actual, cout; + unsigned long diff, min; + unsigned long best_cout, best_act; + int adj; + int ackmd, bpfmd; + int ret = -EINVAL; + + if (!(12288000 % rate)) + target = 12288000; + if (!(11289600 % rate)) + target = 11289600; + if (!target) { + dev_err(dev, "unsupported rate\n"); + return ret; + } + + bpfmd = fsi->chan_num * 32; + ackmd = target / rate; + ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); + if (ret < 0) { + dev_err(dev, "%s failed", __func__); + return ret; + } + + /* + * The clock flow is + * + * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec] + * + * But, it needs to find best match of CPG and FSI_DIV + * combination, since it is difficult to generate correct + * frequency of audio clock from ick clock only. + * Because ick is created from its parent clock. + * + * target = rate x [512/256/128/64]fs + * cout = round(target x adjustment) + * actual = cout / adjustment (by FSI-DIV) ~= target + * audio = actual + */ + min = ~0; + best_cout = 0; + best_act = 0; + for (adj = 1; adj < 0xffff; adj++) { + + cout = target * adj; + if (cout > 100000000) /* max clock = 100MHz */ + break; + + /* cout/actual audio clock */ + cout = clk_round_rate(ick, cout); + actual = cout / adj; + + /* find best frequency */ + diff = abs(actual - target); + if (diff < min) { + min = diff; + best_cout = cout; + best_act = actual; + } + } + + ret = clk_set_rate(ick, best_cout); + if (ret < 0) { + dev_err(dev, "ick clock failed\n"); + return -EIO; + } + + ret = clk_set_rate(div, clk_round_rate(div, best_act)); + if (ret < 0) { + dev_err(dev, "div clock failed\n"); + return -EIO; + } + + dev_dbg(dev, "ick/div = %ld/%ld\n", + clk_get_rate(ick), clk_get_rate(div)); + + 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; - if (!set_rate) - return 0; + /* + * 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 */ @@ -792,10 +1147,9 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, */ static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) { - u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; int i; - if (enable_stream) { + if (fsi_is_enable_stream(fsi)) { /* * stream mode * see @@ -953,8 +1307,6 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) { - u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; - /* * we can use 16bit stream mode * when "playback" and "16bit data" @@ -962,7 +1314,7 @@ static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) * see * fsi_pio_push16() */ - if (enable_stream) + if (fsi_is_enable_stream(fsi)) io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); else @@ -1296,6 +1648,16 @@ static int fsi_hw_startup(struct fsi_priv *fsi, /* clock inversion (CKG2) */ data = 0; + if (fsi->bit_clk_inv) + data |= (1 << 0); + if (fsi->lr_clk_inv) + 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) @@ -1334,14 +1696,21 @@ static int fsi_hw_startup(struct fsi_priv *fsi, /* fifo init */ fsi_fifo_init(fsi, io, dev); + /* start master clock */ + if (fsi_is_clk_master(fsi)) + return fsi_set_master_clk(dev, fsi, fsi->rate, 1); + return 0; } -static void fsi_hw_shutdown(struct fsi_priv *fsi, +static int fsi_hw_shutdown(struct fsi_priv *fsi, struct device *dev) { + /* stop master clock */ if (fsi_is_clk_master(fsi)) - fsi_set_master_clk(dev, fsi, fsi->rate, 0); + return fsi_set_master_clk(dev, fsi, fsi->rate, 0); + + return 0; } static int fsi_dai_startup(struct snd_pcm_substream *substream, @@ -1349,6 +1718,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; @@ -1359,6 +1729,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; } @@ -1372,13 +1743,16 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: fsi_stream_init(fsi, io, substream); - fsi_hw_startup(fsi, io, dai->dev); - ret = fsi_stream_transfer(io); - if (0 == ret) + if (!ret) + ret = fsi_hw_startup(fsi, io, dai->dev); + if (!ret) + ret = fsi_stream_transfer(io); + if (!ret) fsi_stream_start(fsi, io); break; case SNDRV_PCM_TRIGGER_STOP: - fsi_hw_shutdown(fsi, dai->dev); + if (!ret) + ret = fsi_hw_shutdown(fsi, dai->dev); fsi_stream_stop(fsi, io); fsi_stream_quit(fsi, io); break; @@ -1414,7 +1788,6 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM; fsi->chan_num = 2; - fsi->spdif = 1; return 0; } @@ -1423,7 +1796,6 @@ 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); - u32 flags = fsi_get_info_flags(fsi); int ret; /* set master/slave audio interface */ @@ -1437,23 +1809,50 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - if (fsi_is_clk_master(fsi) && !set_rate) { - dev_err(dai->dev, "platform doesn't have set_rate\n"); - return -EINVAL; - } - - /* set format */ - switch (flags & SH_FSI_FMT_MASK) { - case SH_FSI_FMT_DAI: - ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); + /* set clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + fsi->bit_clk_inv = 0; + fsi->lr_clk_inv = 1; break; - case SH_FSI_FMT_SPDIF: - ret = fsi_set_fmt_spdif(fsi); + case SND_SOC_DAIFMT_IB_NF: + fsi->bit_clk_inv = 1; + fsi->lr_clk_inv = 0; break; + case SND_SOC_DAIFMT_IB_IF: + fsi->bit_clk_inv = 1; + fsi->lr_clk_inv = 1; + break; + case SND_SOC_DAIFMT_NB_NF: default: - ret = -EINVAL; + fsi->bit_clk_inv = 0; + fsi->lr_clk_inv = 0; + break; + } + + 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); + else + fsi_clk_init(dai->dev, fsi, 1, 1, 0, + fsi_clk_set_rate_external); } + /* set format */ + if (fsi_is_spdif(fsi)) + ret = fsi_set_fmt_spdif(fsi); + else + ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return ret; } @@ -1462,19 +1861,13 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); - long rate = params_rate(params); - int ret; - if (!fsi_is_clk_master(fsi)) - return 0; - - ret = fsi_set_master_clk(dai->dev, fsi, rate, 1); - if (ret < 0) - return ret; - - fsi->rate = rate; + if (fsi_is_clk_master(fsi)) { + fsi->rate = params_rate(params); + fsi_clk_valid(fsi, fsi->rate); + } - return ret; + return 0; } static const struct snd_soc_dai_ops fsi_dai_ops = { @@ -1498,7 +1891,7 @@ static struct snd_pcm_hardware fsi_pcm_hardware = { .rates = FSI_RATES, .rate_min = 8000, .rate_max = 192000, - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 64 * 1024, .period_bytes_min = 32, @@ -1586,14 +1979,14 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .playback = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .capture = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .ops = &fsi_dai_ops, }, @@ -1602,14 +1995,14 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .playback = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .capture = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .ops = &fsi_dai_ops, }, @@ -1624,15 +2017,29 @@ static struct snd_soc_platform_driver fsi_soc_platform = { /* * platform function */ -static void fsi_handler_init(struct fsi_priv *fsi) +static void fsi_port_info_init(struct fsi_priv *fsi, + struct sh_fsi_port_info *info) +{ + if (info->flags & SH_FSI_FMT_SPDIF) + fsi->spdif = 1; + + if (info->flags & SH_FSI_CLK_CPG) + fsi->clk_cpg = 1; + + if (info->flags & SH_FSI_ENABLE_STREAM_MODE) + fsi->enable_stream = 1; +} + +static void fsi_handler_init(struct fsi_priv *fsi, + struct sh_fsi_port_info *info) { fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ fsi->playback.priv = fsi; fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ fsi->capture.priv = fsi; - if (fsi->info->tx_id) { - fsi->playback.slave.shdma_slave.slave_id = fsi->info->tx_id; + if (info->tx_id) { + fsi->playback.slave.shdma_slave.slave_id = info->tx_id; fsi->playback.handler = &fsi_dma_push_handler; } } @@ -1642,10 +2049,16 @@ static int fsi_probe(struct platform_device *pdev) struct fsi_master *master; 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; + nul_info.flags = 0; + nul_info.tx_id = 0; + nul_info.rx_id = 0; + id_entry = pdev->id_entry; if (!id_entry) { dev_err(&pdev->dev, "unknown fsi device\n"); @@ -1678,22 +2091,28 @@ static int fsi_probe(struct platform_device *pdev) spin_lock_init(&master->lock); /* FSI A setting */ - master->fsia.base = master->base; - master->fsia.master = master; - master->fsia.info = &info->port_a; - fsi_handler_init(&master->fsia); - ret = fsi_stream_probe(&master->fsia, &pdev->dev); + pinfo = (info) ? &info->port_a : &nul_info; + fsi = &master->fsia; + fsi->base = master->base; + fsi->master = master; + 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"); return ret; } /* FSI B setting */ - master->fsib.base = master->base + 0x40; - master->fsib.master = master; - master->fsib.info = &info->port_b; - fsi_handler_init(&master->fsib); - ret = fsi_stream_probe(&master->fsib, &pdev->dev); + pinfo = (info) ? &info->port_b : &nul_info; + fsi = &master->fsib; + fsi->base = master->base + 0x40; + fsi->master = master; + 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"); goto exit_fsia; @@ -1702,7 +2121,7 @@ static int fsi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); dev_set_drvdata(&pdev->dev, master); - ret = request_irq(irq, &fsi_interrupt, 0, + ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0, id_entry->name, master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); @@ -1712,7 +2131,7 @@ static int fsi_probe(struct platform_device *pdev) ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); if (ret < 0) { dev_err(&pdev->dev, "cannot snd soc register\n"); - goto exit_free_irq; + goto exit_fsib; } ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai, @@ -1726,8 +2145,6 @@ static int fsi_probe(struct platform_device *pdev) exit_snd_soc: snd_soc_unregister_platform(&pdev->dev); -exit_free_irq: - free_irq(irq, master); exit_fsib: pm_runtime_disable(&pdev->dev); fsi_stream_remove(&master->fsib); @@ -1743,7 +2160,6 @@ static int fsi_remove(struct platform_device *pdev) master = dev_get_drvdata(&pdev->dev); - free_irq(master->irq, master); pm_runtime_disable(&pdev->dev); snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); @@ -1774,10 +2190,6 @@ static void __fsi_resume(struct fsi_priv *fsi, return; fsi_hw_startup(fsi, io, dev); - - if (fsi_is_clk_master(fsi) && fsi->rate) - fsi_set_master_clk(dev, fsi, fsi->rate, 1); - fsi_stream_start(fsi, io); } diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 9d56f0218f41..e72f55428f0b 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -88,7 +88,7 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) ret = snd_soc_write(codec, i, val); if (ret) return ret; - dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", + dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", i, val); } return 0; @@ -156,7 +156,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) /* Fall back to flat compression */ if (i == ARRAY_SIZE(cache_types)) { - dev_warn(codec->dev, "Could not match compress type: %d\n", + dev_warn(codec->dev, "ASoC: Could not match compress type: %d\n", codec->compress_type); i = 0; } @@ -166,7 +166,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) if (codec->cache_ops->init) { if (codec->cache_ops->name) - dev_dbg(codec->dev, "Initializing %s cache for %s codec\n", + dev_dbg(codec->dev, "ASoC: Initializing %s cache for %s codec\n", codec->cache_ops->name, codec->name); return codec->cache_ops->init(codec); } @@ -181,7 +181,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) { if (codec->cache_ops && codec->cache_ops->exit) { if (codec->cache_ops->name) - dev_dbg(codec->dev, "Destroying %s cache for %s codec\n", + dev_dbg(codec->dev, "ASoC: Destroying %s cache for %s codec\n", codec->cache_ops->name, codec->name); return codec->cache_ops->exit(codec); } @@ -265,7 +265,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec) name = "unknown"; if (codec->cache_ops->name) - dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", + dev_dbg(codec->dev, "ASoC: Syncing %s cache for %s codec\n", codec->cache_ops->name, codec->name); trace_snd_soc_cache_sync(codec, name, "start"); ret = codec->cache_ops->sync(codec); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 10d21be383f6..9c768bcb98a6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -271,7 +271,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) codec->debugfs_codec_root = debugfs_create_dir(codec->name, debugfs_card_root); if (!codec->debugfs_codec_root) { - dev_warn(codec->dev, "Failed to create codec debugfs directory\n"); + dev_warn(codec->dev, "ASoC: Failed to create codec debugfs" + " directory\n"); return; } @@ -284,7 +285,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) codec->debugfs_codec_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) - dev_warn(codec->dev, "Failed to create codec register debugfs file\n"); + dev_warn(codec->dev, "ASoC: Failed to create codec register" + " debugfs file\n"); snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); } @@ -302,7 +304,7 @@ static void soc_init_platform_debugfs(struct snd_soc_platform *platform) debugfs_card_root); if (!platform->debugfs_platform_root) { dev_warn(platform->dev, - "Failed to create platform debugfs directory\n"); + "ASoC: Failed to create platform debugfs directory\n"); return; } @@ -430,7 +432,7 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) &card->pop_time); if (!card->debugfs_pop_time) dev_warn(card->dev, - "Failed to create pop time debugfs file\n"); + "ASoC: Failed to create pop time debugfs file\n"); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) @@ -475,7 +477,7 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, !strcmp(card->rtd[i].dai_link->name, dai_link)) return card->rtd[i].pcm->streams[stream].substream; } - dev_dbg(card->dev, "failed to find dai link %s\n", dai_link); + dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link); return NULL; } EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); @@ -489,7 +491,7 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, if (!strcmp(card->rtd[i].dai_link->name, dai_link)) return &card->rtd[i]; } - dev_dbg(card->dev, "failed to find rtd %s\n", dai_link); + dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link); return NULL; } EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); @@ -519,7 +521,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) codec->card->snd_card->number, 0, codec->name); err = device_register(&codec->ac97->dev); if (err < 0) { - snd_printk(KERN_ERR "Can't register ac97 bus\n"); + dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); codec->ac97->dev.bus = NULL; return err; } @@ -628,7 +630,8 @@ int snd_soc_suspend(struct device *dev) */ if (codec->dapm.idle_bias_off) { dev_dbg(codec->dev, - "idle_bias_off CODEC on over suspend\n"); + "ASoC: idle_bias_off CODEC on" + " over suspend\n"); break; } case SND_SOC_BIAS_OFF: @@ -639,7 +642,8 @@ int snd_soc_suspend(struct device *dev) regcache_mark_dirty(codec->control_data); break; default: - dev_dbg(codec->dev, "CODEC is on over suspend\n"); + dev_dbg(codec->dev, "ASoC: CODEC is on" + " over suspend\n"); break; } } @@ -676,7 +680,7 @@ static void soc_resume_deferred(struct work_struct *work) * so userspace apps are blocked from touching us */ - dev_dbg(card->dev, "starting resume work\n"); + dev_dbg(card->dev, "ASoC: starting resume work\n"); /* Bring us up into D2 so that DAPM starts enabling things */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); @@ -708,7 +712,8 @@ static void soc_resume_deferred(struct work_struct *work) codec->suspended = 0; break; default: - dev_dbg(codec->dev, "CODEC was on over suspend\n"); + dev_dbg(codec->dev, "ASoC: CODEC was on over" + " suspend\n"); break; } } @@ -758,7 +763,7 @@ static void soc_resume_deferred(struct work_struct *work) if (card->resume_post) card->resume_post(card); - dev_dbg(card->dev, "resume work completed\n"); + dev_dbg(card->dev, "ASoC: resume work completed\n"); /* userspace can access us now we are back as we were before */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); @@ -790,12 +795,12 @@ int snd_soc_resume(struct device *dev) ac97_control |= cpu_dai->driver->ac97_control; } if (ac97_control) { - dev_dbg(dev, "Resuming AC97 immediately\n"); + dev_dbg(dev, "ASoC: Resuming AC97 immediately\n"); soc_resume_deferred(&card->deferred_resume_work); } else { - dev_dbg(dev, "Scheduling resume work\n"); + dev_dbg(dev, "ASoC: Scheduling resume work\n"); if (!schedule_work(&card->deferred_resume_work)) - dev_err(dev, "resume work item may be lost\n"); + dev_err(dev, "ASoC: resume work item may be lost\n"); } return 0; @@ -818,7 +823,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) struct snd_soc_dai *codec_dai, *cpu_dai; const char *platform_name; - dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num); + dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); /* Find CPU DAI from registered DAIs*/ list_for_each_entry(cpu_dai, &dai_list, list) { @@ -836,7 +841,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) } if (!rtd->cpu_dai) { - dev_err(card->dev, "CPU DAI %s not registered\n", + dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); return -EPROBE_DEFER; } @@ -867,14 +872,14 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) } if (!rtd->codec_dai) { - dev_err(card->dev, "CODEC DAI %s not registered\n", + dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", dai_link->codec_dai_name); return -EPROBE_DEFER; } } if (!rtd->codec) { - dev_err(card->dev, "CODEC %s not registered\n", + dev_err(card->dev, "ASoC: CODEC %s not registered\n", dai_link->codec_name); return -EPROBE_DEFER; } @@ -898,7 +903,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) rtd->platform = platform; } if (!rtd->platform) { - dev_err(card->dev, "platform %s not registered\n", + dev_err(card->dev, "ASoC: platform %s not registered\n", dai_link->platform_name); return -EPROBE_DEFER; } @@ -915,8 +920,8 @@ static int soc_remove_platform(struct snd_soc_platform *platform) if (platform->driver->remove) { ret = platform->driver->remove(platform); if (ret < 0) - pr_err("asoc: failed to remove %s: %d\n", - platform->name, ret); + dev_err(platform->dev, "ASoC: failed to remove %d\n", + ret); } /* Make sure all DAPM widgets are freed */ @@ -937,9 +942,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec) if (codec->driver->remove) { err = codec->driver->remove(codec); if (err < 0) - dev_err(codec->dev, - "asoc: failed to remove %s: %d\n", - codec->name, err); + dev_err(codec->dev, "ASoC: failed to remove %d\n", err); } /* Make sure all DAPM widgets are freed */ @@ -971,8 +974,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) if (codec_dai->driver->remove) { err = codec_dai->driver->remove(codec_dai); if (err < 0) - pr_err("asoc: failed to remove %s: %d\n", - codec_dai->name, err); + dev_err(codec_dai->dev, + "ASoC: failed to remove %s: %d\n", + codec_dai->name, err); } codec_dai->probed = 0; list_del(&codec_dai->card_list); @@ -984,8 +988,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->remove) { err = cpu_dai->driver->remove(cpu_dai); if (err < 0) - pr_err("asoc: failed to remove %s: %d\n", - cpu_dai->name, err); + dev_err(cpu_dai->dev, + "ASoC: failed to remove %s: %d\n", + cpu_dai->name, err); } cpu_dai->probed = 0; list_del(&cpu_dai->card_list); @@ -1099,8 +1104,7 @@ static int soc_probe_codec(struct snd_soc_card *card, ret = driver->probe(codec); if (ret < 0) { dev_err(codec->dev, - "asoc: failed to probe CODEC %s: %d\n", - codec->name, ret); + "ASoC: failed to probe CODEC %d\n", ret); goto err_probe; } } @@ -1163,8 +1167,7 @@ static int soc_probe_platform(struct snd_soc_card *card, ret = driver->probe(platform); if (ret < 0) { dev_err(platform->dev, - "asoc: failed to probe platform %s: %d\n", - platform->name, ret); + "ASoC: failed to probe platform %d\n", ret); goto err_probe; } } @@ -1229,7 +1232,7 @@ static int soc_post_component_init(struct snd_soc_card *card, else if (dailess && aux_dev->init) ret = aux_dev->init(&codec->dapm); if (ret < 0) { - dev_err(card->dev, "asoc: failed to init %s: %d\n", name, ret); + dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret); return ret; } codec->name_prefix = temp; @@ -1253,7 +1256,7 @@ static int soc_post_component_init(struct snd_soc_card *card, ret = device_add(rtd->dev); if (ret < 0) { dev_err(card->dev, - "asoc: failed to register runtime device: %d\n", ret); + "ASoC: failed to register runtime device: %d\n", ret); return ret; } rtd->dev_registered = 1; @@ -1262,14 +1265,13 @@ static int soc_post_component_init(struct snd_soc_card *card, ret = snd_soc_dapm_sys_add(rtd->dev); if (ret < 0) dev_err(codec->dev, - "asoc: failed to add codec dapm sysfs entries: %d\n", - ret); + "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); /* add codec sysfs entries */ ret = device_create_file(rtd->dev, &dev_attr_codec_reg); if (ret < 0) dev_err(codec->dev, - "asoc: failed to add codec sysfs files: %d\n", ret); + "ASoC: failed to add codec sysfs files: %d\n", ret); #ifdef CONFIG_DEBUG_FS /* add DPCM sysfs entries */ @@ -1278,7 +1280,7 @@ static int soc_post_component_init(struct snd_soc_card *card, ret = soc_dpcm_debugfs_add(rtd); if (ret < 0) - dev_err(rtd->dev, "asoc: failed to add dpcm sysfs entries: %d\n", ret); + dev_err(rtd->dev, "ASoC: failed to add dpcm sysfs entries: %d\n", ret); out: #endif @@ -1333,7 +1335,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) struct snd_soc_dapm_widget *play_w, *capture_w; int ret; - dev_dbg(card->dev, "probe %s dai link %d late %d\n", + dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", card->name, num, order); /* config components */ @@ -1359,8 +1361,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { - pr_err("asoc: failed to probe CPU DAI %s: %d\n", - cpu_dai->name, ret); + dev_err(cpu_dai->dev, + "ASoC: failed to probe CPU DAI %s: %d\n", + cpu_dai->name, ret); module_put(cpu_dai->dev->driver->owner); return ret; } @@ -1375,8 +1378,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (codec_dai->driver->probe) { ret = codec_dai->driver->probe(codec_dai); if (ret < 0) { - pr_err("asoc: failed to probe CODEC DAI %s: %d\n", - codec_dai->name, ret); + dev_err(codec_dai->dev, + "ASoC: failed to probe CODEC DAI %s: %d\n", + codec_dai->name, ret); return ret; } } @@ -1396,13 +1400,14 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) ret = device_create_file(rtd->dev, &dev_attr_pmdown_time); if (ret < 0) - pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret); + dev_warn(rtd->dev, "ASoC: failed to add pmdown_time sysfs: %d\n", + ret); if (cpu_dai->driver->compress_dai) { /*create compress_device"*/ ret = soc_new_compress(rtd, num); if (ret < 0) { - pr_err("asoc: can't create compress %s\n", + dev_err(card->dev, "ASoC: can't create compress %s\n", dai_link->stream_name); return ret; } @@ -1412,7 +1417,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) /* create the pcm */ ret = soc_new_pcm(rtd, num); if (ret < 0) { - pr_err("asoc: can't create pcm %s :%d\n", + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", dai_link->stream_name, ret); return ret; } @@ -1424,7 +1429,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) ret = snd_soc_dapm_new_pcm(card, dai_link->params, capture_w, play_w); if (ret != 0) { - dev_err(card->dev, "Can't link %s to %s: %d\n", + dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", play_w->name, capture_w->name, ret); return ret; } @@ -1436,7 +1441,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) ret = snd_soc_dapm_new_pcm(card, dai_link->params, capture_w, play_w); if (ret != 0) { - dev_err(card->dev, "Can't link %s to %s: %d\n", + dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", play_w->name, capture_w->name, ret); return ret; } @@ -1473,7 +1478,8 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) ret = soc_ac97_dev_register(rtd->codec); if (ret < 0) { - pr_err("asoc: AC97 device register failed:%d\n", ret); + dev_err(rtd->codec->dev, + "ASoC: AC97 device register failed: %d\n", ret); return ret; } @@ -1502,7 +1508,7 @@ static int soc_check_aux_dev(struct snd_soc_card *card, int num) return 0; } - dev_err(card->dev, "%s not registered\n", aux_dev->codec_name); + dev_err(card->dev, "ASoC: %s not registered\n", aux_dev->codec_name); return -EPROBE_DEFER; } @@ -1518,7 +1524,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) if (!strcmp(codec->name, aux_dev->codec_name)) { if (codec->probed) { dev_err(codec->dev, - "asoc: codec already probed"); + "ASoC: codec already probed"); ret = -EBUSY; goto out; } @@ -1526,7 +1532,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) } } /* codec not found */ - dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name); + dev_err(card->dev, "ASoC: codec %s not found", aux_dev->codec_name); return -EPROBE_DEFER; found: @@ -1569,8 +1575,8 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, codec->compress_type = compress_type; ret = snd_soc_cache_init(codec); if (ret < 0) { - dev_err(codec->dev, "Failed to set cache compression type: %d\n", - ret); + dev_err(codec->dev, "ASoC: Failed to set cache compression" + " type: %d\n", ret); return ret; } codec->cache_init = 1; @@ -1626,8 +1632,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, card->owner, 0, &card->snd_card); if (ret < 0) { - pr_err("asoc: can't create sound card for card %s: %d\n", - card->name, ret); + dev_err(card->dev, "ASoC: can't create sound card for" + " card %s: %d\n", card->name, ret); goto base_error; } card->snd_card->dev = card->dev; @@ -1663,8 +1669,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) { ret = soc_probe_link_components(card, i, order); if (ret < 0) { - pr_err("asoc: failed to instantiate card %s: %d\n", - card->name, ret); + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", + ret); goto probe_dai_err; } } @@ -1676,8 +1683,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) { ret = soc_probe_link_dais(card, i, order); if (ret < 0) { - pr_err("asoc: failed to instantiate card %s: %d\n", - card->name, ret); + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", + ret); goto probe_dai_err; } } @@ -1686,8 +1694,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_aux_devs; i++) { ret = soc_probe_aux_dev(card, i); if (ret < 0) { - pr_err("asoc: failed to add auxiliary devices %s: %d\n", - card->name, ret); + dev_err(card->dev, + "ASoC: failed to add auxiliary devices %d\n", + ret); goto probe_aux_dev_err; } } @@ -1712,7 +1721,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dai_fmt); if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].codec_dai->dev, - "Failed to set DAI format: %d\n", + "ASoC: Failed to set DAI format: %d\n", ret); } @@ -1723,7 +1732,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dai_fmt); if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].cpu_dai->dev, - "Failed to set DAI format: %d\n", + "ASoC: Failed to set DAI format: %d\n", ret); } else if (dai_fmt) { /* Flip the polarity for the "CPU" end */ @@ -1748,7 +1757,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dai_fmt); if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].cpu_dai->dev, - "Failed to set DAI format: %d\n", + "ASoC: Failed to set DAI format: %d\n", ret); } } @@ -1775,7 +1784,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (card->late_probe) { ret = card->late_probe(card); if (ret < 0) { - dev_err(card->dev, "%s late_probe() failed: %d\n", + dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", card->name, ret); goto probe_aux_dev_err; } @@ -1789,8 +1798,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = snd_card_register(card->snd_card); if (ret < 0) { - pr_err("asoc: failed to register soundcard for %s: %d\n", - card->name, ret); + dev_err(card->dev, "ASoC: failed to register soundcard %d\n", + ret); goto probe_aux_dev_err; } @@ -1799,8 +1808,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_rtd; i++) { ret = soc_register_ac97_dai_link(&card->rtd[i]); if (ret < 0) { - pr_err("asoc: failed to register AC97 %s: %d\n", - card->name, ret); + dev_err(card->dev, "ASoC: failed to register AC97:" + " %d\n", ret); while (--i >= 0) soc_unregister_ac97_dai_link(card->rtd[i].codec); goto probe_aux_dev_err; @@ -1846,7 +1855,7 @@ static int soc_probe(struct platform_device *pdev) return -EINVAL; dev_warn(&pdev->dev, - "ASoC machine %s should use snd_soc_register_card()\n", + "ASoC: machine %s should use snd_soc_register_card()\n", card->name); /* Bodge while we unpick instantiation */ @@ -1996,7 +2005,7 @@ int snd_soc_platform_read(struct snd_soc_platform *platform, unsigned int ret; if (!platform->driver->read) { - dev_err(platform->dev, "platform has no read back\n"); + dev_err(platform->dev, "ASoC: platform has no read back\n"); return -1; } @@ -2012,7 +2021,7 @@ int snd_soc_platform_write(struct snd_soc_platform *platform, unsigned int reg, unsigned int val) { if (!platform->driver->write) { - dev_err(platform->dev, "platform has no write back\n"); + dev_err(platform->dev, "ASoC: platform has no write back\n"); return -1; } @@ -2283,7 +2292,8 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev, err = snd_ctl_add(card, snd_soc_cnew(control, data, control->name, prefix)); if (err < 0) { - dev_err(dev, "Failed to add %s: %d\n", control->name, err); + dev_err(dev, "ASoC: Failed to add %s: %d\n", + control->name, err); return err; } } @@ -3534,15 +3544,14 @@ int snd_soc_register_card(struct snd_soc_card *card) * not both or neither. */ if (!!link->codec_name == !!link->codec_of_node) { - dev_err(card->dev, - "Neither/both codec name/of_node are set for %s\n", - link->name); + dev_err(card->dev, "ASoC: Neither/both codec" + " name/of_node are set for %s\n", link->name); return -EINVAL; } /* Codec DAI name must be specified */ if (!link->codec_dai_name) { - dev_err(card->dev, "codec_dai_name not set for %s\n", - link->name); + dev_err(card->dev, "ASoC: codec_dai_name not" + " set for %s\n", link->name); return -EINVAL; } @@ -3551,8 +3560,8 @@ int snd_soc_register_card(struct snd_soc_card *card) * can be left unspecified, and a dummy platform will be used. */ if (link->platform_name && link->platform_of_node) { - dev_err(card->dev, - "Both platform name/of_node are set for %s\n", link->name); + dev_err(card->dev, "ASoC: Both platform name/of_node" + " are set for %s\n", link->name); return -EINVAL; } @@ -3562,9 +3571,8 @@ int snd_soc_register_card(struct snd_soc_card *card) * name alone.. */ if (link->cpu_name && link->cpu_of_node) { - dev_err(card->dev, - "Neither/both cpu name/of_node are set for %s\n", - link->name); + dev_err(card->dev, "ASoC: Neither/both " + "cpu name/of_node are set for %s\n",link->name); return -EINVAL; } /* @@ -3573,9 +3581,8 @@ int snd_soc_register_card(struct snd_soc_card *card) */ if (!link->cpu_dai_name && !(link->cpu_name || link->cpu_of_node)) { - dev_err(card->dev, - "Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); + dev_err(card->dev, "ASoC: Neither cpu_dai_name nor " + "cpu_name/of_node are set for %s\n", link->name); return -EINVAL; } } @@ -3622,7 +3629,7 @@ int snd_soc_unregister_card(struct snd_soc_card *card) { if (card->instantiated) soc_cleanup_card_resources(card); - dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); + dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; } @@ -3679,8 +3686,8 @@ static inline char *fmt_multiple_name(struct device *dev, struct snd_soc_dai_driver *dai_drv) { if (dai_drv->name == NULL) { - pr_err("asoc: error - multiple DAI %s registered with no name\n", - dev_name(dev)); + dev_err(dev, "ASoC: error - multiple DAI %s registered with" + " no name\n", dev_name(dev)); return NULL; } @@ -3698,7 +3705,7 @@ int snd_soc_register_dai(struct device *dev, struct snd_soc_codec *codec; struct snd_soc_dai *dai; - dev_dbg(dev, "dai register %s\n", dev_name(dev)); + dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev)); dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); if (dai == NULL) @@ -3721,7 +3728,7 @@ int snd_soc_register_dai(struct device *dev, list_for_each_entry(codec, &codec_list, list) { if (codec->dev == dev) { - dev_dbg(dev, "Mapped DAI %s to CODEC %s\n", + dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n", dai->name, codec->name); dai->codec = codec; break; @@ -3735,7 +3742,7 @@ int snd_soc_register_dai(struct device *dev, mutex_unlock(&client_mutex); - pr_debug("Registered DAI '%s'\n", dai->name); + dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); return 0; } @@ -3761,7 +3768,7 @@ found: list_del(&dai->list); mutex_unlock(&client_mutex); - pr_debug("Unregistered DAI '%s'\n", dai->name); + dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name); kfree(dai->name); kfree(dai); } @@ -3780,7 +3787,7 @@ int snd_soc_register_dais(struct device *dev, struct snd_soc_dai *dai; int i, ret = 0; - dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count); + dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); for (i = 0; i < count; i++) { @@ -3812,8 +3819,8 @@ int snd_soc_register_dais(struct device *dev, list_for_each_entry(codec, &codec_list, list) { if (codec->dev == dev) { - dev_dbg(dev, "Mapped DAI %s to CODEC %s\n", - dai->name, codec->name); + dev_dbg(dev, "ASoC: Mapped DAI %s to " + "CODEC %s\n", dai->name, codec->name); dai->codec = codec; break; } @@ -3826,7 +3833,7 @@ int snd_soc_register_dais(struct device *dev, mutex_unlock(&client_mutex); - pr_debug("Registered DAI '%s'\n", dai->name); + dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name); } return 0; @@ -3864,7 +3871,7 @@ int snd_soc_register_platform(struct device *dev, { struct snd_soc_platform *platform; - dev_dbg(dev, "platform register %s\n", dev_name(dev)); + dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev)); platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); if (platform == NULL) @@ -3888,7 +3895,7 @@ int snd_soc_register_platform(struct device *dev, list_add(&platform->list, &platform_list); mutex_unlock(&client_mutex); - pr_debug("Registered platform '%s'\n", platform->name); + dev_dbg(dev, "ASoC: Registered platform '%s'\n", platform->name); return 0; } @@ -3914,7 +3921,7 @@ found: list_del(&platform->list); mutex_unlock(&client_mutex); - pr_debug("Unregistered platform '%s'\n", platform->name); + dev_dbg(dev, "ASoC: Unregistered platform '%s'\n", platform->name); kfree(platform->name); kfree(platform); } @@ -4007,7 +4014,7 @@ int snd_soc_register_codec(struct device *dev, codec->reg_size = reg_size; /* it is necessary to make a copy of the default register cache * because in the case of using a compression type that requires - * the default register cache to be marked as __devinitconst the + * the default register cache to be marked as the * kernel might have freed the array by the time we initialize * the cache. */ @@ -4043,11 +4050,11 @@ int snd_soc_register_codec(struct device *dev, if (num_dai) { ret = snd_soc_register_dais(dev, dai_drv, num_dai); if (ret < 0) - dev_err(codec->dev, "Failed to regster DAIs: %d\n", - ret); + dev_err(codec->dev, "ASoC: Failed to regster" + " DAIs: %d\n", ret); } - pr_debug("Registered codec '%s'\n", codec->name); + dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name); return 0; fail: @@ -4082,7 +4089,7 @@ found: list_del(&codec->list); mutex_unlock(&client_mutex); - pr_debug("Unregistered codec '%s'\n", codec->name); + dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name); snd_soc_cache_exit(codec); kfree(codec->reg_def_copy); @@ -4106,7 +4113,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, */ if (ret < 0 && ret != -EINVAL) { dev_err(card->dev, - "Property '%s' could not be read: %d\n", + "ASoC: Property '%s' could not be read: %d\n", propname, ret); return ret; } @@ -4125,15 +4132,13 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, num_routes = of_property_count_strings(np, propname); if (num_routes < 0 || num_routes & 1) { - dev_err(card->dev, - "Property '%s' does not exist or its length is not even\n", - propname); + dev_err(card->dev, "ASoC: Property '%s' does not exist or its" + " length is not even\n", propname); return -EINVAL; } num_routes /= 2; if (!num_routes) { - dev_err(card->dev, - "Property '%s's length is zero\n", + dev_err(card->dev, "ASoC: Property '%s's length is zero\n", propname); return -EINVAL; } @@ -4142,7 +4147,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, GFP_KERNEL); if (!routes) { dev_err(card->dev, - "Could not allocate DAPM route table\n"); + "ASoC: Could not allocate DAPM route table\n"); return -EINVAL; } @@ -4150,9 +4155,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, ret = of_property_read_string_index(np, propname, 2 * i, &routes[i].sink); if (ret) { - dev_err(card->dev, - "Property '%s' index %d could not be read: %d\n", - propname, 2 * i, ret); + dev_err(card->dev, "ASoC: Property '%s' index %d" + " could not be read: %d\n", propname, 2 * i, + ret); kfree(routes); return -EINVAL; } @@ -4160,8 +4165,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, (2 * i) + 1, &routes[i].source); if (ret) { dev_err(card->dev, - "Property '%s' index %d could not be read: %d\n", - propname, (2 * i) + 1, ret); + "ASoC: Property '%s' index %d could not be" + " read: %d\n", propname, (2 * i) + 1, ret); kfree(routes); return -EINVAL; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6e35bcae02df..1e36bc81e5af 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -220,7 +220,7 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) else if (w->platform) return snd_soc_platform_read(w->platform, reg); - dev_err(w->dapm->dev, "no valid widget read method\n"); + dev_err(w->dapm->dev, "ASoC: no valid widget read method\n"); return -1; } @@ -231,7 +231,7 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) else if (w->platform) return snd_soc_platform_write(w->platform, reg, val); - dev_err(w->dapm->dev, "no valid widget write method\n"); + dev_err(w->dapm->dev, "ASoC: no valid widget write method\n"); return -1; } @@ -546,7 +546,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) wlist = kzalloc(wlistsize, GFP_KERNEL); if (wlist == NULL) { dev_err(dapm->dev, - "asoc: can't allocate widget list for %s\n", + "ASoC: can't allocate widget list for %s\n", w->name); return -ENOMEM; } @@ -595,9 +595,9 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) prefix); ret = snd_ctl_add(card, path->kcontrol); if (ret < 0) { - dev_err(dapm->dev, - "asoc: failed to add dapm kcontrol %s: %d\n", - path->long_name, ret); + dev_err(dapm->dev, "ASoC: failed to add widget" + " %s dapm kcontrol %s: %d\n", + w->name, path->long_name, ret); kfree(wlist); kfree(path->long_name); path->long_name = NULL; @@ -626,7 +626,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) if (w->num_kcontrols != 1) { dev_err(dapm->dev, - "asoc: mux %s has incorrect number of controls\n", + "ASoC: mux %s has incorrect number of controls\n", w->name); return -EINVAL; } @@ -645,7 +645,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) wlist = krealloc(wlist, wlistsize, GFP_KERNEL); if (wlist == NULL) { dev_err(dapm->dev, - "asoc: can't allocate widget list for %s\n", w->name); + "ASoC: can't allocate widget list for %s\n", w->name); return -ENOMEM; } wlist->num_widgets = wlistentries; @@ -677,7 +677,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) name + prefix_len, prefix); ret = snd_ctl_add(card, kcontrol); if (ret < 0) { - dev_err(dapm->dev, "failed to add kcontrol %s: %d\n", + dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n", w->name, ret); kfree(wlist); return ret; @@ -699,7 +699,7 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) { if (w->num_kcontrols) dev_err(w->dapm->dev, - "asoc: PGA controls not supported: '%s'\n", w->name); + "ASoC: PGA controls not supported: '%s'\n", w->name); return 0; } @@ -725,7 +725,7 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) case SNDRV_CTL_POWER_D3hot: case SNDRV_CTL_POWER_D3cold: if (widget->ignore_suspend) - dev_dbg(widget->dapm->dev, "%s ignoring suspend\n", + dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n", widget->name); return widget->ignore_suspend; default: @@ -757,14 +757,14 @@ static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, wlistentries * sizeof(struct snd_soc_dapm_widget *); *list = krealloc(wlist, wlistsize, GFP_KERNEL); if (*list == NULL) { - dev_err(w->dapm->dev, "can't allocate widget list for %s\n", + dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n", w->name); return -ENOMEM; } wlist = *list; /* insert the widget */ - dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n", + dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n", w->name, wlist->num_widgets); wlist->widgets[wlist->num_widgets] = w; @@ -844,7 +844,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, int err; err = dapm_list_add_widget(list, path->sink); if (err < 0) { - dev_err(widget->dapm->dev, "could not add widget %s\n", + dev_err(widget->dapm->dev, + "ASoC: could not add widget %s\n", widget->name); return con; } @@ -943,7 +944,8 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, int err; err = dapm_list_add_widget(list, path->source); if (err < 0) { - dev_err(widget->dapm->dev, "could not add widget %s\n", + dev_err(widget->dapm->dev, + "ASoC: could not add widget %s\n", widget->name); return con; } @@ -1024,7 +1026,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) dev_warn(w->dapm->dev, - "Failed to bypass %s: %d\n", + "ASoC: Failed to bypass %s: %d\n", w->name, ret); } @@ -1034,7 +1036,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ret = regulator_allow_bypass(w->regulator, false); if (ret != 0) dev_warn(w->dapm->dev, - "Failed to unbypass %s: %d\n", + "ASoC: Failed to unbypass %s: %d\n", w->name, ret); } @@ -1253,7 +1255,7 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, ret = w->event(w, NULL, event); trace_snd_soc_dapm_widget_event_done(w, event); if (ret < 0) - pr_err("%s: %s event failed: %d\n", + dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n", ev_name, w->name, ret); } } @@ -1402,7 +1404,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, if (ret < 0) dev_err(w->dapm->dev, - "Failed to apply widget power: %d\n", ret); + "ASoC: Failed to apply widget power: %d\n", ret); } if (!list_empty(&pending)) @@ -1431,20 +1433,21 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) (w->event_flags & SND_SOC_DAPM_PRE_REG)) { ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); if (ret != 0) - pr_err("%s DAPM pre-event failed: %d\n", + dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", w->name, ret); } ret = soc_widget_update_bits_locked(w, update->reg, update->mask, update->val); if (ret < 0) - pr_err("%s DAPM update failed: %d\n", w->name, ret); + dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n", + w->name, ret); if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) { ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); if (ret != 0) - pr_err("%s DAPM post-event failed: %d\n", + dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", w->name, ret); } } @@ -1466,7 +1469,7 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); if (ret != 0) dev_err(d->dev, - "Failed to turn on bias: %d\n", ret); + "ASoC: Failed to turn on bias: %d\n", ret); } /* Prepare for a STADDBY->ON or ON->STANDBY transition */ @@ -1474,7 +1477,7 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); if (ret != 0) dev_err(d->dev, - "Failed to prepare bias: %d\n", ret); + "ASoC: Failed to prepare bias: %d\n", ret); } } @@ -1492,7 +1495,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) d->target_bias_level == SND_SOC_BIAS_OFF)) { ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); if (ret != 0) - dev_err(d->dev, "Failed to apply standby bias: %d\n", + dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n", ret); } @@ -1501,7 +1504,8 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) d->target_bias_level == SND_SOC_BIAS_OFF) { ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); if (ret != 0) - dev_err(d->dev, "Failed to turn off bias: %d\n", ret); + dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n", + ret); if (d->dev) pm_runtime_put(d->dev); @@ -1512,7 +1516,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) d->target_bias_level == SND_SOC_BIAS_ON) { ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); if (ret != 0) - dev_err(d->dev, "Failed to apply active bias: %d\n", + dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n", ret); } } @@ -1838,7 +1842,7 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, if (!dapm->debugfs_dapm) { dev_warn(dapm->dev, - "Failed to create DAPM debugfs directory\n"); + "ASoC: Failed to create DAPM debugfs directory\n"); return; } @@ -2123,7 +2127,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); if (!w) { - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); return -EINVAL; } @@ -2212,8 +2216,16 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (!wsource) wsource = wtsource; - if (wsource == NULL || wsink == NULL) + if (wsource == NULL) { + dev_err(dapm->dev, "ASoC: no source widget found for %s\n", + route->source); return -ENODEV; + } + if (wsink == NULL) { + dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", + route->sink); + return -ENODEV; + } path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); if (!path) @@ -2308,7 +2320,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, return 0; err: - dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n", + dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", source, control, sink); kfree(path); return ret; @@ -2325,7 +2337,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, if (route->control) { dev_err(dapm->dev, - "Removal of routes with controls not supported\n"); + "ASoC: Removal of routes with controls not supported\n"); return -EINVAL; } @@ -2360,7 +2372,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, list_del(&path->list_source); kfree(path); } else { - dev_warn(dapm->dev, "Route %s->%s does not exist\n", + dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", source, sink); } @@ -2389,8 +2401,10 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, for (i = 0; i < num; i++) { r = snd_soc_dapm_add_route(dapm, route); if (r < 0) { - dev_err(dapm->dev, "Failed to add route %s->%s\n", - route->source, route->sink); + dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n", + route->source, + route->control ? route->control : "direct", + route->sink); ret = r; } route++; @@ -2438,19 +2452,19 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, int count = 0; if (!source) { - dev_err(dapm->dev, "Unable to find source %s for weak route\n", + dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n", route->source); return -ENODEV; } if (!sink) { - dev_err(dapm->dev, "Unable to find sink %s for weak route\n", + dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n", route->sink); return -ENODEV; } if (route->control || route->connected) - dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n", + dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n", route->source, route->sink); list_for_each_entry(path, &source->sinks, list_source) { @@ -2461,10 +2475,10 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, } if (count == 0) - dev_err(dapm->dev, "No path found for weak route %s->%s\n", + dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n", route->source, route->sink); if (count > 1) - dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n", + dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n", count, route->source, route->sink); return 0; @@ -2601,7 +2615,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, if (snd_soc_volsw_is_stereo(mc)) dev_warn(widget->dapm->dev, - "Control '%s' is stereo, which is not supported\n", + "ASoC: Control '%s' is stereo, which is not supported\n", kcontrol->id.name); ucontrol->value.integer.value[0] = @@ -2644,7 +2658,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, if (snd_soc_volsw_is_stereo(mc)) dev_warn(widget->dapm->dev, - "Control '%s' is stereo, which is not supported\n", + "ASoC: Control '%s' is stereo, which is not supported\n", kcontrol->id.name); val = (ucontrol->value.integer.value[0] & mask); @@ -3021,7 +3035,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->regulator = devm_regulator_get(dapm->dev, w->name); if (IS_ERR(w->regulator)) { ret = PTR_ERR(w->regulator); - dev_err(dapm->dev, "Failed to request %s: %d\n", + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; } @@ -3031,7 +3045,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); - dev_err(dapm->dev, "Failed to request %s: %d\n", + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; } @@ -3182,7 +3196,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, if (config->formats) { fmt = ffs(config->formats) - 1; } else { - dev_warn(w->dapm->dev, "Invalid format %llx specified\n", + dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", config->formats); fmt = 0; } @@ -3215,7 +3229,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, params, source); if (ret != 0) { dev_err(source->dev, - "hw_params() failed: %d\n", ret); + "ASoC: hw_params() failed: %d\n", ret); goto out; } } @@ -3226,7 +3240,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, sink); if (ret != 0) { dev_err(sink->dev, - "hw_params() failed: %d\n", ret); + "ASoC: hw_params() failed: %d\n", ret); goto out; } } @@ -3235,14 +3249,14 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: ret = snd_soc_dai_digital_mute(sink, 0); if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "Failed to unmute: %d\n", ret); + 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); if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "Failed to mute: %d\n", ret); + dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret); ret = 0; break; @@ -3281,11 +3295,11 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD; - dev_dbg(card->dev, "adding %s widget\n", link_name); + dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control(&card->dapm, &template); if (!w) { - dev_err(card->dev, "Failed to create %s widget\n", + dev_err(card->dev, "ASoC: Failed to create %s widget\n", link_name); return -ENOMEM; } @@ -3319,12 +3333,12 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name = dai->driver->playback.stream_name; template.sname = dai->driver->playback.stream_name; - dev_dbg(dai->dev, "adding %s widget\n", + dev_dbg(dai->dev, "ASoC: adding %s widget\n", template.name); w = snd_soc_dapm_new_control(dapm, &template); if (!w) { - dev_err(dapm->dev, "Failed to create %s widget\n", + dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", dai->driver->playback.stream_name); } @@ -3337,12 +3351,12 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name = dai->driver->capture.stream_name; template.sname = dai->driver->capture.stream_name; - dev_dbg(dai->dev, "adding %s widget\n", + dev_dbg(dai->dev, "ASoC: adding %s widget\n", template.name); w = snd_soc_dapm_new_control(dapm, &template); if (!w) { - dev_err(dapm->dev, "Failed to create %s widget\n", + dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", dai->driver->capture.stream_name); } @@ -3518,11 +3532,11 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); if (!w) { - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin); return -EINVAL; } - dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin); + dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); w->connected = 1; w->force = 1; dapm_mark_dirty(w, "force enable"); @@ -3605,7 +3619,7 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false); if (!w) { - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin); return -EINVAL; } @@ -3664,7 +3678,7 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_widget *w; - dev_dbg(codec->dev, "Auto NC: DAPMs: card:%p codec:%p\n", + dev_dbg(codec->dev, "ASoC: Auto NC: DAPMs: card:%p codec:%p\n", &card->dapm, &codec->dapm); list_for_each_entry(w, &card->widgets, list) { @@ -3674,7 +3688,7 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) case snd_soc_dapm_input: case snd_soc_dapm_output: case snd_soc_dapm_micbias: - dev_dbg(codec->dev, "Auto NC: Checking widget %s\n", + dev_dbg(codec->dev, "ASoC: Auto NC: Checking widget %s\n", w->name); if (!snd_soc_dapm_widget_in_card_paths(card, w)) { dev_dbg(codec->dev, diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index bbc125748a38..111b7d921e89 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -317,3 +317,5 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) return 0; } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); + +MODULE_LICENSE("GPL"); diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 1ab5fe04bfcc..0bb5cccd7766 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -66,7 +66,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) struct snd_soc_dapm_context *dapm; struct snd_soc_jack_pin *pin; int enable; - int oldstatus; trace_snd_soc_jack_report(jack, mask, status); @@ -78,8 +77,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) mutex_lock(&jack->mutex); - oldstatus = jack->status; - jack->status &= ~mask; jack->status |= status & mask; @@ -172,12 +169,13 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!pins[i].pin) { - printk(KERN_ERR "No name for pin %d\n", i); + dev_err(jack->codec->dev, "ASoC: No name for pin %d\n", + i); return -EINVAL; } if (!pins[i].mask) { - printk(KERN_ERR "No mask for pin %d (%s)\n", i, - pins[i].pin); + dev_err(jack->codec->dev, "ASoC: No mask for pin %d" + " (%s)\n", i, pins[i].pin); return -EINVAL; } @@ -297,13 +295,13 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!gpio_is_valid(gpios[i].gpio)) { - printk(KERN_ERR "Invalid gpio %d\n", + dev_err(jack->codec->dev, "ASoC: Invalid gpio %d\n", gpios[i].gpio); ret = -EINVAL; goto undo; } if (!gpios[i].name) { - printk(KERN_ERR "No name for gpio %d\n", + dev_err(jack->codec->dev, "ASoC: No name for gpio %d\n", gpios[i].gpio); ret = -EINVAL; goto undo; @@ -332,7 +330,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (gpios[i].wake) { ret = irq_set_irq_wake(gpio_to_irq(gpios[i].gpio), 1); if (ret != 0) - printk(KERN_ERR + dev_err(jack->codec->dev, "ASoC: " "Failed to mark GPIO %d as wake source: %d\n", gpios[i].gpio, ret); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ef22d0bd9e9e..5c3ca2a34661 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -43,7 +43,7 @@ static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, struct snd_soc_pcm_runtime *be = dpcm->be; - dev_dbg(be->dev, "pm: BE %s event %d dir %d\n", + dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n", be->dai_link->name, event, dir); snd_soc_dapm_stream_event(be, dir, event); @@ -70,18 +70,19 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, */ if (!soc_dai->rate) { dev_warn(soc_dai->dev, - "Not enforcing symmetric_rates due to race\n"); + "ASoC: Not enforcing symmetric_rates due to race\n"); return 0; } - dev_dbg(soc_dai->dev, "Symmetry forces %dHz rate\n", soc_dai->rate); + dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, soc_dai->rate, soc_dai->rate); if (ret < 0) { dev_err(soc_dai->dev, - "Unable to apply rate symmetry constraint: %d\n", ret); + "ASoC: Unable to apply rate symmetry constraint: %d\n", + ret); return ret; } @@ -118,7 +119,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, sample_sizes[i], bits); if (ret != 0) dev_warn(dai->dev, - "Failed to set MSB %d/%d: %d\n", + "ASoC: Failed to set MSB %d/%d: %d\n", bits, sample_sizes[i], ret); } } @@ -149,8 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai); if (ret < 0) { - dev_err(cpu_dai->dev, "can't open interface %s: %d\n", - cpu_dai->name, ret); + dev_err(cpu_dai->dev, "ASoC: can't open interface" + " %s: %d\n", cpu_dai->name, ret); goto out; } } @@ -158,8 +159,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->open) { ret = platform->driver->ops->open(substream); if (ret < 0) { - dev_err(platform->dev, "can't open platform %s: %d\n", - platform->name, ret); + dev_err(platform->dev, "ASoC: can't open platform" + " %s: %d\n", platform->name, ret); goto platform_err; } } @@ -167,8 +168,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); if (ret < 0) { - dev_err(codec_dai->dev, "can't open codec %s: %d\n", - codec_dai->name, ret); + dev_err(codec_dai->dev, "ASoC: can't open codec" + " %s: %d\n", codec_dai->name, ret); goto codec_dai_err; } } @@ -176,7 +177,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { ret = rtd->dai_link->ops->startup(substream); if (ret < 0) { - pr_err("asoc: %s startup failed: %d\n", + pr_err("ASoC: %s startup failed: %d\n", rtd->dai_link->name, ret); goto machine_err; } @@ -238,18 +239,18 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ret = -EINVAL; snd_pcm_limit_hw_rates(runtime); if (!runtime->hw.rates) { - printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", + printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", codec_dai->name, cpu_dai->name); goto config_err; } if (!runtime->hw.formats) { - printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", + printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", codec_dai->name, cpu_dai->name); goto config_err; } if (!runtime->hw.channels_min || !runtime->hw.channels_max || runtime->hw.channels_min > runtime->hw.channels_max) { - printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", + printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", codec_dai->name, cpu_dai->name); goto config_err; } @@ -270,12 +271,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto config_err; } - pr_debug("asoc: %s <-> %s info:\n", + pr_debug("ASoC: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); - pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); - pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, + pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); + pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, runtime->hw.channels_max); - pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, + pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min, runtime->hw.rate_max); dynamic: @@ -330,7 +331,7 @@ static void close_delayed_work(struct work_struct *work) mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - pr_debug("pop wq checking: %s status: %s waiting: %s\n", + 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", codec_dai->pop_wait ? "yes" : "no"); @@ -444,7 +445,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); if (ret < 0) { - pr_err("asoc: machine prepare error: %d\n", ret); + dev_err(rtd->card->dev, "ASoC: machine prepare error:" + " %d\n", ret); goto out; } } @@ -452,8 +454,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->prepare) { ret = platform->driver->ops->prepare(substream); if (ret < 0) { - dev_err(platform->dev, "platform prepare error: %d\n", - ret); + dev_err(platform->dev, "ASoC: platform prepare error:" + " %d\n", ret); goto out; } } @@ -461,7 +463,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); if (ret < 0) { - dev_err(codec_dai->dev, "DAI prepare error: %d\n", + dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n", ret); goto out; } @@ -470,7 +472,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { - dev_err(cpu_dai->dev, "DAI prepare error: %d\n", + dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n", ret); goto out; } @@ -512,7 +514,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { - pr_err("asoc: machine hw_params failed: %d\n", ret); + dev_err(rtd->card->dev, "ASoC: machine hw_params" + " failed: %d\n", ret); goto out; } } @@ -520,8 +523,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (codec_dai->driver->ops->hw_params) { ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); if (ret < 0) { - dev_err(codec_dai->dev, "can't set %s hw params: %d\n", - codec_dai->name, ret); + dev_err(codec_dai->dev, "ASoC: can't set %s hw params:" + " %d\n", codec_dai->name, ret); goto codec_err; } } @@ -529,7 +532,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (cpu_dai->driver->ops->hw_params) { ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); if (ret < 0) { - dev_err(cpu_dai->dev, "%s hw params failed: %d\n", + dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n", cpu_dai->name, ret); goto interface_err; } @@ -538,7 +541,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (platform->driver->ops && platform->driver->ops->hw_params) { ret = platform->driver->ops->hw_params(substream, params); if (ret < 0) { - dev_err(platform->dev, "%s hw params failed: %d\n", + dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", platform->name, ret); goto platform_err; } @@ -760,7 +763,7 @@ static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm, *d; list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { - dev_dbg(fe->dev, "BE %s disconnect check for %s\n", + dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", stream ? "capture" : "playback", dpcm->be->dai_link->name); @@ -815,7 +818,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, } } - dev_err(card->dev, "can't get %s BE for %s\n", + dev_err(card->dev, "ASoC: can't get %s BE for %s\n", stream ? "capture" : "playback", widget->name); return NULL; } @@ -866,7 +869,7 @@ static int dpcm_path_get(struct snd_soc_pcm_runtime *fe, /* get number of valid DAI paths and their widgets */ paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); - dev_dbg(fe->dev, "found %d audio %s paths\n", paths, + dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, stream ? "capture" : "playback"); *list_ = list; @@ -903,7 +906,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, if (widget && widget_in_list(list, widget)) continue; - dev_dbg(fe->dev, "pruning %s BE %s for %s\n", + dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", stream ? "capture" : "playback", dpcm->be->dai_link->name, fe->dai_link->name); dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; @@ -911,7 +914,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, prune++; } - dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune); + dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune); return prune; } @@ -932,7 +935,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, /* is there a valid BE rtd for this widget */ be = dpcm_get_be(card, list->widgets[i], stream); if (!be) { - dev_err(fe->dev, "no BE found for %s\n", + dev_err(fe->dev, "ASoC: no BE found for %s\n", list->widgets[i]->name); continue; } @@ -948,7 +951,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, /* newly connected FE and BE */ err = dpcm_be_connect(fe, be, stream); if (err < 0) { - dev_err(fe->dev, "can't connect %s\n", + dev_err(fe->dev, "ASoC: can't connect %s\n", list->widgets[i]->name); break; } else if (err == 0) /* already connected */ @@ -959,7 +962,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, new++; } - dev_dbg(fe->dev, "found %d new BE paths\n", new); + dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new); return new; } @@ -998,7 +1001,7 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, snd_soc_dpcm_get_substream(be, stream); if (be->dpcm[stream].users == 0) - dev_err(be->dev, "no users %s at close - state %d\n", + dev_err(be->dev, "ASoC: no users %s at close - state %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1032,7 +1035,7 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) /* first time the dpcm is open ? */ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) - dev_err(be->dev, "too many users %s at open %d\n", + dev_err(be->dev, "ASoC: too many users %s at open %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1043,15 +1046,15 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue; - dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name); + dev_dbg(be->dev, "ASoC: open BE %s\n", be->dai_link->name); be_substream->runtime = be->dpcm[stream].runtime; err = soc_pcm_open(be_substream); if (err < 0) { - dev_err(be->dev, "BE open failed %d\n", err); + dev_err(be->dev, "ASoC: BE open failed %d\n", err); be->dpcm[stream].users--; if (be->dpcm[stream].users < 0) - dev_err(be->dev, "no users %s at unwind %d\n", + dev_err(be->dev, "ASoC: no users %s at unwind %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1076,7 +1079,7 @@ unwind: continue; if (be->dpcm[stream].users == 0) - dev_err(be->dev, "no users %s at close %d\n", + dev_err(be->dev, "ASoC: no users %s at close %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1128,16 +1131,16 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) ret = dpcm_be_dai_startup(fe, fe_substream->stream); if (ret < 0) { - dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret); + dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret); goto be_err; } - dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name); /* start the DAI frontend */ ret = soc_pcm_open(fe_substream); if (ret < 0) { - dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret); + dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret); goto unwind; } @@ -1172,7 +1175,7 @@ static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) continue; if (be->dpcm[stream].users == 0) - dev_err(be->dev, "no users %s at close - state %d\n", + dev_err(be->dev, "ASoC: no users %s at close - state %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1183,7 +1186,7 @@ static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) continue; - dev_dbg(be->dev, "dpcm: close BE %s\n", + dev_dbg(be->dev, "ASoC: close BE %s\n", dpcm->fe->dai_link->name); soc_pcm_close(be_substream); @@ -1204,7 +1207,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) /* shutdown the BEs */ dpcm_be_dai_shutdown(fe, substream->stream); - dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name); /* now shutdown the frontend */ soc_pcm_close(substream); @@ -1243,7 +1246,7 @@ static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) continue; - dev_dbg(be->dev, "dpcm: hw_free BE %s\n", + dev_dbg(be->dev, "ASoC: hw_free BE %s\n", dpcm->fe->dai_link->name); soc_pcm_hw_free(be_substream); @@ -1262,12 +1265,12 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; - dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name); /* call hw_free on the frontend */ err = soc_pcm_hw_free(substream); if (err < 0) - dev_err(fe->dev,"dpcm: hw_free FE %s failed\n", + dev_err(fe->dev,"ASoC: hw_free FE %s failed\n", fe->dai_link->name); /* only hw_params backends that are either sinks or sources @@ -1305,7 +1308,7 @@ static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE)) continue; - dev_dbg(be->dev, "dpcm: hw_params BE %s\n", + dev_dbg(be->dev, "ASoC: hw_params BE %s\n", dpcm->fe->dai_link->name); /* copy params for each dpcm */ @@ -1318,7 +1321,7 @@ static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) &dpcm->hw_params); if (ret < 0) { dev_err(be->dev, - "dpcm: hw_params BE fixup failed %d\n", + "ASoC: hw_params BE fixup failed %d\n", ret); goto unwind; } @@ -1327,7 +1330,7 @@ static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); if (ret < 0) { dev_err(dpcm->be->dev, - "dpcm: hw_params BE failed %d\n", ret); + "ASoC: hw_params BE failed %d\n", ret); goto unwind; } @@ -1374,18 +1377,18 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, sizeof(struct snd_pcm_hw_params)); ret = dpcm_be_dai_hw_params(fe, substream->stream); if (ret < 0) { - dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret); + dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret); goto out; } - dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n", + dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n", fe->dai_link->name, params_rate(params), params_channels(params), params_format(params)); /* call hw_params on the frontend */ ret = soc_pcm_hw_params(substream, params); if (ret < 0) { - dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret); dpcm_be_dai_hw_free(fe, stream); } else fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; @@ -1401,12 +1404,12 @@ static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, { int ret; - dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n", + dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n", dpcm->fe->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); if (ret < 0) - dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret); + dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret); return ret; } @@ -1517,12 +1520,12 @@ static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) case SND_SOC_DPCM_TRIGGER_PRE: /* call trigger on the frontend before the backend. */ - dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n", + dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", fe->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto out; } @@ -1533,11 +1536,11 @@ static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto out; } - dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n", + dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", fe->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); @@ -1545,17 +1548,17 @@ static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) case SND_SOC_DPCM_TRIGGER_BESPOKE: /* bespoke trigger() - handles both FE and BEs */ - dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n", + dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n", fe->dai_link->name, cmd); ret = soc_pcm_bespoke_trigger(substream, cmd); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto out; } break; default: - dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd, + dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, fe->dai_link->name); ret = -EINVAL; goto out; @@ -1598,12 +1601,12 @@ static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) continue; - dev_dbg(be->dev, "dpcm: prepare BE %s\n", + dev_dbg(be->dev, "ASoC: prepare BE %s\n", dpcm->fe->dai_link->name); ret = soc_pcm_prepare(be_substream); if (ret < 0) { - dev_err(be->dev, "dpcm: backend prepare failed %d\n", + dev_err(be->dev, "ASoC: backend prepare failed %d\n", ret); break; } @@ -1620,13 +1623,13 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; /* there is no point preparing this FE if there are no BEs */ if (list_empty(&fe->dpcm[stream].be_clients)) { - dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n", + dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n", fe->dai_link->name); ret = -EINVAL; goto out; @@ -1639,7 +1642,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) /* call prepare on the frontend */ ret = soc_pcm_prepare(substream); if (ret < 0) { - dev_err(fe->dev,"dpcm: prepare FE %s failed\n", + dev_err(fe->dev,"ASoC: prepare FE %s failed\n", fe->dai_link->name); goto out; } @@ -1673,33 +1676,33 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int err; - dev_dbg(fe->dev, "runtime %s close on FE %s\n", + dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { /* call bespoke trigger - FE takes care of all BE triggers */ - dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n", + dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n", fe->dai_link->name); err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); if (err < 0) - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err); } else { - dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n", + dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n", fe->dai_link->name); err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); if (err < 0) - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err); } err = dpcm_be_dai_hw_free(fe, stream); if (err < 0) - dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err); + dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err); err = dpcm_be_dai_shutdown(fe, stream); if (err < 0) - dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err); + dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err); /* run the stream event for each BE */ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); @@ -1715,7 +1718,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int ret; - dev_dbg(fe->dev, "runtime %s open on FE %s\n", + dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); /* Only start the BE if the FE is ready */ @@ -1761,22 +1764,22 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { /* call trigger on the frontend - FE takes care of all BE triggers */ - dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n", + dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n", fe->dai_link->name); ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); if (ret < 0) { - dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret); goto hw_free; } } else { - dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", + dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n", fe->dai_link->name); ret = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_START); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto hw_free; } } @@ -1805,7 +1808,7 @@ static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; ret = dpcm_run_update_startup(fe, stream); if (ret < 0) - dev_err(fe->dev, "failed to startup some BEs\n"); + dev_err(fe->dev, "ASoC: failed to startup some BEs\n"); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; return ret; @@ -1818,7 +1821,7 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; ret = dpcm_run_update_shutdown(fe, stream); if (ret < 0) - dev_err(fe->dev, "failed to shutdown some BEs\n"); + dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; return ret; @@ -1853,7 +1856,7 @@ int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) continue; /* DAPM sync will call this to update DSP paths */ - dev_dbg(fe->dev, "DPCM runtime update for FE %s\n", + dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n", fe->dai_link->name); /* skip if FE doesn't have playback capability */ @@ -1862,7 +1865,7 @@ int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); if (paths < 0) { - dev_warn(fe->dev, "%s no valid %s path\n", + dev_warn(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, "playback"); mutex_unlock(&card->mutex); return paths; @@ -1891,7 +1894,7 @@ capture: paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); if (paths < 0) { - dev_warn(fe->dev, "%s no valid %s path\n", + dev_warn(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, "capture"); mutex_unlock(&card->mutex); return paths; @@ -1934,7 +1937,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) if (be->dai_link->ignore_suspend) continue; - dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name); + dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name); if (drv->ops->digital_mute && dai->playback_active) drv->ops->digital_mute(dai, mute); @@ -1955,7 +1958,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) fe->dpcm[stream].runtime = fe_substream->runtime; if (dpcm_path_get(fe, stream, &list) <= 0) { - dev_dbg(fe->dev, "asoc: %s no valid %s route\n", + dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", fe->dai_link->name, stream ? "capture" : "playback"); } @@ -2039,11 +2042,11 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) capture, &pcm); } if (ret < 0) { - dev_err(rtd->card->dev, "can't create pcm for %s\n", + dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n", rtd->dai_link->name); return ret; } - dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); + dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); @@ -2097,7 +2100,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (platform->driver->pcm_new) { ret = platform->driver->pcm_new(rtd); if (ret < 0) { - dev_err(platform->dev, "pcm constructor failed\n"); + dev_err(platform->dev, + "ASoC: pcm constructor failed: %d\n", + ret); return ret; } } diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index bf99296bce95..49653375970b 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -210,7 +210,7 @@ static int __devexit tegra20_das_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra20_das_of_match[] __devinitconst = { +static const struct of_device_id tegra20_das_of_match[] = { { .compatible = "nvidia,tegra20-das", }, {}, }; diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 0832e8afd73c..2ae8af86edbd 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -463,12 +463,12 @@ static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = { +static const struct of_device_id tegra20_i2s_of_match[] = { { .compatible = "nvidia,tegra20-i2s", }, {}, }; -static const struct dev_pm_ops tegra20_i2s_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra20_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend, tegra20_i2s_runtime_resume, NULL) }; diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 3ebc8670ba00..d9641ef7b1ee 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -373,7 +373,7 @@ static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev) return 0; } -static const struct dev_pm_ops tegra20_spdif_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra20_spdif_pm_ops = { SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend, tegra20_spdif_runtime_resume, NULL) }; diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index bf5610122c76..2269170b0df4 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -288,7 +288,7 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) } EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); -static const char * const configlink_clocks[] __devinitconst = { +static const char * const configlink_clocks[] = { "i2s0", "i2s1", "i2s2", @@ -603,12 +603,12 @@ static int __devexit tegra30_ahub_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra30_ahub_of_match[] __devinitconst = { +static const struct of_device_id tegra30_ahub_of_match[] = { { .compatible = "nvidia,tegra30-ahub", }, {}, }; -static const struct dev_pm_ops tegra30_ahub_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra30_ahub_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, tegra30_ahub_runtime_resume, NULL) }; diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 44184228d1f0..bf0e089e7997 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -508,12 +508,12 @@ static int __devexit tegra30_i2s_platform_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra30_i2s_of_match[] __devinitconst = { +static const struct of_device_id tegra30_i2s_of_match[] = { { .compatible = "nvidia,tegra30-i2s", }, {}, }; -static const struct dev_pm_ops tegra30_i2s_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra30_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend, tegra30_i2s_runtime_resume, NULL) }; diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 76cb1b363b71..523795a6e83e 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -242,7 +242,7 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra_alc5632_of_match[] __devinitconst = { +static const struct of_device_id tegra_alc5632_of_match[] = { { .compatible = "nvidia,tegra-audio-alc5632", }, {}, }; diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index ea9166d5c4eb..effe5b41b5f9 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -200,7 +200,7 @@ static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra_wm8753_of_match[] __devinitconst = { +static const struct of_device_id tegra_wm8753_of_match[] = { { .compatible = "nvidia,tegra-audio-wm8753", }, {}, }; diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index cee13b7bfb94..0f794126fbe4 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -417,7 +417,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra_wm8903_of_match[] __devinitconst = { +static const struct of_device_id tegra_wm8903_of_match[] = { { .compatible = "nvidia,tegra-audio-wm8903", }, {}, }; diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index e69a4f7000d6..4a255a4d0c47 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -195,7 +195,7 @@ static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id trimslice_of_match[] __devinitconst = { +static const struct of_device_id trimslice_of_match[] = { { .compatible = "nvidia,tegra-audio-trimslice", }, {}, }; diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 54f7e25b6f7d..651a52a95fd7 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -33,7 +33,7 @@ struct snd_soc_dai_link mop500_dai_links[] = { .stream_name = "ab8500_0", .cpu_dai_name = "ux500-msp-i2s.1", .codec_dai_name = "ab8500-codec-dai.0", - .platform_name = "ux500-pcm.0", + .platform_name = "ux500-msp-i2s.1", .codec_name = "ab8500-codec.0", .init = mop500_ab8500_machine_init, .ops = mop500_ab8500_ops, @@ -43,7 +43,7 @@ struct snd_soc_dai_link mop500_dai_links[] = { .stream_name = "ab8500_1", .cpu_dai_name = "ux500-msp-i2s.3", .codec_dai_name = "ab8500-codec-dai.1", - .platform_name = "ux500-pcm.0", + .platform_name = "ux500-msp-i2s.3", .codec_name = "ab8500-codec.0", .init = NULL, .ops = mop500_ab8500_ops, diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index be94bf9bf94f..478b4b60e0cc 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -28,6 +28,7 @@ #include "ux500_msp_i2s.h" #include "ux500_msp_dai.h" +#include "ux500_pcm.h" static int setup_pcm_multichan(struct snd_soc_dai *dai, struct ux500_msp_config *msp_config) @@ -398,11 +399,28 @@ static int ux500_msp_dai_startup(struct snd_pcm_substream *substream, return ret; } - /* Enable clock */ - dev_dbg(dai->dev, "%s: Enabling MSP-clock.\n", __func__); - clk_enable(drvdata->clk); + /* Prepare and enable clocks */ + dev_dbg(dai->dev, "%s: Enabling MSP-clocks.\n", __func__); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->msp->dev, + "%s: Failed to prepare/enable pclk!\n", __func__); + goto err_pclk; + } - return 0; + ret = clk_prepare_enable(drvdata->clk); + if (ret) { + dev_err(drvdata->msp->dev, + "%s: Failed to prepare/enable clk!\n", __func__); + goto err_clk; + } + + return ret; +err_clk: + clk_disable_unprepare(drvdata->pclk); +err_pclk: + regulator_disable(drvdata->reg_vape); + return ret; } static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, @@ -428,8 +446,9 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, __func__, dai->id, snd_pcm_stream_str(substream)); } - /* Disable clock */ - clk_disable(drvdata->clk); + /* Disable and unprepare clocks */ + clk_disable_unprepare(drvdata->clk); + clk_disable_unprepare(drvdata->pclk); /* Disable regulator */ ret = regulator_disable(drvdata->reg_vape); @@ -780,6 +799,14 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) } prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50); + drvdata->pclk = clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(drvdata->pclk)) { + ret = (int)PTR_ERR(drvdata->pclk); + dev_err(&pdev->dev, "%s: ERROR: clk_get of pclk failed (%d)!\n", + __func__, ret); + goto err_pclk; + } + drvdata->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(drvdata->clk)) { ret = (int)PTR_ERR(drvdata->clk); @@ -806,12 +833,23 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) goto err_init_msp; } + ret = ux500_pcm_register_platform(pdev); + if (ret < 0) { + dev_err(&pdev->dev, + "Error: %s: Failed to register PCM platform device!\n", + __func__); + goto err_reg_plat; + } + return 0; +err_reg_plat: + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); err_init_msp: clk_put(drvdata->clk); - err_clk: + clk_put(drvdata->pclk); +err_pclk: devm_regulator_put(drvdata->reg_vape); return ret; @@ -821,12 +859,15 @@ static int __devexit ux500_msp_drv_remove(struct platform_device *pdev) { struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + ux500_pcm_unregister_platform(pdev); + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); devm_regulator_put(drvdata->reg_vape); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); clk_put(drvdata->clk); + clk_put(drvdata->pclk); ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp); diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index 98202a34a5dd..9c778d9c3838 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -69,6 +69,7 @@ struct ux500_msp_i2s_drvdata { /* Clocks */ unsigned int master_clk; struct clk *clk; + struct clk *pclk; /* Regulators */ int vape_opp_constraint; diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 1a04e248453c..894c9f4bb9f6 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -282,7 +282,7 @@ static struct snd_soc_platform_driver ux500_pcm_soc_drv = { .pcm_new = ux500_pcm_new, }; -static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev) +int __devinit ux500_pcm_register_platform(struct platform_device *pdev) { int ret; @@ -296,23 +296,12 @@ static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev) return 0; } +EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); -static int __devinit ux500_pcm_drv_remove(struct platform_device *pdev) +int __devexit ux500_pcm_unregister_platform(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; } - -static struct platform_driver ux500_pcm_driver = { - .driver = { - .name = "ux500-pcm", - .owner = THIS_MODULE, - }, - - .probe = ux500_pcm_drv_probe, - .remove = __devexit_p(ux500_pcm_drv_remove), -}; -module_platform_driver(ux500_pcm_driver); - -MODULE_LICENSE("GPL v2"); +EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h index 77ed44d371e9..76d344476afc 100644 --- a/sound/soc/ux500/ux500_pcm.h +++ b/sound/soc/ux500/ux500_pcm.h @@ -32,4 +32,7 @@ #define UX500_PLATFORM_PERIODS_MAX 48 #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) +int ux500_pcm_register_platform(struct platform_device *pdev); +int ux500_pcm_unregister_platform(struct platform_device *pdev); + #endif diff --git a/sound/usb/midi.c b/sound/usb/midi.c index c83f6143c0eb..eeefbce3873c 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -148,6 +148,7 @@ struct snd_usb_midi_out_endpoint { struct snd_usb_midi_out_endpoint* ep; struct snd_rawmidi_substream *substream; int active; + bool autopm_reference; uint8_t cable; /* cable number << 4 */ uint8_t state; #define STATE_UNKNOWN 0 @@ -1076,7 +1077,8 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) return -ENXIO; } err = usb_autopm_get_interface(umidi->iface); - if (err < 0) + port->autopm_reference = err >= 0; + if (err < 0 && err != -EACCES) return -EIO; substream->runtime->private_data = port; port->state = STATE_UNKNOWN; @@ -1087,9 +1089,11 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct usbmidi_out_port *port = substream->runtime->private_data; substream_open(substream, 0); - usb_autopm_put_interface(umidi->iface); + if (port->autopm_reference) + usb_autopm_put_interface(umidi->iface); return 0; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 5c12a3fe8c3e..ef6fa24fc473 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -459,7 +459,7 @@ static int configure_endpoint(struct snd_usb_substream *subs) return ret; if (subs->sync_endpoint) - ret = snd_usb_endpoint_set_params(subs->data_endpoint, + ret = snd_usb_endpoint_set_params(subs->sync_endpoint, subs->pcm_format, subs->channels, subs->period_bytes, |