diff options
148 files changed, 6416 insertions, 2199 deletions
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt new file mode 100644 index 0000000..38e51ad --- /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/sound/ak4104.txt b/Documentation/devicetree/bindings/sound/ak4104.txt new file mode 100644 index 0000000..b902ee3 --- /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 0000000..9c5a994 --- /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 c81b5fd..a850fb9 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 65dec87..fd40c85 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/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index d410581..aaa42d8 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 3e6e5c1..3b721ee 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 e6391a4..2dcec8d 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 3add030..acfa207 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 03fc136..69667d0 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 5269825..af47c75 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 3cee0e6..9e76427a 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 f820261..a41eb3d 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 414bd85..e67cfa2 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 04295c0..7fcbe05 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 cd604aa..a27d9dd 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 d6f9c23..c0f4c8c 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 9c61e59..8215839 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 84af1b5..a4282d3 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 fcd233c..d26474a 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 72e9084..b683fdc 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 5047bdc..b656110 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 e503538..18fbbb2 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 3ab2b86..ebdbf42 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 32ee3f8..d9bc3fa 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/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 80f9ab9..ac869d2 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 bb1ff17..f4b9dd0 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 52069d2..96253cd 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/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7c0f1ec..104a7c3 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 83fe6f5..5ea769e 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 0000000..7a04f54 --- /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/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 1b48f20..7561971 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/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 8fefc96..45a20c5 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -401,13 +401,19 @@ static const __devinitconst struct reg_default wm1811_reva_patch[] = { */ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) { - struct wm8994_pdata *pdata = wm8994->dev->platform_data; + struct wm8994_pdata *pdata; struct regmap_config *regmap_config; const struct reg_default *regmap_patch = NULL; const char *devname; int ret, i, patch_regs; int pulls = 0; + if (dev_get_platdata(wm8994->dev)) { + pdata = dev_get_platdata(wm8994->dev); + wm8994->pdata = *pdata; + } + pdata = &wm8994->pdata; + dev_set_drvdata(wm8994->dev, wm8994); /* Add the on-chip regulators first for bootstrapping */ @@ -604,24 +610,21 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) } } - if (pdata) { - wm8994->irq_base = pdata->irq_base; - wm8994->gpio_base = pdata->gpio_base; - - /* GPIO configuration is only applied if it's non-zero */ - for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { - if (pdata->gpio_defaults[i]) { - wm8994_set_bits(wm8994, WM8994_GPIO_1 + i, - 0xffff, - pdata->gpio_defaults[i]); - } + wm8994->irq_base = pdata->irq_base; + wm8994->gpio_base = pdata->gpio_base; + + /* GPIO configuration is only applied if it's non-zero */ + for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { + if (pdata->gpio_defaults[i]) { + wm8994_set_bits(wm8994, WM8994_GPIO_1 + i, + 0xffff, pdata->gpio_defaults[i]); } + } - wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven; + wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven; - if (pdata->spkmode_pu) - pulls |= WM8994_SPKMODE_PU; - } + if (pdata->spkmode_pu) + pulls |= WM8994_SPKMODE_PU; /* Disable unneeded pulls */ wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5bb1877..d07a9ed 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/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h index 4eb3175..deb0ae5 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/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index dd231ac..a580363 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 7ab4429..8b1d1da 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/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h index 1f17330..ae5c249 100644 --- a/include/linux/mfd/wm8994/core.h +++ b/include/linux/mfd/wm8994/core.h @@ -19,6 +19,8 @@ #include <linux/interrupt.h> #include <linux/regmap.h> +#include <linux/mfd/wm8994/pdata.h> + enum wm8994_type { WM8994 = 0, WM8958 = 1, @@ -55,6 +57,8 @@ struct regulator_bulk_data; struct wm8994 { struct mutex irq_lock; + struct wm8994_pdata pdata; + enum wm8994_type type; int revision; int cust_id; diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index fc87be4..8e21a09 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -176,6 +176,11 @@ struct wm8994_pdata { unsigned int lineout1fb:1; unsigned int lineout2fb:1; + /* Delay between detecting a jack and starting microphone + * detect (specified in ms) + */ + int micdet_delay; + /* IRQ for microphone detection if brought out directly as a * signal. */ diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h index aa9875f..8827259 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 d0c5825..f3d6e4f 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -16,6 +16,8 @@ #ifndef __DAVINCI_ASP_H #define __DAVINCI_ASP_H +#include <linux/genalloc.h> + struct snd_platform_data { u32 tx_dma_offset; u32 rx_dma_offset; @@ -30,6 +32,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/regmap.h b/include/linux/regmap.h index e3bcc3f..9f228d7 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/sound/cs4271.h b/include/sound/cs4271.h index 50a059e..6d9e15e 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 9060103..cc1c919 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 c009f70..24e5d99 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/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 72b09cf..d1b691b 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 a5c0bf1..41967cc 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 0000000..30184a4 --- /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 0000000..6a293c7 --- /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 9b84f98..e99f181 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 5e0a95e..bb45d20 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 354341e..1c76634 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 5d4f0f9b..b1f08d5 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 c883514..0744610 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 b92759a..3a84782 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 9bd4d95..f6e8e36 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 af54749..4d96090 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 31d4483..4b11b82 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 618fdc3..fc55810 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 b3e24f2..546466a 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 054967d..87cfaa3 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -380,6 +380,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; } @@ -925,6 +937,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 +985,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; } @@ -1002,6 +1020,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source, 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 36ec649..84c415d 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,22 @@ 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_lhpf1_mode; extern const struct soc_enum arizona_lhpf2_mode; extern const struct soc_enum arizona_lhpf3_mode; @@ -146,6 +191,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 e3f0a7f..6ad3878 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -474,15 +474,25 @@ static int cs4271_probe(struct snd_soc_codec *codec) struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; int ret; int gpio_nreset = -EINVAL; + int amutec_eq_bmutec = 0; #ifdef CONFIG_OF - if (of_match_device(cs4271_dt_ids, codec->dev)) + if (of_match_device(cs4271_dt_ids, codec->dev)) { gpio_nreset = of_get_named_gpio(codec->dev->of_node, "reset-gpio", 0); + + if (!of_get_property(codec->dev->of_node, + "cirrus,amutec-eq-bmutec", NULL)) + amutec_eq_bmutec = 1; + } #endif - if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset)) - gpio_nreset = cs4271plat->gpio_nreset; + if (cs4271plat) { + if (gpio_is_valid(cs4271plat->gpio_nreset)) + gpio_nreset = cs4271plat->gpio_nreset; + + amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; + } if (gpio_nreset >= 0) if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) @@ -528,6 +538,11 @@ static int cs4271_probe(struct snd_soc_codec *codec) /* Power-up sequence requires 85 uS */ udelay(85); + if (amutec_eq_bmutec) + snd_soc_update_bits(codec, CS4271_MODE2, + CS4271_MODE2_MUTECAEQUB, + CS4271_MODE2_MUTECAEQUB); + return snd_soc_add_codec_controls(codec, cs4271_snd_controls, ARRAY_SIZE(cs4271_snd_controls)); } diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index af5db70..ab1ee5b 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; } diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index f379b08..d3a6de2 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 85d9cab..9ad1da3 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 99b0a9d..096b6aa 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 17b3ec2..a777de6 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 3264a51..b858264 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 0000000..c9772ca --- /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 960d0e9..d6ca615 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 0000000..38145ba --- /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 f230292..e39e08d 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 aae2b24..3577422 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 99afc00..40256b5 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 683dc43..02750ab 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 eab64a1..ff45b02 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 7f56758..9f57996 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 7394e73..53793b1 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 }, @@ -687,6 +695,9 @@ 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), +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 +719,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,17 +748,6 @@ 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_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, ARIZONA_SPK1R_MUTE_SHIFT, 1, 1), @@ -819,11 +811,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 +860,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 +891,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 +993,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 +1070,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 +1095,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 +1129,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 +1221,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 +1268,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 +1392,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 +1440,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 +1459,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 +1469,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 9211e41..2a075ad 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -308,10 +308,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 +352,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 +586,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 +611,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 +788,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 +904,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 +957,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 a4cae06..32b8f08 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 5d277a9..262c440 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 c12a54e..923e7e1 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 4281a08..99b8ebe 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 89151ca..7665d68 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 2e4a775..50a5dc7 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 c7c0034..0b690ba 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 c088020..837bfb5 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 2f1c075..7a82b7d 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/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 00121ba..b0710d8 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -195,7 +195,7 @@ ok: static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i; /* If the DSP is already running then noop */ @@ -210,9 +210,9 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* If we've got user supplied MBC settings use them */ - if (pdata && pdata->num_mbc_cfgs) { + if (control->pdata.num_mbc_cfgs) { struct wm8958_mbc_cfg *cfg - = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + = &control->pdata.mbc_cfgs[wm8994->mbc_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1, @@ -239,7 +239,7 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i, ena; if (wm8994->mbc_vss) @@ -249,26 +249,26 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* If we've got user supplied settings use them */ - if (pdata && pdata->num_mbc_cfgs) { + if (control->pdata.num_mbc_cfgs) { struct wm8958_mbc_cfg *cfg - = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + = &control->pdata.mbc_cfgs[wm8994->mbc_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++) snd_soc_write(codec, i + 0x2800, cfg->combined_regs[i]); } - if (pdata && pdata->num_vss_cfgs) { + if (control->pdata.num_vss_cfgs) { struct wm8958_vss_cfg *cfg - = &pdata->vss_cfgs[wm8994->vss_cfg]; + = &control->pdata.vss_cfgs[wm8994->vss_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) snd_soc_write(codec, i + 0x2600, cfg->regs[i]); } - if (pdata && pdata->num_vss_hpf_cfgs) { + if (control->pdata.num_vss_hpf_cfgs) { struct wm8958_vss_hpf_cfg *cfg - = &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg]; + = &control->pdata.vss_hpf_cfgs[wm8994->vss_hpf_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) snd_soc_write(codec, i + 0x2400, cfg->regs[i]); @@ -300,7 +300,7 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i; wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false); @@ -309,9 +309,9 @@ static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* If we've got user supplied settings use them */ - if (pdata && pdata->num_enh_eq_cfgs) { + if (control->pdata.num_enh_eq_cfgs) { struct wm8958_enh_eq_cfg *cfg - = &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg]; + = &control->pdata.enh_eq_cfgs[wm8994->enh_eq_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) snd_soc_write(codec, i + 0x2200, @@ -458,7 +458,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -467,7 +467,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_mbc_cfgs) + if (value >= control->pdata.num_mbc_cfgs) return -EINVAL; wm8994->mbc_cfg = value; @@ -548,7 +548,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -557,7 +557,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_vss_cfgs) + if (value >= control->pdata.num_vss_cfgs) return -EINVAL; wm8994->vss_cfg = value; @@ -581,7 +581,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -590,7 +590,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_vss_hpf_cfgs) + if (value >= control->pdata.num_vss_hpf_cfgs) return -EINVAL; wm8994->vss_hpf_cfg = value; @@ -748,7 +748,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -757,7 +757,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_enh_eq_cfgs) + if (value >= control->pdata.num_enh_eq_cfgs) return -EINVAL; wm8994->enh_eq_cfg = value; @@ -883,13 +883,6 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) wm8994->mbc_vss = fw; mutex_unlock(&codec->mutex); } - - /* We can't have more than one request outstanding at once so - * we daisy chain. - */ - request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL, - codec, wm8958_enh_eq_loaded); } static void wm8958_mbc_loaded(const struct firmware *fw, void *context) @@ -897,25 +890,18 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) struct snd_soc_codec *codec = context; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0) - return; - - mutex_lock(&codec->mutex); - wm8994->mbc = fw; - mutex_unlock(&codec->mutex); - - /* We can't have more than one request outstanding at once so - * we daisy chain. - */ - request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL, - codec, wm8958_mbc_vss_loaded); + if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { + mutex_lock(&codec->mutex); + wm8994->mbc = fw; + mutex_unlock(&codec->mutex); + } } void wm8958_dsp2_init(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int ret, i; wm8994->dsp_active = -1; @@ -932,9 +918,12 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "wm8958_mbc.wfw", codec->dev, GFP_KERNEL, codec, wm8958_mbc_loaded); - - if (!pdata) - return; + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL, + codec, wm8958_mbc_vss_loaded); + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL, + codec, wm8958_enh_eq_loaded); if (pdata->num_mbc_cfgs) { struct snd_kcontrol_new control[] = { diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f0f6f660..cf09cb6 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 ce67200..8fd38cb4 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 5ce6477..70dd27e 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 4c0a8e4..8c1dac9 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; } diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 14f6663..7b3f409 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/wm8988.c b/sound/soc/codecs/wm8988.c index 1d4c5cf..715788d 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -882,7 +882,7 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) if (wm8988 == NULL) return -ENOMEM; - wm8988->regmap = regmap_init_spi(spi, &wm8988_regmap); + wm8988->regmap = devm_regmap_init_spi(spi, &wm8988_regmap); if (IS_ERR(wm8988->regmap)) { ret = PTR_ERR(wm8988->regmap); dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); @@ -893,17 +893,12 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8988, &wm8988_dai, 1); - if (ret != 0) - regmap_exit(wm8988->regmap); - return ret; } static int __devexit wm8988_spi_remove(struct spi_device *spi) { - struct wm8988_priv *wm8988 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8988->regmap); return 0; } @@ -931,7 +926,7 @@ static __devinit int wm8988_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8988); - wm8988->regmap = regmap_init_i2c(i2c, &wm8988_regmap); + wm8988->regmap = devm_regmap_init_i2c(i2c, &wm8988_regmap); if (IS_ERR(wm8988->regmap)) { ret = PTR_ERR(wm8988->regmap); dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); @@ -940,17 +935,12 @@ static __devinit int wm8988_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8988, &wm8988_dai, 1); - if (ret != 0) - regmap_exit(wm8988->regmap); - return ret; } static __devexit int wm8988_i2c_remove(struct i2c_client *client) { - struct wm8988_priv *wm8988 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8988->regmap); return 0; } diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 94737a3..347a359 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1660,7 +1660,7 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c, wm8993->dev = &i2c->dev; init_completion(&wm8993->fll_lock); - wm8993->regmap = regmap_init_i2c(i2c, &wm8993_regmap); + wm8993->regmap = devm_regmap_init_i2c(i2c, &wm8993_regmap); if (IS_ERR(wm8993->regmap)) { ret = PTR_ERR(wm8993->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -1672,18 +1672,18 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++) wm8993->supplies[i].supply = wm8993_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies), + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies), wm8993->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); - goto err; + return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; + return ret; } ret = regmap_read(wm8993->regmap, WM8993_SOFTWARE_RESET, ®); @@ -1742,10 +1742,6 @@ err_irq: free_irq(i2c->irq, wm8993); err_enable: regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); -err: - regmap_exit(wm8993->regmap); return ret; } @@ -1756,9 +1752,7 @@ static __devexit int wm8993_i2c_remove(struct i2c_client *i2c) snd_soc_unregister_codec(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm8993); - regmap_exit(wm8993->regmap); regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); - regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); return 0; } diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b2b2b37..302f69a 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -110,13 +110,13 @@ static const struct wm8958_micd_rate jackdet_rates[] = { static void wm8958_micd_set_rate(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; int best, i, sysclk, val; bool idle; const struct wm8958_micd_rate *rates; int num_rates; - if (!(wm8994->pdata && wm8994->pdata->micd_rates) && - wm8994->jack_cb != wm8958_default_micdet) + if (wm8994->jack_cb != wm8958_default_micdet) return; idle = !wm8994->jack_mic; @@ -127,9 +127,9 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec) else sysclk = wm8994->aifclk[0]; - if (wm8994->pdata && wm8994->pdata->micd_rates) { - rates = wm8994->pdata->micd_rates; - num_rates = wm8994->pdata->num_micd_rates; + if (control->pdata.micd_rates) { + rates = control->pdata.micd_rates; + num_rates = control->pdata.num_micd_rates; } else if (wm8994->jackdet) { rates = jackdet_rates; num_rates = ARRAY_SIZE(jackdet_rates); @@ -326,7 +326,8 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int base = wm8994_drc_base[drc]; int cfg = wm8994->drc_cfg[drc]; int save, i; @@ -362,7 +363,8 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int drc = wm8994_get_drc(kcontrol->id.name); int value = ucontrol->value.integer.value[0]; @@ -394,7 +396,8 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int base = wm8994_retune_mobile_base[block]; int iface, best, best_val, save, i, cfg; @@ -465,7 +468,8 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int block = wm8994_get_retune_mobile_block(kcontrol->id.name); int value = ucontrol->value.integer.value[0]; @@ -862,7 +866,7 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | WM8994_VMID_BUF_ENA | - (0x3 << WM8994_VMID_RAMP_SHIFT)); + (0x2 << WM8994_VMID_RAMP_SHIFT)); /* Main bias enable, VMID=2x40k */ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, @@ -870,7 +874,7 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_VMID_SEL_MASK, WM8994_BIAS_ENA | 0x2); - msleep(50); + msleep(300); snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_VMID_RAMP_MASK | @@ -939,16 +943,10 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_BIAS_SRC | WM8994_VMID_DISCH); - switch (wm8994->vmid_mode) { - case WM8994_VMID_FORCE: - msleep(350); - break; - default: - break; - } + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK, 0); - snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, - WM8994_VROI, WM8994_VROI); + msleep(400); /* Active discharge */ snd_soc_update_bits(codec, WM8994_ANTIPOP_1, @@ -957,17 +955,12 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_LINEOUT1_DISCH | WM8994_LINEOUT2_DISCH); - msleep(150); - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, WM8994_LINEOUT1N_ENA | WM8994_LINEOUT1P_ENA | WM8994_LINEOUT2N_ENA | WM8994_LINEOUT2P_ENA, 0); - snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, - WM8994_VROI, 0); - /* Switch off startup biases */ snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_BIAS_SRC | @@ -976,10 +969,7 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_VMID_RAMP_MASK, 0); snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, - WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); - - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, - WM8994_VMID_RAMP_MASK, 0); + WM8994_VMID_SEL_MASK, 0); } pm_runtime_put(codec->dev); @@ -2277,6 +2267,18 @@ out: configure_clock(codec); + /* + * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers + * for detection. + */ + if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) { + dev_dbg(codec->dev, "Configuring AIFs for 128fs\n"); + snd_soc_update_bits(codec, WM8994_AIF1_RATE, + WM8994_AIF1CLK_RATE_MASK, 0x1); + snd_soc_update_bits(codec, WM8994_AIF2_RATE, + WM8994_AIF2CLK_RATE_MASK, 0x1); + } + return 0; } @@ -2365,6 +2367,18 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, configure_clock(codec); + /* + * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers + * for detection. + */ + if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) { + dev_dbg(codec->dev, "Configuring AIFs for 128fs\n"); + snd_soc_update_bits(codec, WM8994_AIF1_RATE, + WM8994_AIF1CLK_RATE_MASK, 0x1); + snd_soc_update_bits(codec, WM8994_AIF2_RATE, + WM8994_AIF2CLK_RATE_MASK, 0x1); + } + return 0; } @@ -3082,7 +3096,8 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec) static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) { struct snd_soc_codec *codec = wm8994->hubs.codec; - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; struct snd_kcontrol_new controls[] = { SOC_ENUM_EXT("AIF1.1 EQ Mode", wm8994->retune_mobile_enum, @@ -3149,7 +3164,8 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) static void wm8994_handle_pdata(struct wm8994_priv *wm8994) { struct snd_soc_codec *codec = wm8994->hubs.codec; - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int ret, i; if (!pdata) @@ -3451,7 +3467,7 @@ static void wm8958_default_micdet(u16 status, void *data) mutex_unlock(&wm8994->accdet_lock); - if (wm8994->pdata->jd_ext_cap) + if (wm8994->wm8994->pdata.jd_ext_cap) snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); } @@ -3486,11 +3502,48 @@ static void wm8958_default_micdet(u16 status, void *data) } } +/* Deferred mic detection to allow for extra settling time */ +static void wm1811_mic_work(struct work_struct *work) +{ + struct wm8994_priv *wm8994 = container_of(work, struct wm8994_priv, + mic_work.work); + struct wm8994 *control = wm8994->wm8994; + struct snd_soc_codec *codec = wm8994->hubs.codec; + + pm_runtime_get_sync(codec->dev); + + /* If required for an external cap force MICBIAS on */ + if (control->pdata.jd_ext_cap) { + snd_soc_dapm_force_enable_pin(&codec->dapm, + "MICBIAS2"); + snd_soc_dapm_sync(&codec->dapm); + } + + mutex_lock(&wm8994->accdet_lock); + + dev_dbg(codec->dev, "Starting mic detection\n"); + + /* + * Start off measument of microphone impedence to find out + * what's actually there. + */ + wm8994->mic_detecting = true; + wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC); + + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, + WM8958_MICD_ENA, WM8958_MICD_ENA); + + mutex_unlock(&wm8994->accdet_lock); + + pm_runtime_put(codec->dev); +} + static irqreturn_t wm1811_jackdet_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; + struct wm8994 *control = wm8994->wm8994; struct snd_soc_codec *codec = wm8994->hubs.codec; - int reg; + int reg, delay; bool present; pm_runtime_get_sync(codec->dev); @@ -3521,18 +3574,14 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, WM1811_JACKDET_DB, 0); - /* - * Start off measument of microphone impedence to find - * out what's actually there. - */ - wm8994->mic_detecting = true; - wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC); - - snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, - WM8958_MICD_ENA, WM8958_MICD_ENA); + delay = control->pdata.micdet_delay; + schedule_delayed_work(&wm8994->mic_work, + msecs_to_jiffies(delay)); } else { dev_dbg(codec->dev, "Jack not detected\n"); + cancel_delayed_work_sync(&wm8994->mic_work); + snd_soc_update_bits(codec, WM8958_MICBIAS2, WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); @@ -3549,14 +3598,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) mutex_unlock(&wm8994->accdet_lock); - /* If required for an external cap force MICBIAS on */ - if (wm8994->pdata->jd_ext_cap) { - if (present) - snd_soc_dapm_force_enable_pin(&codec->dapm, - "MICBIAS2"); - else - snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); - } + /* Turn off MICBIAS if it was on for an external cap */ + if (control->pdata.jd_ext_cap && !present) + snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); if (present) snd_soc_jack_report(wm8994->micdet[0].jack, @@ -3633,8 +3677,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, wm8958_micd_set_rate(codec); /* Detect microphones and short circuits by default */ - if (wm8994->pdata->micd_lvl_sel) - micd_lvl_sel = wm8994->pdata->micd_lvl_sel; + if (control->pdata.micd_lvl_sel) + micd_lvl_sel = control->pdata.micd_lvl_sel; else micd_lvl_sel = 0x41; @@ -3779,15 +3823,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); mutex_init(&wm8994->accdet_lock); - INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, wm1811_jackdet_bootstrap); + switch (control->type) { + case WM8994: + INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); + break; + case WM1811: + INIT_DELAYED_WORK(&wm8994->mic_work, wm1811_mic_work); + break; + default: + break; + } + for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) init_completion(&wm8994->fll_locked[i]); - if (wm8994->pdata && wm8994->pdata->micdet_irq) - wm8994->micdet_irq = wm8994->pdata->micdet_irq; + wm8994->micdet_irq = control->pdata.micdet_irq; pm_runtime_enable(codec->dev); pm_runtime_idle(codec->dev); @@ -3800,8 +3853,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) switch (control->type) { case WM8994: /* Single ended line outputs should have VMID on. */ - if (!wm8994->pdata->lineout1_diff || - !wm8994->pdata->lineout2_diff) + if (!control->pdata.lineout1_diff || + !control->pdata.lineout2_diff) codec->dapm.idle_bias_off = 0; switch (wm8994->revision) { @@ -3839,20 +3892,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.no_cache_dac_hp_direct = true; wm8994->fll_byp = true; - switch (control->cust_id) { - case 0: - case 2: - wm8994->hubs.dcs_codes_l = -9; - wm8994->hubs.dcs_codes_r = -7; - break; - case 1: - case 3: - wm8994->hubs.dcs_codes_l = -8; - wm8994->hubs.dcs_codes_r = -7; - break; - default: - break; - } + wm8994->hubs.dcs_codes_l = -9; + wm8994->hubs.dcs_codes_r = -7; snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1, WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN); @@ -4236,7 +4277,6 @@ static int __devinit wm8994_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm8994); wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); - wm8994->pdata = dev_get_platdata(pdev->dev.parent); return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, wm8994_dai, ARRAY_SIZE(wm8994_dai)); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index ccbce57..3120c0f 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -143,7 +143,6 @@ struct wm8994_priv { int micdet_irq; int revision; - struct wm8994_pdata *pdata; unsigned int aif1clk_enable:1; unsigned int aif2clk_enable:1; diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 28c89b0..f1a7cf1 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2261,41 +2261,28 @@ static int __devinit wm8995_spi_probe(struct spi_device *spi) struct wm8995_priv *wm8995; int ret; - wm8995 = kzalloc(sizeof *wm8995, GFP_KERNEL); + wm8995 = devm_kzalloc(&spi->dev, sizeof(*wm8995), GFP_KERNEL); if (!wm8995) return -ENOMEM; spi_set_drvdata(spi, wm8995); - wm8995->regmap = regmap_init_spi(spi, &wm8995_regmap); + wm8995->regmap = devm_regmap_init_spi(spi, &wm8995_regmap); if (IS_ERR(wm8995->regmap)) { ret = PTR_ERR(wm8995->regmap); dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); - goto err_alloc; + return ret; } ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8995, wm8995_dai, ARRAY_SIZE(wm8995_dai)); - if (ret < 0) - goto err_regmap; - - return ret; - -err_regmap: - regmap_exit(wm8995->regmap); -err_alloc: - kfree(wm8995); - return ret; } static int __devexit wm8995_spi_remove(struct spi_device *spi) { - struct wm8995_priv *wm8995 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8995->regmap); - kfree(wm8995); return 0; } @@ -2316,44 +2303,31 @@ static __devinit int wm8995_i2c_probe(struct i2c_client *i2c, struct wm8995_priv *wm8995; int ret; - wm8995 = kzalloc(sizeof *wm8995, GFP_KERNEL); + wm8995 = devm_kzalloc(&i2c->dev, sizeof(*wm8995), GFP_KERNEL); if (!wm8995) return -ENOMEM; i2c_set_clientdata(i2c, wm8995); - wm8995->regmap = regmap_init_i2c(i2c, &wm8995_regmap); + wm8995->regmap = devm_regmap_init_i2c(i2c, &wm8995_regmap); if (IS_ERR(wm8995->regmap)) { ret = PTR_ERR(wm8995->regmap); dev_err(&i2c->dev, "Failed to register regmap: %d\n", ret); - goto err_alloc; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8995, wm8995_dai, ARRAY_SIZE(wm8995_dai)); - 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(wm8995->regmap); -err_alloc: - kfree(wm8995); return ret; } static __devexit int wm8995_i2c_remove(struct i2c_client *client) { - struct wm8995_priv *wm8995 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8995->regmap); - kfree(wm8995); return 0; } diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c new file mode 100644 index 0000000..7fdb68e --- /dev/null +++ b/sound/soc/codecs/wm_adsp.c @@ -0,0 +1,666 @@ +/* + * 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: + 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; + + 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 0000000..ffd29a4 --- /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 0000000..5632ded --- /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 6fac5af..d55e647 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 714e51e..5715595 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,6 +574,50 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } +static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) +{ + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); + + 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 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; + + default: + return -EINVAL; + } + + return 0; +} + +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); + + 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 channel_size) { @@ -709,8 +773,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 +782,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 +794,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); } } @@ -809,6 +865,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, word_length = DAVINCI_AUDIO_WORD_16; break; + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + dma_params->data_type = 3; + word_length = DAVINCI_AUDIO_WORD_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; @@ -880,13 +944,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) @@ -1098,6 +1167,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 +1185,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 0de9ed6..156f15f 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -23,7 +23,7 @@ #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 diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 93ea3bf..afab81f 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 fc4d01c..b6ef703 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 4563b28..3b98159 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 5f3cf3f..afd3479 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 93dc360b..d5cd9ef 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 199408e..3d9b1c4 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 0000000..897e32f --- /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 4b63ec8..4d26192 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 2ba0814..58d5a96 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, diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 1d5db48..d3629d5 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -99,6 +99,29 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate) } 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; } @@ -205,20 +242,18 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + /* 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 */ - ctl &= ~KIRKWOOD_PLAYCTL_BURST_MASK; - ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE - | KIRKWOOD_PLAYCTL_SPDIF_EN); - - if (priv->burst == 32) - ctl |= KIRKWOOD_PLAYCTL_BURST_32; - else - ctl |= KIRKWOOD_PLAYCTL_BURST_128; - ctl |= KIRKWOOD_PLAYCTL_I2S_EN; + /* enable playback */ writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; @@ -259,30 +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: + /* 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 f9084d8..4d92637 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 c294fbb..b304e37 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 afb8d4f..a9a2438 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 49a6725..a89791c 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 a57a4e6..1d6ea86 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 a6ee157..0916760 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/samsung/ac97.c b/sound/soc/samsung/ac97.c index 14fbcd3..386bab1 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"); @@ -468,7 +468,7 @@ 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); @@ -488,7 +488,7 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev) 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 a2ca156..59ffd6c 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-audio", + .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 = "wm5102-aif1", + .codec_dai_name = "wm0010-sdi1", .platform_name = "samsung-audio", + .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", .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", @@ -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 = "wm5110-aif1", + .codec_dai_name = "wm0010-sdi1", .platform_name = "samsung-audio", + .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", .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", @@ -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/i2s.c b/sound/soc/samsung/i2s.c index 40b00a1..aaf57b7 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); @@ -1067,7 +1069,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 +1089,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; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index c860819..45f4a75 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; @@ -592,14 +592,14 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) return 0; 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; @@ -619,8 +619,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/spdif.c b/sound/soc/samsung/spdif.c index bc24c7a..5f3b06d 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, @@ -444,10 +444,10 @@ err4: 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; @@ -466,9 +466,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/sh/fsi.c b/sound/soc/sh/fsi.c index 9d7f307..a606d0f 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 9d56f02..e72f554 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 10d21be..9c768bc 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 6e35bca..1e36bc8 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 bbc1257..111b7d92 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 1ab5fe0..0bb5cccd 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 ef22d0b..5c3ca2a 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 bf99296..4965337 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 0832e8a..2ae8af8 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 3ebc867..d9641ef 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 bf56101..2269170 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 4418422..bf0e089 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 76cb1b3..523795a 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 ea9166d..effe5b4 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 cee13b7..0f79412 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 e69a4f7..4a255a4 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 54f7e25..651a52a 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 be94bf9..478b4b6 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 98202a3..9c778d9 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 1a04e24..894c9f4 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 77ed44d..76d3444 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 |