mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-25 19:14:39 +08:00
sound updates for 4.17-rc1
This became a large update. The changes are scattered widely, and majority of them are attributed to ASoC componentization. The gitk output made me dizzy, but it's slightly better than London tube. OK, below are some highlights: - Continued hardening works in ALSA PCM core; most of the existing syzkaller reports should have been covered. - USB-audio got the initial USB Audio Class 3 support, as well as UAC2 jack detection support and more DSD-device support. - ASoC componentization: finally each individual driver was converted to components framework, which is more future-proof for further works. Most of conversations were systematic. - Lots of fixes for Intel Baytrail / Cherrytrail devices with Realtek codecs, typically tablets and small PCs. - Fixes / cleanups for Samsung Odroid systems - Cleanups in Freescale SSI driver - New ASoC drivers: * AKM AK4458 and AK5558 codecs * A few AMD based machine drivers * Intel Kabylake machine drivers * Maxim MAX9759 codec * Motorola CPCAP codec * Socionext Uniphier SoCs * TI PCM1789 and TDA7419 codecs - Retirement of Blackfin drivers along with architecture removal. -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAlrF2gUOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE/ZLhAAvUgpOkpHRmvyXoqhWdG/FWWFWtoFrQaDZE5y NPcGHy/ZLuCXGL3Zpsm9lZqXd1sxRdsxF3hiWT0JqqC7oxs/oSOhSzf7w6P9ppW7 nxZKo4SCSQpmy0Y58QhwpXUkuGzRAOXcug39BNiAqxjtWPPNT8bUj/br3ApH9+90 Dtittl26Z1Eek1KwNJDMdJt8l5P4P5Ls44g/9Xwhgxk/P0nHmErNuUftlNc/65/b HdVgLSXVJbfJ9dLRjQC0yg7jPzSgSp5xssAkWGfPv8AMnM6ql7LWGO+6zOdVcOUo 0ipKJpZHUI/k1Uv4yBxI32GueOl/gH78M3iGv1CVe/jaC8g8XXA5GScnG41U1ZUO p9f78q8jk+O4uCDvbCvigw+iqb7Lm7ME0jNaQ6gZzZX2sDDBUBIYMS6W658pQfgT w00c73gm7J+MPv4FsVyyzZsmqyO/xE/1x9F2eGut67DbCKVcfQnyheYJq3Gt96qo tzvJ+cy3JxCfGn7Ngl2/i8jtHD6sGf1Pl3gOPk5DEN2qfuBy/vQ4W4TlJ1pOqGFG JjpUhEpvYhP/XPrFo970g2yYQq5VsjumQiHGxbD56qu4hrkPU3w92gYKNc0F689j QQRc8gyAvUp78ZletF4WYLf6H1yNmkP3ufhsuP1MQWuxRmTcxVtIRDU1PLAq5J8w 10mGs6s= =F3q1 -----END PGP SIGNATURE----- Merge tag 'sound-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "This became a large update. The changes are scattered widely, and the majority of them are attributed to ASoC componentization. The gitk output made me dizzy, but it's slightly better than London tube. OK, below are some highlights: - Continued hardening works in ALSA PCM core; most of the existing syzkaller reports should have been covered. - USB-audio got the initial USB Audio Class 3 support, as well as UAC2 jack detection support and more DSD-device support. - ASoC componentization: finally each individual driver was converted to components framework, which is more future-proof for further works. Most of conversations were systematic. - Lots of fixes for Intel Baytrail / Cherrytrail devices with Realtek codecs, typically tablets and small PCs. - Fixes / cleanups for Samsung Odroid systems - Cleanups in Freescale SSI driver - New ASoC drivers: * AKM AK4458 and AK5558 codecs * A few AMD based machine drivers * Intel Kabylake machine drivers * Maxim MAX9759 codec * Motorola CPCAP codec * Socionext Uniphier SoCs * TI PCM1789 and TDA7419 codecs - Retirement of Blackfin drivers along with architecture removal" * tag 'sound-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (497 commits) ALSA: pcm: Fix UAF at PCM release via PCM timer access ALSA: usb-audio: silence a static checker warning ASoC: tscs42xx: Remove owner assignment from i2c_driver ASoC: mediatek: remove "simple-mfd" in the example ASoC: cpcap: replace codec to component ASoC: Intel: bytcr_rt5651: don't use codec anymore ASoC: amd: don't use codec anymore ALSA: usb-audio: fix memory leak on cval ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls ASoC: topology: Fix kcontrol name string handling ALSA: aloop: Mark paused device as inactive ALSA: usb-audio: update clock valid control ALSA: usb-audio: UAC2 jack detection ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams ALSA: pcm: Avoid potential races between OSS ioctls and read/write ALSA: usb-audio: Integrate native DSD support for ITF-USB based DACs. ALSA: usb-audio: FIX native DSD support for TEAC UD-501 DAC ALSA: usb-audio: Add native DSD support for Luxman DA-06 ALSA: usb-audio: fix uac control query argument ASoC: nau8824: recover system clock when device changes ...
This commit is contained in:
commit
e02d37bf55
23
Documentation/devicetree/bindings/sound/ak4458.txt
Normal file
23
Documentation/devicetree/bindings/sound/ak4458.txt
Normal file
@ -0,0 +1,23 @@
|
||||
AK4458 audio DAC
|
||||
|
||||
This device supports I2C mode.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "asahi-kasei,ak4458"
|
||||
- reg : The I2C address of the device for I2C
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: A GPIO specifier for the power down & reset pin
|
||||
- mute-gpios: A GPIO specifier for the soft mute pin
|
||||
|
||||
Example:
|
||||
|
||||
&i2c {
|
||||
ak4458: dac@10 {
|
||||
compatible = "asahi-kasei,ak4458";
|
||||
reg = <0x10>;
|
||||
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>
|
||||
mute-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>
|
||||
};
|
||||
};
|
22
Documentation/devicetree/bindings/sound/ak5558.txt
Normal file
22
Documentation/devicetree/bindings/sound/ak5558.txt
Normal file
@ -0,0 +1,22 @@
|
||||
AK5558 8 channel differential 32-bit delta-sigma ADC
|
||||
|
||||
This device supports I2C mode only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "asahi-kasei,ak5558"
|
||||
- reg : The I2C address of the device.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios: A GPIO specifier for the power down & reset pin.
|
||||
|
||||
Example:
|
||||
|
||||
&i2c {
|
||||
ak5558: adc@10 {
|
||||
compatible = "asahi-kasei,ak5558";
|
||||
reg = <0x10>;
|
||||
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
@ -25,6 +25,9 @@ Optional properties:
|
||||
interrupt is to be used to wake system, otherwise "irq" should be used.
|
||||
- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
|
||||
|
||||
- #clock-cells : Should be set to '<0>', only one clock source provided;
|
||||
- clock-output-names : Name given for DAI clocks output;
|
||||
|
||||
- clocks : phandle and clock specifier for codec MCLK.
|
||||
- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
|
||||
|
||||
@ -83,6 +86,9 @@ Example:
|
||||
VDDMIC-supply = <®_audio>;
|
||||
VDDIO-supply = <®_audio>;
|
||||
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "dai-clks";
|
||||
|
||||
clocks = <&clks 201>;
|
||||
clock-names = "mclk";
|
||||
|
||||
|
@ -8,6 +8,7 @@ Required properties:
|
||||
Optional properties:
|
||||
- dmicen-gpios: GPIO specifier for dmic to control start and stop
|
||||
- num-channels: Number of microphones on this DAI
|
||||
- wakeup-delay-ms: Delay (in ms) after enabling the DMIC
|
||||
|
||||
Example node:
|
||||
|
||||
@ -15,4 +16,5 @@ Example node:
|
||||
compatible = "dmic-codec";
|
||||
dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
|
||||
num-channels = <1>;
|
||||
wakeup-delay-ms <50>;
|
||||
};
|
||||
|
@ -28,7 +28,6 @@ The compatible list for this generic sound card currently:
|
||||
(compatible with CS4271 and CS4272)
|
||||
|
||||
"fsl,imx-audio-wm8962"
|
||||
(compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt)
|
||||
|
||||
"fsl,imx-audio-sgtl5000"
|
||||
(compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt)
|
||||
|
@ -1,53 +0,0 @@
|
||||
Freescale i.MX audio complex with WM8962 codec
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "fsl,imx-audio-wm8962"
|
||||
|
||||
- model : The user-visible name of this sound complex
|
||||
|
||||
- ssi-controller : The phandle of the i.MX SSI controller
|
||||
|
||||
- audio-codec : The phandle of the WM8962 audio codec
|
||||
|
||||
- audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the
|
||||
connection's sink, the second being the connection's
|
||||
source. Valid names could be power supplies, WM8962
|
||||
pins, and the jacks on the board:
|
||||
|
||||
Power supplies:
|
||||
* Mic Bias
|
||||
|
||||
Board connectors:
|
||||
* Mic Jack
|
||||
* Headphone Jack
|
||||
* Ext Spk
|
||||
|
||||
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
|
||||
|
||||
- mux-ext-port : The external port of the i.MX audio muxer
|
||||
|
||||
Note: The AUDMUX port numbering should start at 1, which is consistent with
|
||||
hardware manual.
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "fsl,imx6q-sabresd-wm8962",
|
||||
"fsl,imx-audio-wm8962";
|
||||
model = "wm8962-audio";
|
||||
ssi-controller = <&ssi2>;
|
||||
audio-codec = <&codec>;
|
||||
audio-routing =
|
||||
"Headphone Jack", "HPOUTL",
|
||||
"Headphone Jack", "HPOUTR",
|
||||
"Ext Spk", "SPKOUTL",
|
||||
"Ext Spk", "SPKOUTR",
|
||||
"MICBIAS", "AMIC",
|
||||
"IN3R", "MICBIAS",
|
||||
"DMIC", "MICBIAS",
|
||||
"DMICDAT", "DMIC";
|
||||
mux-int-port = <2>;
|
||||
mux-ext-port = <3>;
|
||||
};
|
@ -16,6 +16,8 @@ Optional properties:
|
||||
|
||||
- clock-names: Should be "mclk"
|
||||
|
||||
- #sound-dai-cells : should be 0.
|
||||
|
||||
- maxim,dmic-freq: Frequency at which to clock DMIC
|
||||
|
||||
- maxim,micbias: Micbias voltage applies to the analog mic, valid voltages value are:
|
||||
|
18
Documentation/devicetree/bindings/sound/maxim,max9759.txt
Normal file
18
Documentation/devicetree/bindings/sound/maxim,max9759.txt
Normal file
@ -0,0 +1,18 @@
|
||||
Maxim MAX9759 Speaker Amplifier
|
||||
===============================
|
||||
|
||||
Required properties:
|
||||
- compatible : "maxim,max9759"
|
||||
- shutdown-gpios : the gpio connected to the shutdown pin
|
||||
- mute-gpios : the gpio connected to the mute pin
|
||||
- gain-gpios : the 2 gpios connected to the g1 and g2 pins
|
||||
|
||||
Example:
|
||||
|
||||
max9759: analog-amplifier {
|
||||
compatible = "maxim,max9759";
|
||||
shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
|
||||
mute-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
|
||||
gain-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>,
|
||||
<&gpio3 25 GPIO_ACTIVE_LOW>;
|
||||
};
|
@ -53,7 +53,7 @@ See ../arm/mediatek/mediatek,audsys.txt for details about the parent node.
|
||||
Example:
|
||||
|
||||
audsys: audio-subsystem@11220000 {
|
||||
compatible = "mediatek,mt2701-audsys", "syscon", "simple-mfd";
|
||||
compatible = "mediatek,mt2701-audsys", "syscon";
|
||||
...
|
||||
|
||||
afe: audio-controller {
|
||||
|
22
Documentation/devicetree/bindings/sound/pcm1789.txt
Normal file
22
Documentation/devicetree/bindings/sound/pcm1789.txt
Normal file
@ -0,0 +1,22 @@
|
||||
Texas Instruments pcm1789 DT bindings
|
||||
|
||||
PCM1789 is a simple audio codec that can be connected via
|
||||
I2C or SPI. Currently, only I2C bus is supported.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,pcm1789"
|
||||
|
||||
Required properties on I2C:
|
||||
|
||||
- reg: the I2C address
|
||||
- reset-gpios: GPIO to control the RESET pin
|
||||
|
||||
Examples:
|
||||
|
||||
audio-codec@4c {
|
||||
compatible = "ti,pcm1789";
|
||||
reg = <0x4c>;
|
||||
reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
@ -351,6 +351,7 @@ Required properties:
|
||||
- "renesas,rcar_sound-r8a7793" (R-Car M2-N)
|
||||
- "renesas,rcar_sound-r8a7794" (R-Car E2)
|
||||
- "renesas,rcar_sound-r8a7795" (R-Car H3)
|
||||
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
|
||||
- reg : Should contain the register physical address.
|
||||
required register is
|
||||
SRU/ADG/SSI if generation1
|
||||
|
@ -22,7 +22,7 @@ Optionnal properties:
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "rockchip,rockchip-audio-es8388";
|
||||
compatible = "rockchip,rk3288-hdmi-analog";
|
||||
rockchip,model = "Analog audio output";
|
||||
rockchip,i2s-controller = <&i2s>;
|
||||
rockchip,audio-codec = <&es8388>;
|
||||
|
29
Documentation/devicetree/bindings/sound/rohm,bd28623.txt
Normal file
29
Documentation/devicetree/bindings/sound/rohm,bd28623.txt
Normal file
@ -0,0 +1,29 @@
|
||||
ROHM BD28623MUV Class D speaker amplifier for digital input
|
||||
|
||||
This codec does not have any control buses such as I2C, it detect format and
|
||||
rate of I2S signal automatically. It has two signals that can be connected
|
||||
to GPIOs: reset and mute.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "rohm,bd28623"
|
||||
- #sound-dai-cells: should be 0.
|
||||
- VCCA-supply : regulator phandle for the VCCA supply
|
||||
- VCCP1-supply : regulator phandle for the VCCP1 supply
|
||||
- VCCP2-supply : regulator phandle for the VCCP2 supply
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios : GPIO specifier for the active low reset line
|
||||
- mute-gpios : GPIO specifier for the active low mute line
|
||||
|
||||
Example:
|
||||
|
||||
codec {
|
||||
compatible = "rohm,bd28623";
|
||||
#sound-dai-cells = <0>;
|
||||
|
||||
VCCA-supply = <&vcc_reg>;
|
||||
VCCP1-supply = <&vcc_reg>;
|
||||
VCCP2-supply = <&vcc_reg>;
|
||||
reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>;
|
||||
mute-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
|
||||
};
|
@ -16,6 +16,23 @@ Optional properties:
|
||||
- realtek,dmic-en
|
||||
Boolean. true if dmic is used.
|
||||
|
||||
- realtek,jack-detect-source
|
||||
u32. Valid values:
|
||||
1: Use JD1_1 pin for jack-detect
|
||||
2: Use JD1_2 pin for jack-detect
|
||||
3: Use JD2 pin for jack-detect
|
||||
|
||||
- realtek,over-current-threshold-microamp
|
||||
u32, micbias over-current detection threshold in µA, valid values are
|
||||
600, 1500 and 2000µA.
|
||||
|
||||
- realtek,over-current-scale-factor
|
||||
u32, micbias over-current detection scale-factor, valid values are:
|
||||
0: Scale current by 0.5
|
||||
1: Scale current by 0.75
|
||||
2: Scale current by 1.0
|
||||
3: Scale current by 1.5
|
||||
|
||||
Pins on the device (for linking into audio routes) for RT5651:
|
||||
|
||||
* DMIC L1
|
||||
|
@ -1,10 +1,10 @@
|
||||
RT5665/RT5666/RT5668 audio CODEC
|
||||
RT5665/RT5666 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : One of "realtek,rt5665", "realtek,rt5666" or "realtek,rt5668".
|
||||
- compatible : One of "realtek,rt5665", "realtek,rt5666".
|
||||
|
||||
- reg : The I2C address of the device.
|
||||
|
||||
|
@ -2,8 +2,10 @@ Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board,
|
||||
"samsung,odroidxu4-audio" - for Odroid XU4 board
|
||||
- compatible - "hardkernel,odroid-xu3-audio" - for Odroid XU3 board,
|
||||
"hardkernel,odroid-xu4-audio" - for Odroid XU4 board (deprecated),
|
||||
"samsung,odroid-xu3-audio" - for Odroid XU3 board (deprecated),
|
||||
"samsung,odroid-xu4-audio" - for Odroid XU4 board (deprecated)
|
||||
- model - the user-visible name of this sound complex
|
||||
- clocks - should contain entries matching clock names in the clock-names
|
||||
property
|
||||
@ -35,7 +37,7 @@ Required sub-nodes:
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "samsung,odroidxu3-audio";
|
||||
compatible = "hardkernel,odroid-xu3-audio";
|
||||
model = "Odroid-XU3";
|
||||
samsung,audio-routing =
|
||||
"Headphone Jack", "HPL",
|
||||
|
@ -4,9 +4,13 @@ Required properties:
|
||||
|
||||
- compatible : "samsung,tm2-audio"
|
||||
- model : the user-visible name of this sound complex
|
||||
- audio-codec : the phandle of the wm5110 audio codec node,
|
||||
as described in ../mfd/arizona.txt
|
||||
- i2s-controller : the phandle of the I2S controller
|
||||
- audio-codec : the first entry should be phandle of the wm5110 audio
|
||||
codec node, as described in ../mfd/arizona.txt;
|
||||
the second entry should be phandle of the HDMI
|
||||
transmitter node
|
||||
- i2s-controller : the list of phandle and argument tuples pointing to
|
||||
I2S controllers, the first entry should be I2S0 and
|
||||
the second one I2S1
|
||||
- audio-amplifier : the phandle of the MAX98504 amplifier
|
||||
- samsung,audio-routing : a list of the connections between audio components;
|
||||
each entry is a pair of strings, the first being the
|
||||
@ -22,8 +26,8 @@ Example:
|
||||
|
||||
sound {
|
||||
compatible = "samsung,tm2-audio";
|
||||
audio-codec = <&wm5110>;
|
||||
i2s-controller = <&i2s0>;
|
||||
audio-codec = <&wm5110>, <&hdmi>;
|
||||
i2s-controller = <&i2s0 0>, <&i2s1 0>;
|
||||
audio-amplifier = <&max98504>;
|
||||
mic-bias-gpios = <&gpr3 2 0>;
|
||||
model = "wm5110";
|
||||
|
@ -7,7 +7,7 @@ Required SoC Specific Properties:
|
||||
- samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
|
||||
secondary fifo, s/w reset control and internal mux for root clk src.
|
||||
- samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
|
||||
playback, sterio channel capture, secondary fifo using internal
|
||||
playback, stereo channel capture, secondary fifo using internal
|
||||
or external dma, s/w reset control, internal mux for root clk src
|
||||
and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
|
||||
is to allow transfer of multiple channel audio data on single data line.
|
||||
@ -25,7 +25,7 @@ Required SoC Specific Properties:
|
||||
These strings correspond 1:1 with the ordered pairs in dmas.
|
||||
- clocks: Handle to iis clock and RCLK source clk.
|
||||
- clock-names:
|
||||
i2s0 uses some base clks from CMU and some are from audio subsystem internal
|
||||
i2s0 uses some base clocks from CMU and some are from audio subsystem internal
|
||||
clock controller. The clock names for i2s0 should be "iis", "i2s_opclk0" and
|
||||
"i2s_opclk1" as shown in the example below.
|
||||
i2s1 and i2s2 uses clocks from CMU. The clock names for i2s1 and i2s2 should
|
||||
@ -36,9 +36,9 @@ Required SoC Specific Properties:
|
||||
- #clock-cells: should be 1, this property must be present if the I2S device
|
||||
is a clock provider in terms of the common clock bindings, described in
|
||||
../clock/clock-bindings.txt.
|
||||
- clock-output-names: from the common clock bindings, names of the CDCLK
|
||||
I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
|
||||
"i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
|
||||
- clock-output-names (deprecated): from the common clock bindings, names of
|
||||
the CDCLK I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
|
||||
"i2s_cdclk3" for the I2S0, I2S1, I2S2 devices respectively.
|
||||
|
||||
There are following clocks available at the I2S device nodes:
|
||||
CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock,
|
||||
@ -49,9 +49,10 @@ There are following clocks available at the I2S device nodes:
|
||||
|
||||
Refer to the SoC datasheet for availability of the above clocks.
|
||||
The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
|
||||
in the IIS Multi Audio Interface (I2S0).
|
||||
Note: Old DTs may not have the #clock-cells, clock-output-names properties
|
||||
and then not use the I2S node as a clock supplier.
|
||||
in the IIS Multi Audio Interface.
|
||||
|
||||
Note: Old DTs may not have the #clock-cells property and then not use the I2S
|
||||
node as a clock supplier.
|
||||
|
||||
Optional SoC Specific Properties:
|
||||
|
||||
@ -59,6 +60,7 @@ Optional SoC Specific Properties:
|
||||
sub system(used in secondary sound source).
|
||||
- pinctrl-0: Should specify pin control groups used for this controller.
|
||||
- pinctrl-names: Should contain only one value - "default".
|
||||
- #sound-dai-cells: should be 1.
|
||||
|
||||
|
||||
Example:
|
||||
@ -74,9 +76,9 @@ i2s0: i2s@3830000 {
|
||||
<&clock_audss EXYNOS_I2S_BUS>,
|
||||
<&clock_audss EXYNOS_SCLK_I2S>;
|
||||
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
|
||||
#clock-cells;
|
||||
clock-output-names = "i2s_cdclk0";
|
||||
#clock-cells = <1>;
|
||||
samsung,idma-addr = <0x03000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s0_bus>;
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
@ -5,6 +5,8 @@ Required properties:
|
||||
|
||||
- reg : the I2C address of the device
|
||||
|
||||
- #sound-dai-cells: must be equal to 0
|
||||
|
||||
- clocks : the clock provider of SYS_MCLK
|
||||
|
||||
- VDDA-supply : the regulator provider of VDDA
|
||||
@ -40,6 +42,7 @@ Example:
|
||||
codec: sgtl5000@a {
|
||||
compatible = "fsl,sgtl5000";
|
||||
reg = <0x0a>;
|
||||
#sound-dai-cells = <0>;
|
||||
clocks = <&clks 150>;
|
||||
micbias-resistor-k-ohms = <2>;
|
||||
micbias-voltage-m-volts = <2250>;
|
||||
|
@ -5,8 +5,17 @@ Required properties:
|
||||
"google,snow-audio-max98090" or
|
||||
"google,snow-audio-max98091" or
|
||||
"google,snow-audio-max98095"
|
||||
- samsung,i2s-controller: The phandle of the Samsung I2S controller
|
||||
- samsung,audio-codec: The phandle of the audio codec
|
||||
- samsung,i2s-controller (deprecated): The phandle of the Samsung I2S controller
|
||||
- samsung,audio-codec (deprecated): The phandle of the audio codec
|
||||
|
||||
Required sub-nodes:
|
||||
|
||||
- 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
|
||||
controller
|
||||
- 'codec' subnode with a 'sound-dai' property containing list of phandles
|
||||
to the CODEC nodes, first entry must be the phandle of the MAX98090,
|
||||
MAX98091 or MAX98095 CODEC (exact device type is indicated by the compatible
|
||||
string) and the second entry must be the phandle of the HDMI IP block node
|
||||
|
||||
Optional:
|
||||
- samsung,model: The name of the sound-card
|
||||
|
@ -45,6 +45,12 @@ SAI subnodes Optional properties:
|
||||
This property sets SAI sub-block as slave of another SAI sub-block.
|
||||
Must contain the phandle and index of the sai sub-block providing
|
||||
the synchronization.
|
||||
- st,iec60958: support S/PDIF IEC6958 protocol for playback
|
||||
IEC60958 protocol is not available for capture.
|
||||
By default, custom protocol is assumed, meaning that protocol is
|
||||
configured according to protocol defined in related DAI link node,
|
||||
such as i2s, left justified, right justified, dsp and pdm protocols.
|
||||
Note: ac97 protocol is not supported by SAI driver
|
||||
|
||||
The device node should contain one 'port' child node with one child 'endpoint'
|
||||
node, according to the bindings defined in Documentation/devicetree/bindings/
|
||||
|
38
Documentation/devicetree/bindings/sound/tda7419.txt
Normal file
38
Documentation/devicetree/bindings/sound/tda7419.txt
Normal file
@ -0,0 +1,38 @@
|
||||
TDA7419 audio processor
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "st,tda7419"
|
||||
- reg : the I2C address of the device.
|
||||
- vdd-supply : a regulator spec for the common power supply (8-10V)
|
||||
|
||||
Optional properties:
|
||||
|
||||
- st,mute-gpios : a GPIO spec for the MUTE pin.
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* SE3L
|
||||
* SE3R
|
||||
* SE2L
|
||||
* SE2R
|
||||
* SE1L
|
||||
* SE1R
|
||||
* DIFFL
|
||||
* DIFFR
|
||||
* MIX
|
||||
* OUTLF
|
||||
* OUTRF
|
||||
* OUTLR
|
||||
* OUTRR
|
||||
* OUTSW
|
||||
|
||||
Example:
|
||||
|
||||
ap: tda7419@44 {
|
||||
compatible = "st,tda7419";
|
||||
reg = <0x44>;
|
||||
vdd-supply = <&vdd_9v0_reg>;
|
||||
};
|
45
Documentation/devicetree/bindings/sound/uniphier,aio.txt
Normal file
45
Documentation/devicetree/bindings/sound/uniphier,aio.txt
Normal file
@ -0,0 +1,45 @@
|
||||
Socionext UniPhier SoC audio driver
|
||||
|
||||
The Socionext UniPhier audio subsystem consists of I2S and S/PDIF blocks in
|
||||
the same register space.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one of the following:
|
||||
"socionext,uniphier-ld11-aio"
|
||||
"socionext,uniphier-ld20-aio"
|
||||
"socionext,uniphier-pxs2-aio"
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : should contain I2S or S/PDIF interrupt.
|
||||
- pinctrl-names : should be "default".
|
||||
- pinctrl-0 : defined I2S signal pins for an external codec chip.
|
||||
- clock-names : should include following entries:
|
||||
"aio"
|
||||
- clocks : a list of phandle, should contain an entry for each
|
||||
entry in clock-names.
|
||||
- reset-names : should include following entries:
|
||||
"aio"
|
||||
- resets : a list of phandle, should contain an entry for each
|
||||
entry in reset-names.
|
||||
- #sound-dai-cells: should be 1.
|
||||
|
||||
Optional properties:
|
||||
- socionext,syscon: a phandle, should contain soc-glue.
|
||||
The soc-glue is used for changing mode of S/PDIF signal pin
|
||||
to Output from Hi-Z. This property is optional if you use
|
||||
I2S signal pins only.
|
||||
|
||||
Example:
|
||||
audio {
|
||||
compatible = "socionext,uniphier-ld20-aio";
|
||||
reg = <0x56000000 0x80000>;
|
||||
interrupts = <0 144 4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_aout>;
|
||||
clock-names = "aio";
|
||||
clocks = <&sys_clk 40>;
|
||||
reset-names = "aio";
|
||||
resets = <&sys_rst 40>;
|
||||
#sound-dai-cells = <1>;
|
||||
|
||||
socionext,syscon = <&sg>;
|
||||
};
|
@ -10,7 +10,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8524@0 {
|
||||
codec: wm8524 {
|
||||
compatible = "wlf,wm8524";
|
||||
wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
@ -843,13 +843,6 @@ F: sound/soc/codecs/ad7*
|
||||
F: sound/soc/codecs/ssm*
|
||||
F: sound/soc/codecs/sigmadsp.*
|
||||
|
||||
ANALOG DEVICES INC ASOC DRIVERS
|
||||
L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
W: http://blackfin.uclinux.org/
|
||||
S: Supported
|
||||
F: sound/soc/blackfin/*
|
||||
|
||||
ANALOG DEVICES INC DMA DRIVERS
|
||||
M: Lars-Peter Clausen <lars@metafoo.de>
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
|
@ -135,6 +135,7 @@ struct sst_platform_info {
|
||||
const struct sst_res_info *res_info;
|
||||
const struct sst_lib_dnld_info *lib_info;
|
||||
const char *platform;
|
||||
bool streams_lost_on_suspend;
|
||||
};
|
||||
int add_sst_platform_device(void);
|
||||
#endif
|
||||
|
@ -995,15 +995,17 @@ static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = {
|
||||
{ "TX", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_codec_driver vc4_hdmi_audio_codec_drv = {
|
||||
.component_driver = {
|
||||
.controls = vc4_hdmi_audio_controls,
|
||||
.num_controls = ARRAY_SIZE(vc4_hdmi_audio_controls),
|
||||
.dapm_widgets = vc4_hdmi_audio_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets),
|
||||
.dapm_routes = vc4_hdmi_audio_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes),
|
||||
},
|
||||
static const struct snd_soc_component_driver vc4_hdmi_audio_component_drv = {
|
||||
.controls = vc4_hdmi_audio_controls,
|
||||
.num_controls = ARRAY_SIZE(vc4_hdmi_audio_controls),
|
||||
.dapm_widgets = vc4_hdmi_audio_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets),
|
||||
.dapm_routes = vc4_hdmi_audio_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops vc4_hdmi_audio_dai_ops = {
|
||||
@ -1101,11 +1103,11 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* register codec and codec dai */
|
||||
ret = snd_soc_register_codec(dev, &vc4_hdmi_audio_codec_drv,
|
||||
/* register component and codec dai */
|
||||
ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_component_drv,
|
||||
&vc4_hdmi_audio_codec_dai_drv, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register codec: %d\n", ret);
|
||||
dev_err(dev, "Could not register component: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1130,29 +1132,11 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
|
||||
*/
|
||||
snd_soc_card_set_drvdata(card, hdmi);
|
||||
ret = devm_snd_soc_register_card(dev, card);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(dev, "Could not register sound card: %d\n", ret);
|
||||
goto unregister_codec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_codec:
|
||||
snd_soc_unregister_codec(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vc4_hdmi_audio_cleanup(struct vc4_hdmi *hdmi)
|
||||
{
|
||||
struct device *dev = &hdmi->pdev->dev;
|
||||
|
||||
/*
|
||||
* If drvdata is not set this means the audio card was not
|
||||
* registered, just skip codec unregistration in this case.
|
||||
*/
|
||||
if (dev_get_drvdata(dev))
|
||||
snd_soc_unregister_codec(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_VC4_HDMI_CEC
|
||||
@ -1480,7 +1464,6 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master,
|
||||
struct vc4_dev *vc4 = drm->dev_private;
|
||||
struct vc4_hdmi *hdmi = vc4->hdmi;
|
||||
|
||||
vc4_hdmi_audio_cleanup(hdmi);
|
||||
cec_unregister_adapter(hdmi->cec_adap);
|
||||
vc4_hdmi_connector_destroy(hdmi->connector);
|
||||
vc4_hdmi_encoder_destroy(hdmi->encoder);
|
||||
|
15
include/dt-bindings/sound/rt5651.h
Normal file
15
include/dt-bindings/sound/rt5651.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __DT_RT5651_H
|
||||
#define __DT_RT5651_H
|
||||
|
||||
#define RT5651_JD_NULL 0
|
||||
#define RT5651_JD1_1 1
|
||||
#define RT5651_JD1_2 2
|
||||
#define RT5651_JD2 3
|
||||
|
||||
#define RT5651_OVCD_SF_0P5 0
|
||||
#define RT5651_OVCD_SF_0P75 1
|
||||
#define RT5651_OVCD_SF_1P0 2
|
||||
#define RT5651_OVCD_SF_1P5 3
|
||||
|
||||
#endif /* __DT_RT5651_H */
|
@ -34,14 +34,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
|
||||
static inline bool uac_v2v3_control_is_readable(u32 bmControls, u8 control)
|
||||
{
|
||||
return (bmControls >> (control * 2)) & 0x1;
|
||||
return (bmControls >> ((control - 1) * 2)) & 0x1;
|
||||
}
|
||||
|
||||
static inline bool uac2_control_is_writeable(u32 bmControls, u8 control)
|
||||
static inline bool uac_v2v3_control_is_writeable(u32 bmControls, u8 control)
|
||||
{
|
||||
return (bmControls >> (control * 2)) & 0x2;
|
||||
return (bmControls >> ((control - 1) * 2)) & 0x2;
|
||||
}
|
||||
|
||||
/* 4.7.2 Class-Specific AC Interface Descriptor */
|
||||
|
395
include/linux/usb/audio-v3.h
Normal file
395
include/linux/usb/audio-v3.h
Normal file
@ -0,0 +1,395 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2017 Ruslan Bilovol <ruslan.bilovol@gmail.com>
|
||||
*
|
||||
* This file holds USB constants and structures defined
|
||||
* by the USB DEVICE CLASS DEFINITION FOR AUDIO DEVICES Release 3.0.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_USB_AUDIO_V3_H
|
||||
#define __LINUX_USB_AUDIO_V3_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* v1.0, v2.0 and v3.0 of this standard have many things in common. For the rest
|
||||
* of the definitions, please refer to audio.h and audio-v2.h
|
||||
*/
|
||||
|
||||
/* All High Capability descriptors have these 2 fields at the beginning */
|
||||
struct uac3_hc_descriptor_header {
|
||||
__le16 wLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__le16 wDescriptorID;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 4.3.1 CLUSTER DESCRIPTOR HEADER */
|
||||
struct uac3_cluster_header_descriptor {
|
||||
__le16 wLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__le16 wDescriptorID;
|
||||
__u8 bNrChannels;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 4.3.2.1 SEGMENTS */
|
||||
struct uac3_cluster_segment_descriptor {
|
||||
__le16 wLength;
|
||||
__u8 bSegmentType;
|
||||
/* __u8[0]; segment-specific data */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 4.3.2.1.1 END SEGMENT */
|
||||
struct uac3_cluster_end_segment_descriptor {
|
||||
__le16 wLength;
|
||||
__u8 bSegmentType; /* Constant END_SEGMENT */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 4.3.2.1.3.1 INFORMATION SEGMENT */
|
||||
struct uac3_cluster_information_segment_descriptor {
|
||||
__le16 wLength;
|
||||
__u8 bSegmentType;
|
||||
__u8 bChPurpose;
|
||||
__u8 bChRelationship;
|
||||
__u8 bChGroupID;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 4.5.2 CLASS-SPECIFIC AC INTERFACE DESCRIPTOR */
|
||||
struct uac3_ac_header_descriptor {
|
||||
__u8 bLength; /* 10 */
|
||||
__u8 bDescriptorType; /* CS_INTERFACE descriptor type */
|
||||
__u8 bDescriptorSubtype; /* HEADER descriptor subtype */
|
||||
__u8 bCategory;
|
||||
|
||||
/* includes Clock Source, Unit, Terminal, and Power Domain desc. */
|
||||
__le16 wTotalLength;
|
||||
|
||||
__le32 bmControls;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 4.5.2.1 INPUT TERMINAL DESCRIPTOR */
|
||||
struct uac3_input_terminal_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bTerminalID;
|
||||
__le16 wTerminalType;
|
||||
__u8 bAssocTerminal;
|
||||
__u8 bCSourceID;
|
||||
__le32 bmControls;
|
||||
__le16 wClusterDescrID;
|
||||
__le16 wExTerminalDescrID;
|
||||
__le16 wConnectorsDescrID;
|
||||
__le16 wTerminalDescrStr;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 4.5.2.2 OUTPUT TERMINAL DESCRIPTOR */
|
||||
struct uac3_output_terminal_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bTerminalID;
|
||||
__le16 wTerminalType;
|
||||
__u8 bAssocTerminal;
|
||||
__u8 bSourceID;
|
||||
__u8 bCSourceID;
|
||||
__le32 bmControls;
|
||||
__le16 wExTerminalDescrID;
|
||||
__le16 wConnectorsDescrID;
|
||||
__le16 wTerminalDescrStr;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 4.5.2.7 FEATURE UNIT DESCRIPTOR */
|
||||
struct uac3_feature_unit_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bUnitID;
|
||||
__u8 bSourceID;
|
||||
/* bmaControls is actually u32,
|
||||
* but u8 is needed for the hybrid parser */
|
||||
__u8 bmaControls[0]; /* variable length */
|
||||
/* wFeatureDescrStr omitted */
|
||||
} __attribute__((packed));
|
||||
|
||||
#define UAC3_DT_FEATURE_UNIT_SIZE(ch) (7 + ((ch) + 1) * 4)
|
||||
|
||||
/* As above, but more useful for defining your own descriptors */
|
||||
#define DECLARE_UAC3_FEATURE_UNIT_DESCRIPTOR(ch) \
|
||||
struct uac3_feature_unit_descriptor_##ch { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubtype; \
|
||||
__u8 bUnitID; \
|
||||
__u8 bSourceID; \
|
||||
__le32 bmaControls[ch + 1]; \
|
||||
__le16 wFeatureDescrStr; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
/* 4.5.2.12 CLOCK SOURCE DESCRIPTOR */
|
||||
struct uac3_clock_source_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bClockID;
|
||||
__u8 bmAttributes;
|
||||
__le32 bmControls;
|
||||
__u8 bReferenceTerminal;
|
||||
__le16 wClockSourceStr;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* bmAttribute fields */
|
||||
#define UAC3_CLOCK_SOURCE_TYPE_EXT 0x0
|
||||
#define UAC3_CLOCK_SOURCE_TYPE_INT 0x1
|
||||
#define UAC3_CLOCK_SOURCE_ASYNC (0 << 2)
|
||||
#define UAC3_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 1)
|
||||
|
||||
/* 4.5.2.13 CLOCK SELECTOR DESCRIPTOR */
|
||||
struct uac3_clock_selector_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bClockID;
|
||||
__u8 bNrInPins;
|
||||
__u8 baCSourceID[];
|
||||
/* bmControls and wCSelectorDescrStr omitted */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 4.5.2.14 CLOCK MULTIPLIER DESCRIPTOR */
|
||||
struct uac3_clock_multiplier_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bClockID;
|
||||
__u8 bCSourceID;
|
||||
__le32 bmControls;
|
||||
__le16 wCMultiplierDescrStr;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 4.5.2.15 POWER DOMAIN DESCRIPTOR */
|
||||
struct uac3_power_domain_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bPowerDomainID;
|
||||
__le16 waRecoveryTime1;
|
||||
__le16 waRecoveryTime2;
|
||||
__u8 bNrEntities;
|
||||
__u8 baEntityID[];
|
||||
/* wPDomainDescrStr omitted */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* As above, but more useful for defining your own descriptors */
|
||||
#define DECLARE_UAC3_POWER_DOMAIN_DESCRIPTOR(n) \
|
||||
struct uac3_power_domain_descriptor_##n { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubtype; \
|
||||
__u8 bPowerDomainID; \
|
||||
__le16 waRecoveryTime1; \
|
||||
__le16 waRecoveryTime2; \
|
||||
__u8 bNrEntities; \
|
||||
__u8 baEntityID[n]; \
|
||||
__le16 wPDomainDescrStr; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
/* 4.7.2 CLASS-SPECIFIC AS INTERFACE DESCRIPTOR */
|
||||
struct uac3_as_header_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bTerminalLink;
|
||||
__le32 bmControls;
|
||||
__le16 wClusterDescrID;
|
||||
__le64 bmFormats;
|
||||
__u8 bSubslotSize;
|
||||
__u8 bBitResolution;
|
||||
__le16 bmAuxProtocols;
|
||||
__u8 bControlSize;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define UAC3_FORMAT_TYPE_I_RAW_DATA (1 << 6)
|
||||
|
||||
/* 4.8.1.2 CLASS-SPECIFIC AS ISOCHRONOUS AUDIO DATA ENDPOINT DESCRIPTOR */
|
||||
struct uac3_iso_endpoint_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__le32 bmControls;
|
||||
__u8 bLockDelayUnits;
|
||||
__le16 wLockDelay;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 6.1 INTERRUPT DATA MESSAGE */
|
||||
struct uac3_interrupt_data_msg {
|
||||
__u8 bInfo;
|
||||
__u8 bSourceType;
|
||||
__le16 wValue;
|
||||
__le16 wIndex;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* A.2 AUDIO AUDIO FUNCTION SUBCLASS CODES */
|
||||
#define UAC3_FUNCTION_SUBCLASS_UNDEFINED 0x00
|
||||
#define UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 0x01
|
||||
/* BADD profiles */
|
||||
#define UAC3_FUNCTION_SUBCLASS_GENERIC_IO 0x20
|
||||
#define UAC3_FUNCTION_SUBCLASS_HEADPHONE 0x21
|
||||
#define UAC3_FUNCTION_SUBCLASS_SPEAKER 0x22
|
||||
#define UAC3_FUNCTION_SUBCLASS_MICROPHONE 0x23
|
||||
#define UAC3_FUNCTION_SUBCLASS_HEADSET 0x24
|
||||
#define UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER 0x25
|
||||
#define UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE 0x26
|
||||
|
||||
/* A.7 AUDIO FUNCTION CATEGORY CODES */
|
||||
#define UAC3_FUNCTION_SUBCLASS_UNDEFINED 0x00
|
||||
#define UAC3_FUNCTION_DESKTOP_SPEAKER 0x01
|
||||
#define UAC3_FUNCTION_HOME_THEATER 0x02
|
||||
#define UAC3_FUNCTION_MICROPHONE 0x03
|
||||
#define UAC3_FUNCTION_HEADSET 0x04
|
||||
#define UAC3_FUNCTION_TELEPHONE 0x05
|
||||
#define UAC3_FUNCTION_CONVERTER 0x06
|
||||
#define UAC3_FUNCTION_SOUND_RECORDER 0x07
|
||||
#define UAC3_FUNCTION_IO_BOX 0x08
|
||||
#define UAC3_FUNCTION_MUSICAL_INSTRUMENT 0x09
|
||||
#define UAC3_FUNCTION_PRO_AUDIO 0x0a
|
||||
#define UAC3_FUNCTION_AUDIO_VIDEO 0x0b
|
||||
#define UAC3_FUNCTION_CONTROL_PANEL 0x0c
|
||||
#define UAC3_FUNCTION_HEADPHONE 0x0d
|
||||
#define UAC3_FUNCTION_GENERIC_SPEAKER 0x0e
|
||||
#define UAC3_FUNCTION_HEADSET_ADAPTER 0x0f
|
||||
#define UAC3_FUNCTION_SPEAKERPHONE 0x10
|
||||
#define UAC3_FUNCTION_OTHER 0xff
|
||||
|
||||
/* A.8 AUDIO CLASS-SPECIFIC DESCRIPTOR TYPES */
|
||||
#define UAC3_CS_UNDEFINED 0x20
|
||||
#define UAC3_CS_DEVICE 0x21
|
||||
#define UAC3_CS_CONFIGURATION 0x22
|
||||
#define UAC3_CS_STRING 0x23
|
||||
#define UAC3_CS_INTERFACE 0x24
|
||||
#define UAC3_CS_ENDPOINT 0x25
|
||||
#define UAC3_CS_CLUSTER 0x26
|
||||
|
||||
/* A.10 CLUSTER DESCRIPTOR SEGMENT TYPES */
|
||||
#define UAC3_SEGMENT_UNDEFINED 0x00
|
||||
#define UAC3_CLUSTER_DESCRIPTION 0x01
|
||||
#define UAC3_CLUSTER_VENDOR_DEFINED 0x1F
|
||||
#define UAC3_CHANNEL_INFORMATION 0x20
|
||||
#define UAC3_CHANNEL_AMBISONIC 0x21
|
||||
#define UAC3_CHANNEL_DESCRIPTION 0x22
|
||||
#define UAC3_CHANNEL_VENDOR_DEFINED 0xFE
|
||||
#define UAC3_END_SEGMENT 0xFF
|
||||
|
||||
/* A.11 CHANNEL PURPOSE DEFINITIONS */
|
||||
#define UAC3_PURPOSE_UNDEFINED 0x00
|
||||
#define UAC3_PURPOSE_GENERIC_AUDIO 0x01
|
||||
#define UAC3_PURPOSE_VOICE 0x02
|
||||
#define UAC3_PURPOSE_SPEECH 0x03
|
||||
#define UAC3_PURPOSE_AMBIENT 0x04
|
||||
#define UAC3_PURPOSE_REFERENCE 0x05
|
||||
#define UAC3_PURPOSE_ULTRASONIC 0x06
|
||||
#define UAC3_PURPOSE_VIBROKINETIC 0x07
|
||||
#define UAC3_PURPOSE_NON_AUDIO 0xFF
|
||||
|
||||
/* A.12 CHANNEL RELATIONSHIP DEFINITIONS */
|
||||
#define UAC3_CH_RELATIONSHIP_UNDEFINED 0x00
|
||||
#define UAC3_CH_MONO 0x01
|
||||
#define UAC3_CH_LEFT 0x02
|
||||
#define UAC3_CH_RIGHT 0x03
|
||||
#define UAC3_CH_ARRAY 0x04
|
||||
#define UAC3_CH_PATTERN_X 0x20
|
||||
#define UAC3_CH_PATTERN_Y 0x21
|
||||
#define UAC3_CH_PATTERN_A 0x22
|
||||
#define UAC3_CH_PATTERN_B 0x23
|
||||
#define UAC3_CH_PATTERN_M 0x24
|
||||
#define UAC3_CH_PATTERN_S 0x25
|
||||
#define UAC3_CH_FRONT_LEFT 0x80
|
||||
#define UAC3_CH_FRONT_RIGHT 0x81
|
||||
#define UAC3_CH_FRONT_CENTER 0x82
|
||||
#define UAC3_CH_FRONT_LEFT_OF_CENTER 0x83
|
||||
#define UAC3_CH_FRONT_RIGHT_OF_CENTER 0x84
|
||||
#define UAC3_CH_FRONT_WIDE_LEFT 0x85
|
||||
#define UAC3_CH_FRONT_WIDE_RIGHT 0x86
|
||||
#define UAC3_CH_SIDE_LEFT 0x87
|
||||
#define UAC3_CH_SIDE_RIGHT 0x88
|
||||
#define UAC3_CH_SURROUND_ARRAY_LEFT 0x89
|
||||
#define UAC3_CH_SURROUND_ARRAY_RIGHT 0x8A
|
||||
#define UAC3_CH_BACK_LEFT 0x8B
|
||||
#define UAC3_CH_BACK_RIGHT 0x8C
|
||||
#define UAC3_CH_BACK_CENTER 0x8D
|
||||
#define UAC3_CH_BACK_LEFT_OF_CENTER 0x8E
|
||||
#define UAC3_CH_BACK_RIGHT_OF_CENTER 0x8F
|
||||
#define UAC3_CH_BACK_WIDE_LEFT 0x90
|
||||
#define UAC3_CH_BACK_WIDE_RIGHT 0x91
|
||||
#define UAC3_CH_TOP_CENTER 0x92
|
||||
#define UAC3_CH_TOP_FRONT_LEFT 0x93
|
||||
#define UAC3_CH_TOP_FRONT_RIGHT 0x94
|
||||
#define UAC3_CH_TOP_FRONT_CENTER 0x95
|
||||
#define UAC3_CH_TOP_FRONT_LOC 0x96
|
||||
#define UAC3_CH_TOP_FRONT_ROC 0x97
|
||||
#define UAC3_CH_TOP_FRONT_WIDE_LEFT 0x98
|
||||
#define UAC3_CH_TOP_FRONT_WIDE_RIGHT 0x99
|
||||
#define UAC3_CH_TOP_SIDE_LEFT 0x9A
|
||||
#define UAC3_CH_TOP_SIDE_RIGHT 0x9B
|
||||
#define UAC3_CH_TOP_SURR_ARRAY_LEFT 0x9C
|
||||
#define UAC3_CH_TOP_SURR_ARRAY_RIGHT 0x9D
|
||||
#define UAC3_CH_TOP_BACK_LEFT 0x9E
|
||||
#define UAC3_CH_TOP_BACK_RIGHT 0x9F
|
||||
#define UAC3_CH_TOP_BACK_CENTER 0xA0
|
||||
#define UAC3_CH_TOP_BACK_LOC 0xA1
|
||||
#define UAC3_CH_TOP_BACK_ROC 0xA2
|
||||
#define UAC3_CH_TOP_BACK_WIDE_LEFT 0xA3
|
||||
#define UAC3_CH_TOP_BACK_WIDE_RIGHT 0xA4
|
||||
#define UAC3_CH_BOTTOM_CENTER 0xA5
|
||||
#define UAC3_CH_BOTTOM_FRONT_LEFT 0xA6
|
||||
#define UAC3_CH_BOTTOM_FRONT_RIGHT 0xA7
|
||||
#define UAC3_CH_BOTTOM_FRONT_CENTER 0xA8
|
||||
#define UAC3_CH_BOTTOM_FRONT_LOC 0xA9
|
||||
#define UAC3_CH_BOTTOM_FRONT_ROC 0xAA
|
||||
#define UAC3_CH_BOTTOM_FRONT_WIDE_LEFT 0xAB
|
||||
#define UAC3_CH_BOTTOM_FRONT_WIDE_RIGHT 0xAC
|
||||
#define UAC3_CH_BOTTOM_SIDE_LEFT 0xAD
|
||||
#define UAC3_CH_BOTTOM_SIDE_RIGHT 0xAE
|
||||
#define UAC3_CH_BOTTOM_SURR_ARRAY_LEFT 0xAF
|
||||
#define UAC3_CH_BOTTOM_SURR_ARRAY_RIGHT 0xB0
|
||||
#define UAC3_CH_BOTTOM_BACK_LEFT 0xB1
|
||||
#define UAC3_CH_BOTTOM_BACK_RIGHT 0xB2
|
||||
#define UAC3_CH_BOTTOM_BACK_CENTER 0xB3
|
||||
#define UAC3_CH_BOTTOM_BACK_LOC 0xB4
|
||||
#define UAC3_CH_BOTTOM_BACK_ROC 0xB5
|
||||
#define UAC3_CH_BOTTOM_BACK_WIDE_LEFT 0xB6
|
||||
#define UAC3_CH_BOTTOM_BACK_WIDE_RIGHT 0xB7
|
||||
#define UAC3_CH_LOW_FREQUENCY_EFFECTS 0xB8
|
||||
#define UAC3_CH_LFE_LEFT 0xB9
|
||||
#define UAC3_CH_LFE_RIGHT 0xBA
|
||||
#define UAC3_CH_HEADPHONE_LEFT 0xBB
|
||||
#define UAC3_CH_HEADPHONE_RIGHT 0xBC
|
||||
|
||||
/* A.15 AUDIO CLASS-SPECIFIC AC INTERFACE DESCRIPTOR SUBTYPES */
|
||||
/* see audio.h for the rest, which is identical to v1 */
|
||||
#define UAC3_EXTENDED_TERMINAL 0x04
|
||||
#define UAC3_MIXER_UNIT 0x05
|
||||
#define UAC3_SELECTOR_UNIT 0x06
|
||||
#define UAC3_FEATURE_UNIT 0x07
|
||||
#define UAC3_EFFECT_UNIT 0x08
|
||||
#define UAC3_PROCESSING_UNIT 0x09
|
||||
#define UAC3_EXTENSION_UNIT 0x0a
|
||||
#define UAC3_CLOCK_SOURCE 0x0b
|
||||
#define UAC3_CLOCK_SELECTOR 0x0c
|
||||
#define UAC3_CLOCK_MULTIPLIER 0x0d
|
||||
#define UAC3_SAMPLE_RATE_CONVERTER 0x0e
|
||||
#define UAC3_CONNECTORS 0x0f
|
||||
#define UAC3_POWER_DOMAIN 0x10
|
||||
|
||||
/* A.22 AUDIO CLASS-SPECIFIC REQUEST CODES */
|
||||
/* see audio-v2.h for the rest, which is identical to v2 */
|
||||
#define UAC3_CS_REQ_INTEN 0x04
|
||||
#define UAC3_CS_REQ_STRING 0x05
|
||||
#define UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR 0x06
|
||||
|
||||
/* A.23.1 AUDIOCONTROL INTERFACE CONTROL SELECTORS */
|
||||
#define UAC3_AC_CONTROL_UNDEFINED 0x00
|
||||
#define UAC3_AC_ACTIVE_INTERFACE_CONTROL 0x01
|
||||
#define UAC3_AC_POWER_DOMAIN_CONTROL 0x02
|
||||
|
||||
#endif /* __LINUX_USB_AUDIO_V3_H */
|
@ -36,6 +36,8 @@ struct da7219_aad_pdata;
|
||||
struct da7219_pdata {
|
||||
bool wakeup_source;
|
||||
|
||||
const char *dai_clks_name;
|
||||
|
||||
/* Mic */
|
||||
enum da7219_micbias_voltage micbias_lvl;
|
||||
enum da7219_mic_amp_in_sel mic_amp_in_sel;
|
||||
|
@ -118,6 +118,8 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
|
||||
* PCM substream. Will be called from the PCM drivers hwparams callback.
|
||||
* @compat_request_channel: Callback to request a DMA channel for platforms
|
||||
* which do not use devicetree.
|
||||
* @process: Callback used to apply processing on samples transferred from/to
|
||||
* user space.
|
||||
* @compat_filter_fn: Will be used as the filter function when requesting a
|
||||
* channel for platforms which do not use devicetree. The filter parameter
|
||||
* will be the DAI's DMA data.
|
||||
@ -140,6 +142,9 @@ struct snd_dmaengine_pcm_config {
|
||||
struct dma_chan *(*compat_request_channel)(
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_substream *substream);
|
||||
int (*process)(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long hwoff,
|
||||
void *buf, unsigned long bytes);
|
||||
dma_filter_fn compat_filter_fn;
|
||||
struct device *dma_dev;
|
||||
const char *chan_names[SNDRV_PCM_STREAM_LAST + 1];
|
||||
@ -161,4 +166,6 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct dma_slave_config *slave_config);
|
||||
|
||||
#define SND_DMAENGINE_PCM_DRV_NAME "snd_dmaengine_pcm"
|
||||
|
||||
#endif
|
||||
|
@ -1710,6 +1710,7 @@ struct snd_emu10k1 {
|
||||
unsigned int ecard_ctrl; /* ecard control bits */
|
||||
unsigned int address_mode; /* address mode */
|
||||
unsigned long dma_mask; /* PCI DMA mask */
|
||||
bool iommu_workaround; /* IOMMU workaround needed */
|
||||
unsigned int delay_pcm_irq; /* in samples */
|
||||
int max_cache_pages; /* max memory size / PAGE_SIZE */
|
||||
struct snd_dma_buffer silent_page; /* silent page */
|
||||
@ -1718,7 +1719,6 @@ struct snd_emu10k1 {
|
||||
struct snd_dma_buffer p16v_buffer;
|
||||
|
||||
struct snd_util_memhdr *memhdr; /* page allocation list */
|
||||
struct snd_emu10k1_memblk *reserved_page; /* reserved page */
|
||||
|
||||
struct list_head mapped_link_head;
|
||||
struct list_head mapped_order_link_head;
|
||||
@ -1878,6 +1878,8 @@ void snd_p16v_resume(struct snd_emu10k1 *emu);
|
||||
/* memory allocation */
|
||||
struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream);
|
||||
int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
|
||||
int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
|
||||
struct snd_dma_buffer *dmab);
|
||||
struct snd_util_memblk *snd_emu10k1_synth_alloc(struct snd_emu10k1 *emu, unsigned int size);
|
||||
int snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
|
||||
int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, int size);
|
||||
|
@ -146,6 +146,8 @@ int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid,
|
||||
int flags, unsigned int verb, unsigned int parm);
|
||||
bool snd_hdac_check_power_state(struct hdac_device *hdac,
|
||||
hda_nid_t nid, unsigned int target_state);
|
||||
unsigned int snd_hdac_sync_power_state(struct hdac_device *hdac,
|
||||
hda_nid_t nid, unsigned int target_state);
|
||||
/**
|
||||
* snd_hdac_read_parm - read a codec parameter
|
||||
* @codec: the codec object
|
||||
|
@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime {
|
||||
char *buffer; /* vmallocated period */
|
||||
size_t buffer_used; /* used length from period buffer */
|
||||
struct mutex params_lock;
|
||||
atomic_t rw_ref; /* concurrent read/write accesses */
|
||||
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
|
||||
struct snd_pcm_plugin *plugin_first;
|
||||
struct snd_pcm_plugin *plugin_last;
|
||||
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* linux/sound/rt286.h -- Platform data for RT286
|
||||
*
|
||||
* Copyright 2013 Realtek Microelectronics
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_SND_RT5651_H
|
||||
#define __LINUX_SND_RT5651_H
|
||||
|
||||
enum rt5651_jd_src {
|
||||
RT5651_JD_NULL,
|
||||
RT5651_JD1_1,
|
||||
RT5651_JD1_2,
|
||||
RT5651_JD2,
|
||||
};
|
||||
|
||||
struct rt5651_platform_data {
|
||||
/* IN2 can optionally be differential */
|
||||
bool in2_diff;
|
||||
|
||||
bool dmic_en;
|
||||
enum rt5651_jd_src jd_src;
|
||||
};
|
||||
|
||||
#endif
|
@ -30,6 +30,7 @@ enum rt5659_dmic2_data_pin {
|
||||
enum rt5659_jd_src {
|
||||
RT5659_JD_NULL,
|
||||
RT5659_JD3,
|
||||
RT5659_JD_HDA_HEADER,
|
||||
};
|
||||
|
||||
struct rt5659_platform_data {
|
||||
|
@ -269,6 +269,13 @@ struct device;
|
||||
.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
|
||||
.on_val = wflags}
|
||||
#define SND_SOC_DAPM_PINCTRL(wname, active, sleep) \
|
||||
{ .id = snd_soc_dapm_pinctrl, .name = wname, \
|
||||
.priv = (&(struct snd_soc_dapm_pinctrl_priv) \
|
||||
{ .active_state = active, .sleep_state = sleep,}), \
|
||||
.reg = SND_SOC_NOPM, .event = dapm_pinctrl_event, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
|
||||
|
||||
|
||||
|
||||
/* dapm kcontrol types */
|
||||
@ -374,6 +381,8 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
int dapm_clock_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
||||
/* dapm controls */
|
||||
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
@ -500,6 +509,7 @@ enum snd_soc_dapm_type {
|
||||
snd_soc_dapm_pre, /* machine specific pre widget - exec first */
|
||||
snd_soc_dapm_post, /* machine specific post widget - exec last */
|
||||
snd_soc_dapm_supply, /* power/clock supply */
|
||||
snd_soc_dapm_pinctrl, /* pinctrl */
|
||||
snd_soc_dapm_regulator_supply, /* external regulator */
|
||||
snd_soc_dapm_clock_supply, /* external clock */
|
||||
snd_soc_dapm_aif_in, /* audio interface input */
|
||||
@ -581,6 +591,7 @@ struct snd_soc_dapm_widget {
|
||||
|
||||
void *priv; /* widget specific data */
|
||||
struct regulator *regulator; /* attached regulator */
|
||||
struct pinctrl *pinctrl; /* attached pinctrl */
|
||||
const struct snd_soc_pcm_stream *params; /* params for dai links */
|
||||
unsigned int num_params; /* number of params for dai links */
|
||||
unsigned int params_select; /* currently selected param for dai link */
|
||||
@ -683,6 +694,11 @@ struct snd_soc_dapm_stats {
|
||||
int neighbour_checks;
|
||||
};
|
||||
|
||||
struct snd_soc_dapm_pinctrl_priv {
|
||||
const char *active_state;
|
||||
const char *sleep_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
|
||||
* @dapm: The DAPM context to initialize
|
||||
|
@ -586,10 +586,17 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int mask, unsigned int value);
|
||||
|
||||
#ifdef CONFIG_SND_SOC_AC97_BUS
|
||||
struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec);
|
||||
struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
|
||||
#define snd_soc_alloc_ac97_codec(codec) \
|
||||
snd_soc_alloc_ac97_component(&codec->component)
|
||||
#define snd_soc_new_ac97_codec(codec, id, id_mask) \
|
||||
snd_soc_new_ac97_component(&codec->component, id, id_mask)
|
||||
#define snd_soc_free_ac97_codec(ac97) \
|
||||
snd_soc_free_ac97_component(ac97)
|
||||
|
||||
struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
|
||||
struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
|
||||
unsigned int id, unsigned int id_mask);
|
||||
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
|
||||
void snd_soc_free_ac97_component(struct snd_ac97 *ac97);
|
||||
|
||||
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
|
||||
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
|
||||
@ -1807,6 +1814,7 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
|
||||
int snd_soc_of_get_dai_link_codecs(struct device *dev,
|
||||
struct device_node *of_node,
|
||||
struct snd_soc_dai_link *dai_link);
|
||||
void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link);
|
||||
|
||||
int snd_soc_add_dai_link(struct snd_soc_card *card,
|
||||
struct snd_soc_dai_link *dai_link);
|
||||
|
@ -27,6 +27,7 @@
|
||||
/* bInterfaceProtocol values to denote the version of the standard used */
|
||||
#define UAC_VERSION_1 0x00
|
||||
#define UAC_VERSION_2 0x20
|
||||
#define UAC_VERSION_3 0x30
|
||||
|
||||
/* A.2 Audio Interface Subclass Codes */
|
||||
#define USB_SUBCLASS_AUDIOCONTROL 0x01
|
||||
|
@ -242,6 +242,7 @@ typedef int __bitwise snd_pcm_format_t;
|
||||
#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */
|
||||
#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */
|
||||
#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE
|
||||
#define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8
|
||||
|
||||
#ifdef SNDRV_LITTLE_ENDIAN
|
||||
#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
|
||||
|
@ -105,7 +105,7 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct snd_kctl_event *cread;
|
||||
|
||||
|
||||
spin_lock_irqsave(&ctl->read_lock, flags);
|
||||
while (!list_empty(&ctl->events)) {
|
||||
cread = snd_kctl_event(ctl->events.next);
|
||||
@ -159,7 +159,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
|
||||
unsigned long flags;
|
||||
struct snd_ctl_file *ctl;
|
||||
struct snd_kctl_event *ev;
|
||||
|
||||
|
||||
if (snd_BUG_ON(!card || !id))
|
||||
return;
|
||||
if (card->shutdown)
|
||||
@ -213,7 +213,7 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
|
||||
{
|
||||
unsigned int size;
|
||||
unsigned int idx;
|
||||
|
||||
|
||||
if (count == 0 || count > MAX_CONTROL_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
@ -238,7 +238,7 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
|
||||
* @ncontrol: the initialization record
|
||||
* @private_data: the private data to set
|
||||
*
|
||||
* Allocates a new struct snd_kcontrol instance and initialize from the given
|
||||
* Allocates a new struct snd_kcontrol instance and initialize from the given
|
||||
* template. When the access field of ncontrol is 0, it's assumed as
|
||||
* READWRITE access. When the count field is 0, it's assumes as one.
|
||||
*
|
||||
@ -251,7 +251,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
|
||||
unsigned int count;
|
||||
unsigned int access;
|
||||
int err;
|
||||
|
||||
|
||||
if (snd_BUG_ON(!ncontrol || !ncontrol->info))
|
||||
return NULL;
|
||||
|
||||
@ -753,7 +753,7 @@ static int snd_ctl_elem_list(struct snd_card *card,
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int offset, space, jidx;
|
||||
int err = 0;
|
||||
|
||||
|
||||
if (copy_from_user(&list, _list, sizeof(list)))
|
||||
return -EFAULT;
|
||||
offset = list.offset;
|
||||
@ -827,7 +827,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
|
||||
struct snd_kcontrol_volatile *vd;
|
||||
unsigned int index_offset;
|
||||
int result;
|
||||
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &info->id);
|
||||
if (kctl == NULL) {
|
||||
@ -992,7 +992,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
|
||||
struct snd_kcontrol *kctl;
|
||||
struct snd_kcontrol_volatile *vd;
|
||||
int result;
|
||||
|
||||
|
||||
if (copy_from_user(&id, _id, sizeof(id)))
|
||||
return -EFAULT;
|
||||
down_write(&card->controls_rwsem);
|
||||
@ -1020,7 +1020,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
||||
struct snd_kcontrol *kctl;
|
||||
struct snd_kcontrol_volatile *vd;
|
||||
int result;
|
||||
|
||||
|
||||
if (copy_from_user(&id, _id, sizeof(id)))
|
||||
return -EFAULT;
|
||||
down_write(&card->controls_rwsem);
|
||||
|
@ -670,7 +670,7 @@ card_id_show_attr(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", card->id);
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", card->id);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -710,7 +710,7 @@ card_number_show_attr(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%i\n", card->number);
|
||||
return scnprintf(buf, PAGE_SIZE, "%i\n", card->number);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL);
|
||||
|
@ -823,8 +823,25 @@ static int choose_rate(struct snd_pcm_substream *substream,
|
||||
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
|
||||
}
|
||||
|
||||
static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
|
||||
bool trylock)
|
||||
/* parameter locking: returns immediately if tried during streaming */
|
||||
static int lock_params(struct snd_pcm_runtime *runtime)
|
||||
{
|
||||
if (mutex_lock_interruptible(&runtime->oss.params_lock))
|
||||
return -ERESTARTSYS;
|
||||
if (atomic_read(&runtime->oss.rw_ref)) {
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unlock_params(struct snd_pcm_runtime *runtime)
|
||||
{
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
}
|
||||
|
||||
/* call with params_lock held */
|
||||
static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_pcm_hw_params *params, *sparams;
|
||||
@ -838,11 +855,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
|
||||
const struct snd_mask *sformat_mask;
|
||||
struct snd_mask mask;
|
||||
|
||||
if (trylock) {
|
||||
if (!(mutex_trylock(&runtime->oss.params_lock)))
|
||||
return -EAGAIN;
|
||||
} else if (mutex_lock_interruptible(&runtime->oss.params_lock))
|
||||
return -ERESTARTSYS;
|
||||
if (!runtime->oss.params)
|
||||
return 0;
|
||||
sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
|
||||
params = kmalloc(sizeof(*params), GFP_KERNEL);
|
||||
sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
|
||||
@ -1068,6 +1082,23 @@ failure:
|
||||
kfree(sw_params);
|
||||
kfree(params);
|
||||
kfree(sparams);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* this one takes the lock by itself */
|
||||
static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
|
||||
bool trylock)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int err;
|
||||
|
||||
if (trylock) {
|
||||
if (!(mutex_trylock(&runtime->oss.params_lock)))
|
||||
return -EAGAIN;
|
||||
} else if (mutex_lock_interruptible(&runtime->oss.params_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
err = snd_pcm_oss_change_params_locked(substream);
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
return err;
|
||||
}
|
||||
@ -1096,11 +1127,14 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call with params_lock held */
|
||||
static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
int err;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
if (!runtime->oss.prepare)
|
||||
return 0;
|
||||
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
|
||||
if (err < 0) {
|
||||
pcm_dbg(substream->pcm,
|
||||
@ -1120,14 +1154,35 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream)
|
||||
struct snd_pcm_runtime *runtime;
|
||||
int err;
|
||||
|
||||
if (substream == NULL)
|
||||
return 0;
|
||||
runtime = substream->runtime;
|
||||
if (runtime->oss.params) {
|
||||
err = snd_pcm_oss_change_params(substream, false);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (runtime->oss.prepare) {
|
||||
if (mutex_lock_interruptible(&runtime->oss.params_lock))
|
||||
return -ERESTARTSYS;
|
||||
err = snd_pcm_oss_prepare(substream);
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call with params_lock held */
|
||||
static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
int err;
|
||||
|
||||
runtime = substream->runtime;
|
||||
if (runtime->oss.params) {
|
||||
err = snd_pcm_oss_change_params_locked(substream);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (runtime->oss.prepare) {
|
||||
err = snd_pcm_oss_prepare(substream);
|
||||
if (err < 0)
|
||||
@ -1332,13 +1387,15 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
|
||||
if (atomic_read(&substream->mmap_count))
|
||||
return -ENXIO;
|
||||
|
||||
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
|
||||
return tmp;
|
||||
atomic_inc(&runtime->oss.rw_ref);
|
||||
while (bytes > 0) {
|
||||
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
|
||||
tmp = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
tmp = snd_pcm_oss_make_ready_locked(substream);
|
||||
if (tmp < 0)
|
||||
goto err;
|
||||
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
|
||||
tmp = bytes;
|
||||
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
|
||||
@ -1394,6 +1451,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
|
||||
}
|
||||
tmp = 0;
|
||||
}
|
||||
atomic_dec(&runtime->oss.rw_ref);
|
||||
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
|
||||
}
|
||||
|
||||
@ -1439,13 +1497,15 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
|
||||
if (atomic_read(&substream->mmap_count))
|
||||
return -ENXIO;
|
||||
|
||||
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
|
||||
return tmp;
|
||||
atomic_inc(&runtime->oss.rw_ref);
|
||||
while (bytes > 0) {
|
||||
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
|
||||
tmp = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
tmp = snd_pcm_oss_make_ready_locked(substream);
|
||||
if (tmp < 0)
|
||||
goto err;
|
||||
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
|
||||
if (runtime->oss.buffer_used == 0) {
|
||||
tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
|
||||
@ -1486,6 +1546,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
|
||||
}
|
||||
tmp = 0;
|
||||
}
|
||||
atomic_dec(&runtime->oss.rw_ref);
|
||||
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
|
||||
}
|
||||
|
||||
@ -1501,10 +1562,12 @@ static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
continue;
|
||||
runtime = substream->runtime;
|
||||
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
|
||||
mutex_lock(&runtime->oss.params_lock);
|
||||
runtime->oss.prepare = 1;
|
||||
runtime->oss.buffer_used = 0;
|
||||
runtime->oss.prev_hw_ptr_period = 0;
|
||||
runtime->oss.period_ptr = 0;
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1590,9 +1653,13 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
goto __direct;
|
||||
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
|
||||
return err;
|
||||
atomic_inc(&runtime->oss.rw_ref);
|
||||
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
|
||||
atomic_dec(&runtime->oss.rw_ref);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
format = snd_pcm_oss_format_from(runtime->oss.format);
|
||||
width = snd_pcm_format_physical_width(format);
|
||||
mutex_lock(&runtime->oss.params_lock);
|
||||
if (runtime->oss.buffer_used > 0) {
|
||||
#ifdef OSS_DEBUG
|
||||
pcm_dbg(substream->pcm, "sync: buffer_used\n");
|
||||
@ -1602,10 +1669,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
runtime->oss.buffer + runtime->oss.buffer_used,
|
||||
size);
|
||||
err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
} else if (runtime->oss.period_ptr > 0) {
|
||||
#ifdef OSS_DEBUG
|
||||
pcm_dbg(substream->pcm, "sync: period_ptr\n");
|
||||
@ -1615,10 +1680,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
runtime->oss.buffer,
|
||||
size * 8 / width);
|
||||
err = snd_pcm_oss_sync1(substream, size);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
}
|
||||
/*
|
||||
* The ALSA's period might be a bit large than OSS one.
|
||||
@ -1632,7 +1695,11 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
|
||||
snd_pcm_lib_writev(substream, NULL, size);
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
atomic_dec(&runtime->oss.rw_ref);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/*
|
||||
* finish sync: drain the buffer
|
||||
*/
|
||||
@ -1643,7 +1710,9 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
substream->f_flags = saved_f_flags;
|
||||
if (err < 0)
|
||||
return err;
|
||||
mutex_lock(&runtime->oss.params_lock);
|
||||
runtime->oss.prepare = 1;
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
}
|
||||
|
||||
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
|
||||
@ -1654,8 +1723,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
mutex_lock(&runtime->oss.params_lock);
|
||||
runtime->oss.buffer_used = 0;
|
||||
runtime->oss.prepare = 1;
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1667,6 +1738,8 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
|
||||
for (idx = 1; idx >= 0; --idx) {
|
||||
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
|
||||
struct snd_pcm_runtime *runtime;
|
||||
int err;
|
||||
|
||||
if (substream == NULL)
|
||||
continue;
|
||||
runtime = substream->runtime;
|
||||
@ -1674,10 +1747,14 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
|
||||
rate = 1000;
|
||||
else if (rate > 192000)
|
||||
rate = 192000;
|
||||
err = lock_params(runtime);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (runtime->oss.rate != rate) {
|
||||
runtime->oss.params = 1;
|
||||
runtime->oss.rate = rate;
|
||||
}
|
||||
unlock_params(runtime);
|
||||
}
|
||||
return snd_pcm_oss_get_rate(pcm_oss_file);
|
||||
}
|
||||
@ -1702,13 +1779,19 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig
|
||||
for (idx = 1; idx >= 0; --idx) {
|
||||
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
|
||||
struct snd_pcm_runtime *runtime;
|
||||
int err;
|
||||
|
||||
if (substream == NULL)
|
||||
continue;
|
||||
runtime = substream->runtime;
|
||||
err = lock_params(runtime);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (runtime->oss.channels != channels) {
|
||||
runtime->oss.params = 1;
|
||||
runtime->oss.channels = channels;
|
||||
}
|
||||
unlock_params(runtime);
|
||||
}
|
||||
return snd_pcm_oss_get_channels(pcm_oss_file);
|
||||
}
|
||||
@ -1781,6 +1864,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
|
||||
{
|
||||
int formats, idx;
|
||||
int err;
|
||||
|
||||
if (format != AFMT_QUERY) {
|
||||
formats = snd_pcm_oss_get_formats(pcm_oss_file);
|
||||
@ -1794,10 +1878,14 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for
|
||||
if (substream == NULL)
|
||||
continue;
|
||||
runtime = substream->runtime;
|
||||
err = lock_params(runtime);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (runtime->oss.format != format) {
|
||||
runtime->oss.params = 1;
|
||||
runtime->oss.format = format;
|
||||
}
|
||||
unlock_params(runtime);
|
||||
}
|
||||
}
|
||||
return snd_pcm_oss_get_format(pcm_oss_file);
|
||||
@ -1817,8 +1905,6 @@ static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int s
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
if (substream == NULL)
|
||||
return 0;
|
||||
runtime = substream->runtime;
|
||||
if (subdivide == 0) {
|
||||
subdivide = runtime->oss.subdivision;
|
||||
@ -1842,9 +1928,17 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int
|
||||
|
||||
for (idx = 1; idx >= 0; --idx) {
|
||||
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
if (substream == NULL)
|
||||
continue;
|
||||
if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
|
||||
runtime = substream->runtime;
|
||||
err = lock_params(runtime);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_oss_set_subdivide1(substream, subdivide);
|
||||
unlock_params(runtime);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
@ -1854,8 +1948,6 @@ static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsign
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
if (substream == NULL)
|
||||
return 0;
|
||||
runtime = substream->runtime;
|
||||
if (runtime->oss.subdivision || runtime->oss.fragshift)
|
||||
return -EINVAL;
|
||||
@ -1875,9 +1967,17 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig
|
||||
|
||||
for (idx = 1; idx >= 0; --idx) {
|
||||
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
if (substream == NULL)
|
||||
continue;
|
||||
if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
|
||||
runtime = substream->runtime;
|
||||
err = lock_params(runtime);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_oss_set_fragment1(substream, val);
|
||||
unlock_params(runtime);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
@ -1961,6 +2061,9 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
|
||||
}
|
||||
if (psubstream) {
|
||||
runtime = psubstream->runtime;
|
||||
cmd = 0;
|
||||
if (mutex_lock_interruptible(&runtime->oss.params_lock))
|
||||
return -ERESTARTSYS;
|
||||
if (trigger & PCM_ENABLE_OUTPUT) {
|
||||
if (runtime->oss.trigger)
|
||||
goto _skip1;
|
||||
@ -1978,13 +2081,19 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
|
||||
cmd = SNDRV_PCM_IOCTL_DROP;
|
||||
runtime->oss.prepare = 1;
|
||||
}
|
||||
err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
_skip1:
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
if (cmd) {
|
||||
err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (csubstream) {
|
||||
runtime = csubstream->runtime;
|
||||
cmd = 0;
|
||||
if (mutex_lock_interruptible(&runtime->oss.params_lock))
|
||||
return -ERESTARTSYS;
|
||||
if (trigger & PCM_ENABLE_INPUT) {
|
||||
if (runtime->oss.trigger)
|
||||
goto _skip2;
|
||||
@ -1999,11 +2108,14 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
|
||||
cmd = SNDRV_PCM_IOCTL_DROP;
|
||||
runtime->oss.prepare = 1;
|
||||
}
|
||||
err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
_skip2:
|
||||
mutex_unlock(&runtime->oss.params_lock);
|
||||
if (cmd) {
|
||||
err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2255,6 +2367,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
|
||||
runtime->oss.maxfrags = 0;
|
||||
runtime->oss.subdivision = 0;
|
||||
substream->pcm_release = snd_pcm_oss_release_substream;
|
||||
atomic_set(&runtime->oss.rw_ref, 0);
|
||||
}
|
||||
|
||||
static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/minors.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/timer.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/info.h>
|
||||
|
||||
@ -1054,8 +1055,13 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
||||
snd_free_pages((void*)runtime->control,
|
||||
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
|
||||
kfree(runtime->hw_constraints.rules);
|
||||
kfree(runtime);
|
||||
/* Avoid concurrent access to runtime via PCM timer interface */
|
||||
if (substream->timer)
|
||||
spin_lock_irq(&substream->timer->lock);
|
||||
substream->runtime = NULL;
|
||||
if (substream->timer)
|
||||
spin_unlock_irq(&substream->timer->lock);
|
||||
kfree(runtime);
|
||||
put_pid(substream->pid);
|
||||
substream->pid = NULL;
|
||||
substream->pstr->substream_opened--;
|
||||
|
@ -1129,16 +1129,12 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
|
||||
if (constrs->rules_num >= constrs->rules_all) {
|
||||
struct snd_pcm_hw_rule *new;
|
||||
unsigned int new_rules = constrs->rules_all + 16;
|
||||
new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
|
||||
new = krealloc(constrs->rules, new_rules * sizeof(*c),
|
||||
GFP_KERNEL);
|
||||
if (!new) {
|
||||
va_end(args);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (constrs->rules) {
|
||||
memcpy(new, constrs->rules,
|
||||
constrs->rules_num * sizeof(*c));
|
||||
kfree(constrs->rules);
|
||||
}
|
||||
constrs->rules = new;
|
||||
constrs->rules_all = new_rules;
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_constraints *constrs =
|
||||
&substream->runtime->hw_constraints;
|
||||
unsigned int k;
|
||||
unsigned int rstamps[constrs->rules_num];
|
||||
unsigned int *rstamps;
|
||||
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
|
||||
unsigned int stamp;
|
||||
struct snd_pcm_hw_rule *r;
|
||||
@ -331,7 +331,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
|
||||
struct snd_mask old_mask;
|
||||
struct snd_interval old_interval;
|
||||
bool again;
|
||||
int changed;
|
||||
int changed, err = 0;
|
||||
|
||||
/*
|
||||
* Each application of rule has own sequence number.
|
||||
@ -339,8 +339,9 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
|
||||
* Each member of 'rstamps' array represents the sequence number of
|
||||
* recent application of corresponding rule.
|
||||
*/
|
||||
for (k = 0; k < constrs->rules_num; k++)
|
||||
rstamps[k] = 0;
|
||||
rstamps = kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL);
|
||||
if (!rstamps)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Each member of 'vstamps' array represents the sequence number of
|
||||
@ -398,8 +399,10 @@ retry:
|
||||
}
|
||||
|
||||
changed = r->func(params, r);
|
||||
if (changed < 0)
|
||||
return changed;
|
||||
if (changed < 0) {
|
||||
err = changed;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the parameter is changed, notify it to the caller
|
||||
@ -430,7 +433,9 @@ retry:
|
||||
if (again)
|
||||
goto retry;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
kfree(rstamps);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
|
||||
|
@ -63,15 +63,18 @@ static int slave_update(struct link_slave *slave)
|
||||
struct snd_ctl_elem_value *uctl;
|
||||
int err, ch;
|
||||
|
||||
uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
if (!uctl)
|
||||
return -ENOMEM;
|
||||
uctl->id = slave->slave.id;
|
||||
err = slave->slave.get(&slave->slave, uctl);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
for (ch = 0; ch < slave->info.count; ch++)
|
||||
slave->vals[ch] = uctl->value.integer.value[ch];
|
||||
error:
|
||||
kfree(uctl);
|
||||
return 0;
|
||||
return err < 0 ? err : 0;
|
||||
}
|
||||
|
||||
/* get the slave ctl info and save the initial values */
|
||||
|
@ -296,6 +296,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
cable->pause |= stream;
|
||||
loopback_timer_stop(dpcm);
|
||||
spin_unlock(&cable->lock);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
loopback_active_notify(dpcm);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
@ -304,6 +306,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
cable->pause &= ~stream;
|
||||
loopback_timer_start(dpcm);
|
||||
spin_unlock(&cable->lock);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
loopback_active_notify(dpcm);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -892,9 +896,11 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol,
|
||||
[kcontrol->id.subdevice][kcontrol->id.device ^ 1];
|
||||
unsigned int val = 0;
|
||||
|
||||
if (cable != NULL)
|
||||
val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
|
||||
1 : 0;
|
||||
if (cable != NULL) {
|
||||
unsigned int running = cable->running ^ cable->pause;
|
||||
|
||||
val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0;
|
||||
}
|
||||
ucontrol->value.integer.value[0] = val;
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
@ -1064,3 +1065,37 @@ bool snd_hdac_check_power_state(struct hdac_device *hdac,
|
||||
return (state == target_state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_check_power_state);
|
||||
/**
|
||||
* snd_hdac_sync_power_state - wait until actual power state matches
|
||||
* with the target state
|
||||
*
|
||||
* @hdac: the HDAC device
|
||||
* @nid: NID to send the command
|
||||
* @target_state: target state to check for
|
||||
*
|
||||
* Return power state or PS_ERROR if codec rejects GET verb.
|
||||
*/
|
||||
unsigned int snd_hdac_sync_power_state(struct hdac_device *codec,
|
||||
hda_nid_t nid, unsigned int power_state)
|
||||
{
|
||||
unsigned long end_time = jiffies + msecs_to_jiffies(500);
|
||||
unsigned int state, actual_state, count;
|
||||
|
||||
for (count = 0; count < 500; count++) {
|
||||
state = snd_hdac_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_POWER_STATE, 0);
|
||||
if (state & AC_PWRST_ERROR) {
|
||||
msleep(20);
|
||||
break;
|
||||
}
|
||||
actual_state = (state >> 4) & 0x0f;
|
||||
if (actual_state == power_state)
|
||||
break;
|
||||
if (time_after_eq(jiffies, end_time))
|
||||
break;
|
||||
/* wait until the codec reachs to the target state */
|
||||
msleep(1);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_sync_power_state);
|
||||
|
@ -736,8 +736,7 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
|
||||
static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct echoaudio *chip = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct audiopipe *pipe = runtime->private_data;
|
||||
struct audiopipe *pipe;
|
||||
int i, err;
|
||||
u32 channelmask = 0;
|
||||
struct snd_pcm_substream *s;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
@ -1272,12 +1273,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
|
||||
release_firmware(emu->dock_fw);
|
||||
if (emu->irq >= 0)
|
||||
free_irq(emu->irq, emu);
|
||||
/* remove reserved page */
|
||||
if (emu->reserved_page) {
|
||||
snd_emu10k1_synth_free(emu,
|
||||
(struct snd_util_memblk *)emu->reserved_page);
|
||||
emu->reserved_page = NULL;
|
||||
}
|
||||
snd_util_memhdr_free(emu->memhdr);
|
||||
if (emu->silent_page.area)
|
||||
snd_dma_free_pages(&emu->silent_page);
|
||||
@ -1764,6 +1759,38 @@ static struct snd_emu_chip_details emu_chip_details[] = {
|
||||
{ } /* terminator */
|
||||
};
|
||||
|
||||
/*
|
||||
* The chip (at least the Audigy 2 CA0102 chip, but most likely others, too)
|
||||
* has a problem that from time to time it likes to do few DMA reads a bit
|
||||
* beyond its normal allocation and gets very confused if these reads get
|
||||
* blocked by a IOMMU.
|
||||
*
|
||||
* This behaviour has been observed for the first (reserved) page
|
||||
* (for which it happens multiple times at every playback), often for various
|
||||
* synth pages and sometimes for PCM playback buffers and the page table
|
||||
* memory itself.
|
||||
*
|
||||
* As a workaround let's widen these DMA allocations by an extra page if we
|
||||
* detect that the device is behind a non-passthrough IOMMU.
|
||||
*/
|
||||
static void snd_emu10k1_detect_iommu(struct snd_emu10k1 *emu)
|
||||
{
|
||||
struct iommu_domain *domain;
|
||||
|
||||
emu->iommu_workaround = false;
|
||||
|
||||
if (!iommu_present(emu->card->dev->bus))
|
||||
return;
|
||||
|
||||
domain = iommu_get_domain_for_dev(emu->card->dev);
|
||||
if (domain && domain->type == IOMMU_DOMAIN_IDENTITY)
|
||||
return;
|
||||
|
||||
dev_notice(emu->card->dev,
|
||||
"non-passthrough IOMMU detected, widening DMA allocations");
|
||||
emu->iommu_workaround = true;
|
||||
}
|
||||
|
||||
int snd_emu10k1_create(struct snd_card *card,
|
||||
struct pci_dev *pci,
|
||||
unsigned short extin_mask,
|
||||
@ -1776,6 +1803,7 @@ int snd_emu10k1_create(struct snd_card *card,
|
||||
struct snd_emu10k1 *emu;
|
||||
int idx, err;
|
||||
int is_audigy;
|
||||
size_t page_table_size;
|
||||
unsigned int silent_page;
|
||||
const struct snd_emu_chip_details *c;
|
||||
static struct snd_device_ops ops = {
|
||||
@ -1873,12 +1901,13 @@ int snd_emu10k1_create(struct snd_card *card,
|
||||
|
||||
is_audigy = emu->audigy = c->emu10k2_chip;
|
||||
|
||||
snd_emu10k1_detect_iommu(emu);
|
||||
|
||||
/* set addressing mode */
|
||||
emu->address_mode = is_audigy ? 0 : 1;
|
||||
/* set the DMA transfer mask */
|
||||
emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK;
|
||||
if (dma_set_mask(&pci->dev, emu->dma_mask) < 0 ||
|
||||
dma_set_coherent_mask(&pci->dev, emu->dma_mask) < 0) {
|
||||
if (dma_set_mask_and_coherent(&pci->dev, emu->dma_mask) < 0) {
|
||||
dev_err(card->dev,
|
||||
"architecture does not support PCI busmaster DMA with mask 0x%lx\n",
|
||||
emu->dma_mask);
|
||||
@ -1900,11 +1929,17 @@ int snd_emu10k1_create(struct snd_card *card,
|
||||
emu->port = pci_resource_start(pci, 0);
|
||||
|
||||
emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
(emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) {
|
||||
|
||||
page_table_size = sizeof(u32) * (emu->address_mode ? MAXPAGES1 :
|
||||
MAXPAGES0);
|
||||
if (snd_emu10k1_alloc_pages_maybe_wider(emu, page_table_size,
|
||||
&emu->ptb_pages) < 0) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
dev_dbg(card->dev, "page table address range is %.8lx:%.8lx\n",
|
||||
(unsigned long)emu->ptb_pages.addr,
|
||||
(unsigned long)(emu->ptb_pages.addr + emu->ptb_pages.bytes));
|
||||
|
||||
emu->page_ptr_table = vmalloc(emu->max_cache_pages * sizeof(void *));
|
||||
emu->page_addr_table = vmalloc(emu->max_cache_pages *
|
||||
@ -1914,11 +1949,16 @@ int snd_emu10k1_create(struct snd_card *card,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
EMUPAGESIZE, &emu->silent_page) < 0) {
|
||||
if (snd_emu10k1_alloc_pages_maybe_wider(emu, EMUPAGESIZE,
|
||||
&emu->silent_page) < 0) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
dev_dbg(card->dev, "silent page range is %.8lx:%.8lx\n",
|
||||
(unsigned long)emu->silent_page.addr,
|
||||
(unsigned long)(emu->silent_page.addr +
|
||||
emu->silent_page.bytes));
|
||||
|
||||
emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE);
|
||||
if (emu->memhdr == NULL) {
|
||||
err = -ENOMEM;
|
||||
@ -1993,13 +2033,8 @@ int snd_emu10k1_create(struct snd_card *card,
|
||||
SPCS_GENERATIONSTATUS | 0x00001200 |
|
||||
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
|
||||
|
||||
emu->reserved_page = (struct snd_emu10k1_memblk *)
|
||||
snd_emu10k1_synth_alloc(emu, 4096);
|
||||
if (emu->reserved_page)
|
||||
emu->reserved_page->map_locked = 1;
|
||||
|
||||
/* Clear silent pages and set up pointers */
|
||||
memset(emu->silent_page.area, 0, PAGE_SIZE);
|
||||
memset(emu->silent_page.area, 0, emu->silent_page.bytes);
|
||||
silent_page = emu->silent_page.addr << emu->address_mode;
|
||||
for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++)
|
||||
((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);
|
||||
|
@ -411,12 +411,20 @@ static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_emu10k1_pcm *epcm = runtime->private_data;
|
||||
size_t alloc_size;
|
||||
int err;
|
||||
|
||||
if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
|
||||
return err;
|
||||
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
|
||||
|
||||
alloc_size = params_buffer_bytes(hw_params);
|
||||
if (emu->iommu_workaround)
|
||||
alloc_size += EMUPAGESIZE;
|
||||
err = snd_pcm_lib_malloc_pages(substream, alloc_size);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (emu->iommu_workaround && runtime->dma_bytes >= EMUPAGESIZE)
|
||||
runtime->dma_bytes -= EMUPAGESIZE;
|
||||
if (err > 0) { /* change */
|
||||
int mapped;
|
||||
if (epcm->memblk != NULL)
|
||||
|
@ -34,7 +34,10 @@
|
||||
* aligned pages in others
|
||||
*/
|
||||
#define __set_ptb_entry(emu,page,addr) \
|
||||
(((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
|
||||
(((__le32 *)(emu)->ptb_pages.area)[page] = \
|
||||
cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
|
||||
#define __get_ptb_entry(emu, page) \
|
||||
(le32_to_cpu(((__le32 *)(emu)->ptb_pages.area)[page]))
|
||||
|
||||
#define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE)
|
||||
#define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES)
|
||||
@ -44,8 +47,7 @@
|
||||
/* get offset address from aligned page */
|
||||
#define aligned_page_offset(page) ((page) << PAGE_SHIFT)
|
||||
|
||||
#if PAGE_SIZE == 4096
|
||||
/* page size == EMUPAGESIZE */
|
||||
#if PAGE_SIZE == EMUPAGESIZE && !IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
|
||||
/* fill PTB entrie(s) corresponding to page with addr */
|
||||
#define set_ptb_entry(emu,page,addr) __set_ptb_entry(emu,page,addr)
|
||||
/* fill PTB entrie(s) corresponding to page with silence pointer */
|
||||
@ -58,6 +60,8 @@ static inline void set_ptb_entry(struct snd_emu10k1 *emu, int page, dma_addr_t a
|
||||
page *= UNIT_PAGES;
|
||||
for (i = 0; i < UNIT_PAGES; i++, page++) {
|
||||
__set_ptb_entry(emu, page, addr);
|
||||
dev_dbg(emu->card->dev, "mapped page %d to entry %.8x\n", page,
|
||||
(unsigned int)__get_ptb_entry(emu, page));
|
||||
addr += EMUPAGESIZE;
|
||||
}
|
||||
}
|
||||
@ -65,9 +69,12 @@ static inline void set_silent_ptb(struct snd_emu10k1 *emu, int page)
|
||||
{
|
||||
int i;
|
||||
page *= UNIT_PAGES;
|
||||
for (i = 0; i < UNIT_PAGES; i++, page++)
|
||||
for (i = 0; i < UNIT_PAGES; i++, page++) {
|
||||
/* do not increment ptr */
|
||||
__set_ptb_entry(emu, page, emu->silent_page.addr);
|
||||
dev_dbg(emu->card->dev, "mapped silent page %d to entry %.8x\n",
|
||||
page, (unsigned int)__get_ptb_entry(emu, page));
|
||||
}
|
||||
}
|
||||
#endif /* PAGE_SIZE */
|
||||
|
||||
@ -102,7 +109,7 @@ static void emu10k1_memblk_init(struct snd_emu10k1_memblk *blk)
|
||||
*/
|
||||
static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct list_head **nextp)
|
||||
{
|
||||
int page = 0, found_page = -ENOMEM;
|
||||
int page = 1, found_page = -ENOMEM;
|
||||
int max_size = npages;
|
||||
int size;
|
||||
struct list_head *candidate = &emu->mapped_link_head;
|
||||
@ -147,6 +154,10 @@ static int map_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
|
||||
page = search_empty_map_area(emu, blk->pages, &next);
|
||||
if (page < 0) /* not found */
|
||||
return page;
|
||||
if (page == 0) {
|
||||
dev_err(emu->card->dev, "trying to map zero (reserved) page\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* insert this block in the proper position of mapped list */
|
||||
list_add_tail(&blk->mapped_link, next);
|
||||
/* append this as a newest block in order list */
|
||||
@ -177,7 +188,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
|
||||
q = get_emu10k1_memblk(p, mapped_link);
|
||||
start_page = q->mapped_page + q->pages;
|
||||
} else
|
||||
start_page = 0;
|
||||
start_page = 1;
|
||||
if ((p = blk->mapped_link.next) != &emu->mapped_link_head) {
|
||||
q = get_emu10k1_memblk(p, mapped_link);
|
||||
end_page = q->mapped_page;
|
||||
@ -366,6 +377,33 @@ int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk)
|
||||
return snd_emu10k1_synth_free(emu, blk);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate DMA pages, widening the allocation if necessary
|
||||
*
|
||||
* See the comment above snd_emu10k1_detect_iommu() in emu10k1_main.c why
|
||||
* this might be needed.
|
||||
*
|
||||
* If you modify this function check whether __synth_free_pages() also needs
|
||||
* changes.
|
||||
*/
|
||||
int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
|
||||
struct snd_dma_buffer *dmab)
|
||||
{
|
||||
if (emu->iommu_workaround) {
|
||||
size_t npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
size_t size_real = npages * PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* The device has been observed to accesses up to 256 extra
|
||||
* bytes, but use 1k to be safe.
|
||||
*/
|
||||
if (size_real < size + 1024)
|
||||
size += PAGE_SIZE;
|
||||
}
|
||||
|
||||
return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
|
||||
snd_dma_pci_data(emu->pci), size, dmab);
|
||||
}
|
||||
|
||||
/*
|
||||
* memory allocation using multiple pages (for synth)
|
||||
@ -450,10 +488,27 @@ static void get_single_page_range(struct snd_util_memhdr *hdr,
|
||||
static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
|
||||
int last_page)
|
||||
{
|
||||
struct snd_dma_buffer dmab;
|
||||
int page;
|
||||
|
||||
dmab.dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
dmab.dev.dev = snd_dma_pci_data(emu->pci);
|
||||
|
||||
for (page = first_page; page <= last_page; page++) {
|
||||
free_page((unsigned long)emu->page_ptr_table[page]);
|
||||
if (emu->page_ptr_table[page] == NULL)
|
||||
continue;
|
||||
dmab.area = emu->page_ptr_table[page];
|
||||
dmab.addr = emu->page_addr_table[page];
|
||||
|
||||
/*
|
||||
* please keep me in sync with logic in
|
||||
* snd_emu10k1_alloc_pages_maybe_wider()
|
||||
*/
|
||||
dmab.bytes = PAGE_SIZE;
|
||||
if (emu->iommu_workaround)
|
||||
dmab.bytes *= 2;
|
||||
|
||||
snd_dma_free_pages(&dmab);
|
||||
emu->page_addr_table[page] = 0;
|
||||
emu->page_ptr_table[page] = NULL;
|
||||
}
|
||||
@ -465,30 +520,30 @@ static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
|
||||
static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
|
||||
{
|
||||
int page, first_page, last_page;
|
||||
struct snd_dma_buffer dmab;
|
||||
|
||||
emu10k1_memblk_init(blk);
|
||||
get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
|
||||
/* allocate kernel pages */
|
||||
for (page = first_page; page <= last_page; page++) {
|
||||
/* first try to allocate from <4GB zone */
|
||||
struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 |
|
||||
__GFP_NOWARN);
|
||||
if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) {
|
||||
if (p)
|
||||
__free_page(p);
|
||||
/* try to allocate from <16MB zone */
|
||||
p = alloc_page(GFP_ATOMIC | GFP_DMA |
|
||||
__GFP_NORETRY | /* no OOM-killer */
|
||||
__GFP_NOWARN);
|
||||
if (snd_emu10k1_alloc_pages_maybe_wider(emu, PAGE_SIZE,
|
||||
&dmab) < 0)
|
||||
goto __fail;
|
||||
if (!is_valid_page(emu, dmab.addr)) {
|
||||
snd_dma_free_pages(&dmab);
|
||||
goto __fail;
|
||||
}
|
||||
if (!p) {
|
||||
__synth_free_pages(emu, first_page, page - 1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
emu->page_addr_table[page] = page_to_phys(p);
|
||||
emu->page_ptr_table[page] = page_address(p);
|
||||
emu->page_addr_table[page] = dmab.addr;
|
||||
emu->page_ptr_table[page] = dmab.area;
|
||||
}
|
||||
return 0;
|
||||
|
||||
__fail:
|
||||
/* release allocated pages */
|
||||
last_page = page - 1;
|
||||
__synth_free_pages(emu, first_page, last_page);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,22 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Digital Beep Input Interface for HD-audio codec
|
||||
*
|
||||
* Author: Matt Ranostay <mranostay@gmail.com>
|
||||
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
|
||||
* Copyright (c) 2008 Embedded Alley Solutions Inc
|
||||
*
|
||||
* This driver 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 driver 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/input.h>
|
||||
|
@ -1,22 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Digital Beep Input Interface for HD-audio codec
|
||||
*
|
||||
* Author: Matt Ranostay <mranostay@gmail.com>
|
||||
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
|
||||
* Copyright (c) 2008 Embedded Alley Solutions Inc
|
||||
*
|
||||
* This driver 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 driver is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_HDA_BEEP_H
|
||||
|
@ -2702,32 +2702,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_set_power_to_all);
|
||||
|
||||
/*
|
||||
* wait until the state is reached, returns the current state
|
||||
*/
|
||||
static unsigned int hda_sync_power_state(struct hda_codec *codec,
|
||||
hda_nid_t fg,
|
||||
unsigned int power_state)
|
||||
{
|
||||
unsigned long end_time = jiffies + msecs_to_jiffies(500);
|
||||
unsigned int state, actual_state;
|
||||
|
||||
for (;;) {
|
||||
state = snd_hda_codec_read(codec, fg, 0,
|
||||
AC_VERB_GET_POWER_STATE, 0);
|
||||
if (state & AC_PWRST_ERROR)
|
||||
break;
|
||||
actual_state = (state >> 4) & 0x0f;
|
||||
if (actual_state == power_state)
|
||||
break;
|
||||
if (time_after_eq(jiffies, end_time))
|
||||
break;
|
||||
/* wait until the codec reachs to the target state */
|
||||
msleep(1);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_codec_eapd_power_filter - A power filter callback for EAPD
|
||||
* @codec: the HDA codec
|
||||
@ -2790,7 +2764,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
|
||||
state);
|
||||
snd_hda_codec_set_power_to_all(codec, fg, power_state);
|
||||
}
|
||||
state = hda_sync_power_state(codec, fg, power_state);
|
||||
state = snd_hda_sync_power_state(codec, fg, power_state);
|
||||
if (!(state & AC_PWRST_ERROR))
|
||||
break;
|
||||
}
|
||||
|
@ -2447,6 +2447,9 @@ static const struct pci_device_id azx_ids[] = {
|
||||
/* Cannonlake */
|
||||
{ PCI_DEVICE(0x8086, 0x9dc8),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
/* Icelake */
|
||||
{ PCI_DEVICE(0x8086, 0x34c8),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
/* Broxton-P(Apollolake) */
|
||||
{ PCI_DEVICE(0x8086, 0x5a98),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
|
||||
|
@ -622,7 +622,11 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
|
||||
{
|
||||
return snd_hdac_check_power_state(&codec->core, nid, target_state);
|
||||
}
|
||||
|
||||
static inline bool snd_hda_sync_power_state(struct hda_codec *codec,
|
||||
hda_nid_t nid, unsigned int target_state)
|
||||
{
|
||||
return snd_hdac_sync_power_state(&codec->core, nid, target_state);
|
||||
}
|
||||
unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
|
||||
hda_nid_t nid,
|
||||
unsigned int power_state);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
@ -425,10 +426,9 @@ DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1);
|
||||
static struct snd_kcontrol *ctl_find(struct snd_card *card,
|
||||
const char *name)
|
||||
{
|
||||
struct snd_ctl_elem_id sid;
|
||||
memset(&sid, 0, sizeof(sid));
|
||||
/* FIXME: strcpy is bad. */
|
||||
strcpy(sid.name, name);
|
||||
struct snd_ctl_elem_id sid = {0};
|
||||
|
||||
strlcpy(sid.name, name, sizeof(sid.name));
|
||||
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
return snd_ctl_find_id(card, &sid);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/info.h>
|
||||
@ -785,10 +786,9 @@ DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1);
|
||||
static struct snd_kcontrol *ctl_find(struct snd_card *card,
|
||||
const char *name)
|
||||
{
|
||||
struct snd_ctl_elem_id sid;
|
||||
memset(&sid, 0, sizeof(sid));
|
||||
/* FIXME: strcpy is bad. */
|
||||
strcpy(sid.name, name);
|
||||
struct snd_ctl_elem_id sid = {0};
|
||||
|
||||
strlcpy(sid.name, name, sizeof(sid.name));
|
||||
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
return snd_ctl_find_id(card, &sid);
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ source "sound/soc/amd/Kconfig"
|
||||
source "sound/soc/atmel/Kconfig"
|
||||
source "sound/soc/au1x/Kconfig"
|
||||
source "sound/soc/bcm/Kconfig"
|
||||
source "sound/soc/blackfin/Kconfig"
|
||||
source "sound/soc/cirrus/Kconfig"
|
||||
source "sound/soc/davinci/Kconfig"
|
||||
source "sound/soc/dwc/Kconfig"
|
||||
|
@ -29,7 +29,6 @@ obj-$(CONFIG_SND_SOC) += amd/
|
||||
obj-$(CONFIG_SND_SOC) += atmel/
|
||||
obj-$(CONFIG_SND_SOC) += au1x/
|
||||
obj-$(CONFIG_SND_SOC) += bcm/
|
||||
obj-$(CONFIG_SND_SOC) += blackfin/
|
||||
obj-$(CONFIG_SND_SOC) += cirrus/
|
||||
obj-$(CONFIG_SND_SOC) += davinci/
|
||||
obj-$(CONFIG_SND_SOC) += dwc/
|
||||
|
@ -3,6 +3,15 @@ config SND_SOC_AMD_ACP
|
||||
help
|
||||
This option enables ACP DMA support on AMD platform.
|
||||
|
||||
config SND_SOC_AMD_CZ_DA7219MX98357_MACH
|
||||
tristate "AMD CZ support for DA7219 and MAX9835"
|
||||
select SND_SOC_DA7219
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_ADAU7002
|
||||
depends on SND_SOC_AMD_ACP && I2C
|
||||
help
|
||||
This option enables machine driver for DA7219 and MAX9835.
|
||||
|
||||
config SND_SOC_AMD_CZ_RT5645_MACH
|
||||
tristate "AMD CZ support for RT5645"
|
||||
select SND_SOC_RT5645
|
||||
|
@ -1,5 +1,7 @@
|
||||
acp_audio_dma-objs := acp-pcm-dma.o
|
||||
snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
|
||||
snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
|
||||
|
276
sound/soc/amd/acp-da7219-max98357a.c
Normal file
276
sound/soc/amd/acp-da7219-max98357a.c
Normal file
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec
|
||||
*
|
||||
* Copyright 2017 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/jack.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "../codecs/da7219.h"
|
||||
#include "../codecs/da7219-aad.h"
|
||||
|
||||
#define CZ_PLAT_CLK 24000000
|
||||
#define MCLK_RATE 24576000
|
||||
#define DUAL_CHANNEL 2
|
||||
|
||||
static struct snd_soc_jack cz_jack;
|
||||
struct clk *da7219_dai_clk;
|
||||
|
||||
static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
|
||||
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK,
|
||||
CZ_PLAT_CLK, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
|
||||
CZ_PLAT_CLK, MCLK_RATE);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
|
||||
|
||||
ret = snd_soc_card_jack_new(card, "Headset Jack",
|
||||
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3,
|
||||
&cz_jack, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(card->dev, "HP jack creation failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
da7219_aad_jack_det(component, &cz_jack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
int ret = 0;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
||||
ret = clk_prepare_enable(da7219_dai_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't enable master clock %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cz_da7219_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
clk_disable_unprepare(da7219_dai_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const unsigned int channels[] = {
|
||||
DUAL_CHANNEL,
|
||||
};
|
||||
|
||||
static const unsigned int rates[] = {
|
||||
48000,
|
||||
};
|
||||
|
||||
static const struct snd_pcm_hw_constraint_list constraints_rates = {
|
||||
.count = ARRAY_SIZE(rates),
|
||||
.list = rates,
|
||||
.mask = 0,
|
||||
};
|
||||
|
||||
static const struct snd_pcm_hw_constraint_list constraints_channels = {
|
||||
.count = ARRAY_SIZE(channels),
|
||||
.list = channels,
|
||||
.mask = 0,
|
||||
};
|
||||
|
||||
static int cz_fe_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops cz_da7219_cap_ops = {
|
||||
.hw_params = cz_da7219_hw_params,
|
||||
.hw_free = cz_da7219_hw_free,
|
||||
.startup = cz_fe_startup,
|
||||
};
|
||||
|
||||
static struct snd_soc_ops cz_max_play_ops = {
|
||||
.hw_params = cz_da7219_hw_params,
|
||||
.hw_free = cz_da7219_hw_free,
|
||||
};
|
||||
|
||||
static struct snd_soc_ops cz_dmic_cap_ops = {
|
||||
.hw_params = cz_da7219_hw_params,
|
||||
.hw_free = cz_da7219_hw_free,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
||||
{
|
||||
.name = "amd-da7219-play-cap",
|
||||
.stream_name = "Playback and Capture",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.3.auto",
|
||||
.codec_dai_name = "da7219-hifi",
|
||||
.codec_name = "i2c-DLGS7219:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.init = cz_da7219_init,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cz_da7219_cap_ops,
|
||||
},
|
||||
{
|
||||
.name = "amd-max98357-play",
|
||||
.stream_name = "HiFi Playback",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.1.auto",
|
||||
.codec_dai_name = "HiFi",
|
||||
.codec_name = "MX98357A:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.dpcm_playback = 1,
|
||||
.ops = &cz_max_play_ops,
|
||||
},
|
||||
{
|
||||
.name = "dmic",
|
||||
.stream_name = "DMIC Capture",
|
||||
.platform_name = "acp_audio_dma.0.auto",
|
||||
.cpu_dai_name = "designware-i2s.2.auto",
|
||||
.codec_dai_name = "adau7002-hifi",
|
||||
.codec_name = "ADAU7002:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cz_dmic_cap_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cz_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphones", NULL),
|
||||
SND_SOC_DAPM_SPK("Speakers", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cz_audio_route[] = {
|
||||
{"Headphones", NULL, "HPL"},
|
||||
{"Headphones", NULL, "HPR"},
|
||||
{"MIC", NULL, "Headset Mic"},
|
||||
{"Speakers", NULL, "Speaker"},
|
||||
{"PDM_DAT", NULL, "Int Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new cz_mc_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphones"),
|
||||
SOC_DAPM_PIN_SWITCH("Speakers"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Int Mic"),
|
||||
};
|
||||
|
||||
static struct snd_soc_card cz_card = {
|
||||
.name = "acpd7219m98357",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = cz_dai_7219_98357,
|
||||
.num_links = ARRAY_SIZE(cz_dai_7219_98357),
|
||||
.dapm_widgets = cz_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cz_widgets),
|
||||
.dapm_routes = cz_audio_route,
|
||||
.num_dapm_routes = ARRAY_SIZE(cz_audio_route),
|
||||
.controls = cz_mc_controls,
|
||||
.num_controls = ARRAY_SIZE(cz_mc_controls),
|
||||
};
|
||||
|
||||
static int cz_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_card *card;
|
||||
|
||||
card = &cz_card;
|
||||
cz_card.dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, card);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"devm_snd_soc_register_card(%s) failed: %d\n",
|
||||
cz_card.name, ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id cz_audio_acpi_match[] = {
|
||||
{ "AMD7219", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
|
||||
|
||||
static struct platform_driver cz_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "cz-da7219-max98357a",
|
||||
.acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = cz_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(cz_pcm_driver);
|
||||
|
||||
MODULE_AUTHOR("akshu.agrawal@amd.com");
|
||||
MODULE_DESCRIPTION("DA7219 & MAX98357A audio support");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -23,6 +23,8 @@
|
||||
#include <drm/amd_asic_type.h>
|
||||
#include "acp.h"
|
||||
|
||||
#define DRV_NAME "acp_audio_dma"
|
||||
|
||||
#define PLAYBACK_MIN_NUM_PERIODS 2
|
||||
#define PLAYBACK_MAX_NUM_PERIODS 2
|
||||
#define PLAYBACK_MAX_PERIOD_SIZE 16384
|
||||
@ -182,19 +184,18 @@ static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
|
||||
* system memory <-> ACP SRAM
|
||||
*/
|
||||
static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
|
||||
u32 size, int direction,
|
||||
u32 pte_offset, u32 asic_type)
|
||||
u32 size, int direction, u32 pte_offset,
|
||||
u16 ch, u32 sram_bank,
|
||||
u16 dma_dscr_idx, u32 asic_type)
|
||||
{
|
||||
u16 i;
|
||||
u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
|
||||
acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
|
||||
|
||||
for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
|
||||
dmadscr[i].xfer_val = 0;
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i;
|
||||
dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS
|
||||
+ (i * (size/2));
|
||||
dma_dscr_idx = dma_dscr_idx + i;
|
||||
dmadscr[i].dest = sram_bank + (i * (size/2));
|
||||
dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
|
||||
+ (pte_offset * SZ_4K) + (i * (size/2));
|
||||
switch (asic_type) {
|
||||
@ -209,25 +210,19 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
|
||||
(size / 2);
|
||||
}
|
||||
} else {
|
||||
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
|
||||
dma_dscr_idx = dma_dscr_idx + i;
|
||||
dmadscr[i].src = sram_bank + (i * (size/2));
|
||||
dmadscr[i].dest =
|
||||
ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
|
||||
(pte_offset * SZ_4K) + (i * (size/2));
|
||||
switch (asic_type) {
|
||||
case CHIP_STONEY:
|
||||
dmadscr[i].src = ACP_SHARED_RAM_BANK_3_ADDRESS +
|
||||
(i * (size/2));
|
||||
dmadscr[i].dest =
|
||||
ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
|
||||
(pte_offset * SZ_4K) + (i * (size/2));
|
||||
dmadscr[i].xfer_val |=
|
||||
BIT(22) |
|
||||
(ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC << 16) |
|
||||
(size / 2);
|
||||
break;
|
||||
default:
|
||||
dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
|
||||
(i * (size/2));
|
||||
dmadscr[i].dest =
|
||||
ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
|
||||
(pte_offset * SZ_4K) + (i * (size/2));
|
||||
dmadscr[i].xfer_val |=
|
||||
BIT(22) |
|
||||
(ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
|
||||
@ -237,72 +232,49 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
|
||||
config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
|
||||
&dmadscr[i]);
|
||||
}
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM,
|
||||
PLAYBACK_START_DMA_DESCR_CH12,
|
||||
NUM_DSCRS_PER_CHANNEL,
|
||||
ACP_DMA_PRIORITY_LEVEL_NORMAL);
|
||||
else
|
||||
config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM,
|
||||
CAPTURE_START_DMA_DESCR_CH14,
|
||||
NUM_DSCRS_PER_CHANNEL,
|
||||
ACP_DMA_PRIORITY_LEVEL_NORMAL);
|
||||
config_acp_dma_channel(acp_mmio, ch,
|
||||
dma_dscr_idx - 1,
|
||||
NUM_DSCRS_PER_CHANNEL,
|
||||
ACP_DMA_PRIORITY_LEVEL_NORMAL);
|
||||
}
|
||||
|
||||
/* Initialize the DMA descriptor information for transfer between
|
||||
* ACP SRAM <-> I2S
|
||||
*/
|
||||
static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
|
||||
u32 size, int direction,
|
||||
u32 asic_type)
|
||||
static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
|
||||
int direction, u32 sram_bank,
|
||||
u16 destination, u16 ch,
|
||||
u16 dma_dscr_idx, u32 asic_type)
|
||||
{
|
||||
|
||||
u16 i;
|
||||
u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
|
||||
acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
|
||||
|
||||
for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
|
||||
dmadscr[i].xfer_val = 0;
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i;
|
||||
dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS +
|
||||
(i * (size/2));
|
||||
dma_dscr_idx = dma_dscr_idx + i;
|
||||
dmadscr[i].src = sram_bank + (i * (size/2));
|
||||
/* dmadscr[i].dest is unused by hardware. */
|
||||
dmadscr[i].dest = 0;
|
||||
dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) |
|
||||
dmadscr[i].xfer_val |= BIT(22) | (destination << 16) |
|
||||
(size / 2);
|
||||
} else {
|
||||
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
|
||||
dma_dscr_idx = dma_dscr_idx + i;
|
||||
/* dmadscr[i].src is unused by hardware. */
|
||||
dmadscr[i].src = 0;
|
||||
switch (asic_type) {
|
||||
case CHIP_STONEY:
|
||||
dmadscr[i].dest =
|
||||
ACP_SHARED_RAM_BANK_3_ADDRESS +
|
||||
(i * (size / 2));
|
||||
break;
|
||||
default:
|
||||
dmadscr[i].dest =
|
||||
ACP_SHARED_RAM_BANK_5_ADDRESS +
|
||||
(i * (size / 2));
|
||||
}
|
||||
dmadscr[i].dest =
|
||||
sram_bank + (i * (size / 2));
|
||||
dmadscr[i].xfer_val |= BIT(22) |
|
||||
(FROM_ACP_I2S_1 << 16) | (size / 2);
|
||||
(destination << 16) | (size / 2);
|
||||
}
|
||||
config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
|
||||
&dmadscr[i]);
|
||||
}
|
||||
/* Configure the DMA channel with the above descriptore */
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
|
||||
PLAYBACK_START_DMA_DESCR_CH13,
|
||||
NUM_DSCRS_PER_CHANNEL,
|
||||
ACP_DMA_PRIORITY_LEVEL_NORMAL);
|
||||
else
|
||||
config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
|
||||
CAPTURE_START_DMA_DESCR_CH15,
|
||||
NUM_DSCRS_PER_CHANNEL,
|
||||
ACP_DMA_PRIORITY_LEVEL_NORMAL);
|
||||
config_acp_dma_channel(acp_mmio, ch, dma_dscr_idx - 1,
|
||||
NUM_DSCRS_PER_CHANNEL,
|
||||
ACP_DMA_PRIORITY_LEVEL_NORMAL);
|
||||
}
|
||||
|
||||
/* Create page table entries in ACP SRAM for the allocated memory */
|
||||
@ -344,23 +316,51 @@ static void config_acp_dma(void __iomem *acp_mmio,
|
||||
struct audio_substream_data *audio_config,
|
||||
u32 asic_type)
|
||||
{
|
||||
u32 pte_offset;
|
||||
u32 pte_offset, sram_bank;
|
||||
u16 ch1, ch2, destination, dma_dscr_idx;
|
||||
|
||||
if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
pte_offset = ACP_PLAYBACK_PTE_OFFSET;
|
||||
else
|
||||
ch1 = SYSRAM_TO_ACP_CH_NUM;
|
||||
ch2 = ACP_TO_I2S_DMA_CH_NUM;
|
||||
sram_bank = ACP_SHARED_RAM_BANK_1_ADDRESS;
|
||||
destination = TO_ACP_I2S_1;
|
||||
|
||||
} else {
|
||||
pte_offset = ACP_CAPTURE_PTE_OFFSET;
|
||||
ch1 = SYSRAM_TO_ACP_CH_NUM;
|
||||
ch2 = ACP_TO_I2S_DMA_CH_NUM;
|
||||
switch (asic_type) {
|
||||
case CHIP_STONEY:
|
||||
sram_bank = ACP_SHARED_RAM_BANK_3_ADDRESS;
|
||||
break;
|
||||
default:
|
||||
sram_bank = ACP_SHARED_RAM_BANK_5_ADDRESS;
|
||||
}
|
||||
destination = FROM_ACP_I2S_1;
|
||||
}
|
||||
|
||||
acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages,
|
||||
pte_offset);
|
||||
if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
|
||||
else
|
||||
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
|
||||
|
||||
/* Configure System memory <-> ACP SRAM DMA descriptors */
|
||||
set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
|
||||
audio_config->direction, pte_offset, asic_type);
|
||||
audio_config->direction, pte_offset,
|
||||
ch1, sram_bank, dma_dscr_idx, asic_type);
|
||||
|
||||
if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
|
||||
else
|
||||
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15;
|
||||
/* Configure ACP SRAM <-> I2S DMA descriptors */
|
||||
set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
|
||||
audio_config->direction, asic_type);
|
||||
audio_config->direction, sram_bank,
|
||||
destination, ch2, dma_dscr_idx,
|
||||
asic_type);
|
||||
}
|
||||
|
||||
/* Start a given DMA channel transfer */
|
||||
@ -655,7 +655,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
|
||||
1, 0);
|
||||
acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
|
||||
|
||||
snd_pcm_period_elapsed(irq_data->play_stream);
|
||||
snd_pcm_period_elapsed(irq_data->play_i2ssp_stream);
|
||||
|
||||
acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16,
|
||||
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
||||
@ -678,7 +678,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
|
||||
|
||||
if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
|
||||
valid_irq = true;
|
||||
snd_pcm_period_elapsed(irq_data->capture_stream);
|
||||
snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
|
||||
acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
|
||||
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
||||
}
|
||||
@ -695,8 +695,8 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
|
||||
int ret = 0;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev);
|
||||
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
|
||||
struct audio_drv_data *intr_data = dev_get_drvdata(component->dev);
|
||||
struct audio_substream_data *adata =
|
||||
kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL);
|
||||
if (adata == NULL)
|
||||
@ -723,7 +723,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
|
||||
ret = snd_pcm_hw_constraint_integer(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0) {
|
||||
dev_err(prtd->platform->dev, "set integer constraint failed\n");
|
||||
dev_err(component->dev, "set integer constraint failed\n");
|
||||
kfree(adata);
|
||||
return ret;
|
||||
}
|
||||
@ -736,11 +736,11 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
|
||||
* This enablement is not required for another stream, if current
|
||||
* stream is not closed
|
||||
*/
|
||||
if (!intr_data->play_stream && !intr_data->capture_stream)
|
||||
if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream)
|
||||
acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
intr_data->play_stream = substream;
|
||||
intr_data->play_i2ssp_stream = substream;
|
||||
/* For Stoney, Memory gating is disabled,i.e SRAM Banks
|
||||
* won't be turned off. The default state for SRAM banks is ON.
|
||||
* Setting SRAM bank state code skipped for STONEY platform.
|
||||
@ -751,7 +751,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
|
||||
bank, true);
|
||||
}
|
||||
} else {
|
||||
intr_data->capture_stream = substream;
|
||||
intr_data->capture_i2ssp_stream = substream;
|
||||
if (intr_data->asic_type != CHIP_STONEY) {
|
||||
for (bank = 5; bank <= 8; bank++)
|
||||
acp_set_sram_bank_state(intr_data->acp_mmio,
|
||||
@ -772,7 +772,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct audio_substream_data *rtd;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
|
||||
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||
|
||||
runtime = substream->runtime;
|
||||
rtd = runtime->private_data;
|
||||
@ -859,11 +860,11 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
||||
bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (bytescount > rtd->renderbytescount)
|
||||
bytescount = bytescount - rtd->renderbytescount;
|
||||
if (bytescount > rtd->i2ssp_renderbytescount)
|
||||
bytescount = bytescount - rtd->i2ssp_renderbytescount;
|
||||
} else {
|
||||
if (bytescount > rtd->capturebytescount)
|
||||
bytescount = bytescount - rtd->capturebytescount;
|
||||
if (bytescount > rtd->i2ssp_capturebytescount)
|
||||
bytescount = bytescount - rtd->i2ssp_capturebytescount;
|
||||
}
|
||||
pos = do_div(bytescount, buffersize);
|
||||
return bytes_to_frames(runtime, pos);
|
||||
@ -909,6 +910,7 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct audio_substream_data *rtd = runtime->private_data;
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
|
||||
|
||||
if (!rtd)
|
||||
return -EINVAL;
|
||||
@ -919,14 +921,14 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
bytescount = acp_get_byte_count(rtd->acp_mmio,
|
||||
substream->stream);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (rtd->renderbytescount == 0)
|
||||
rtd->renderbytescount = bytescount;
|
||||
if (rtd->i2ssp_renderbytescount == 0)
|
||||
rtd->i2ssp_renderbytescount = bytescount;
|
||||
acp_dma_start(rtd->acp_mmio,
|
||||
SYSRAM_TO_ACP_CH_NUM, false);
|
||||
while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
|
||||
BIT(SYSRAM_TO_ACP_CH_NUM)) {
|
||||
if (!loops--) {
|
||||
dev_err(prtd->platform->dev,
|
||||
dev_err(component->dev,
|
||||
"acp dma start timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -937,8 +939,8 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
ACP_TO_I2S_DMA_CH_NUM, true);
|
||||
|
||||
} else {
|
||||
if (rtd->capturebytescount == 0)
|
||||
rtd->capturebytescount = bytescount;
|
||||
if (rtd->i2ssp_capturebytescount == 0)
|
||||
rtd->i2ssp_capturebytescount = bytescount;
|
||||
acp_dma_start(rtd->acp_mmio,
|
||||
I2S_TO_ACP_DMA_CH_NUM, true);
|
||||
}
|
||||
@ -953,13 +955,17 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
* completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM
|
||||
*/
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ret = acp_dma_stop(rtd->acp_mmio,
|
||||
SYSRAM_TO_ACP_CH_NUM);
|
||||
ret = acp_dma_stop(rtd->acp_mmio,
|
||||
ACP_TO_I2S_DMA_CH_NUM);
|
||||
rtd->renderbytescount = 0;
|
||||
rtd->i2ssp_renderbytescount = 0;
|
||||
} else {
|
||||
ret = acp_dma_stop(rtd->acp_mmio,
|
||||
I2S_TO_ACP_DMA_CH_NUM);
|
||||
rtd->capturebytescount = 0;
|
||||
ret = acp_dma_stop(rtd->acp_mmio,
|
||||
ACP_TO_SYSRAM_CH_NUM);
|
||||
rtd->i2ssp_capturebytescount = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -972,7 +978,8 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
int ret;
|
||||
struct audio_drv_data *adata = dev_get_drvdata(rtd->platform->dev);
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||
|
||||
switch (adata->asic_type) {
|
||||
case CHIP_STONEY:
|
||||
@ -989,7 +996,7 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
break;
|
||||
}
|
||||
if (ret < 0)
|
||||
dev_err(rtd->platform->dev,
|
||||
dev_err(component->dev,
|
||||
"buffer preallocation failer error:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -1000,12 +1007,13 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct audio_substream_data *rtd = runtime->private_data;
|
||||
struct snd_soc_pcm_runtime *prtd = substream->private_data;
|
||||
struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
|
||||
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
|
||||
|
||||
kfree(rtd);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
adata->play_stream = NULL;
|
||||
adata->play_i2ssp_stream = NULL;
|
||||
/* For Stoney, Memory gating is disabled,i.e SRAM Banks
|
||||
* won't be turned off. The default state for SRAM banks is ON.
|
||||
* Setting SRAM bank state code skipped for STONEY platform.
|
||||
@ -1017,7 +1025,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
|
||||
false);
|
||||
}
|
||||
} else {
|
||||
adata->capture_stream = NULL;
|
||||
adata->capture_i2ssp_stream = NULL;
|
||||
if (adata->asic_type != CHIP_STONEY) {
|
||||
for (bank = 5; bank <= 8; bank++)
|
||||
acp_set_sram_bank_state(adata->acp_mmio, bank,
|
||||
@ -1028,7 +1036,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
|
||||
/* Disable ACP irq, when the current stream is being closed and
|
||||
* another stream is also not active.
|
||||
*/
|
||||
if (!adata->play_stream && !adata->capture_stream)
|
||||
if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream)
|
||||
acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
|
||||
|
||||
return 0;
|
||||
@ -1046,7 +1054,8 @@ static const struct snd_pcm_ops acp_dma_ops = {
|
||||
.prepare = acp_dma_prepare,
|
||||
};
|
||||
|
||||
static struct snd_soc_platform_driver acp_asoc_platform = {
|
||||
static struct snd_soc_component_driver acp_asoc_platform = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &acp_dma_ops,
|
||||
.pcm_new = acp_dma_new,
|
||||
};
|
||||
@ -1078,8 +1087,9 @@ static int acp_audio_probe(struct platform_device *pdev)
|
||||
* and device doesn't generate any interrupts.
|
||||
*/
|
||||
|
||||
audio_drv_data->play_stream = NULL;
|
||||
audio_drv_data->capture_stream = NULL;
|
||||
audio_drv_data->play_i2ssp_stream = NULL;
|
||||
audio_drv_data->capture_i2ssp_stream = NULL;
|
||||
|
||||
audio_drv_data->asic_type = *pdata;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
@ -1104,7 +1114,8 @@ static int acp_audio_probe(struct platform_device *pdev)
|
||||
return status;
|
||||
}
|
||||
|
||||
status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
|
||||
status = devm_snd_soc_register_component(&pdev->dev,
|
||||
&acp_asoc_platform, NULL, 0);
|
||||
if (status != 0) {
|
||||
dev_err(&pdev->dev, "Fail to register ALSA platform device\n");
|
||||
return status;
|
||||
@ -1125,7 +1136,6 @@ static int acp_audio_remove(struct platform_device *pdev)
|
||||
status = acp_deinit(adata->acp_mmio);
|
||||
if (status)
|
||||
dev_err(&pdev->dev, "ACP Deinit failed status:%d\n", status);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
@ -1143,7 +1153,7 @@ static int acp_pcm_resume(struct device *dev)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (adata->play_stream && adata->play_stream->runtime) {
|
||||
if (adata->play_i2ssp_stream && adata->play_i2ssp_stream->runtime) {
|
||||
/* For Stoney, Memory gating is disabled,i.e SRAM Banks
|
||||
* won't be turned off. The default state for SRAM banks is ON.
|
||||
* Setting SRAM bank state code skipped for STONEY platform.
|
||||
@ -1154,17 +1164,17 @@ static int acp_pcm_resume(struct device *dev)
|
||||
true);
|
||||
}
|
||||
config_acp_dma(adata->acp_mmio,
|
||||
adata->play_stream->runtime->private_data,
|
||||
adata->play_i2ssp_stream->runtime->private_data,
|
||||
adata->asic_type);
|
||||
}
|
||||
if (adata->capture_stream && adata->capture_stream->runtime) {
|
||||
if (adata->capture_i2ssp_stream && adata->capture_i2ssp_stream->runtime) {
|
||||
if (adata->asic_type != CHIP_STONEY) {
|
||||
for (bank = 5; bank <= 8; bank++)
|
||||
acp_set_sram_bank_state(adata->acp_mmio, bank,
|
||||
true);
|
||||
}
|
||||
config_acp_dma(adata->acp_mmio,
|
||||
adata->capture_stream->runtime->private_data,
|
||||
adata->capture_i2ssp_stream->runtime->private_data,
|
||||
adata->asic_type);
|
||||
}
|
||||
acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
|
||||
|
@ -71,9 +71,9 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_component *codec;
|
||||
|
||||
codec = rtd->codec;
|
||||
codec = rtd->codec_dai->component;
|
||||
card = rtd->card;
|
||||
|
||||
ret = snd_soc_card_jack_new(card, "Headset Jack",
|
||||
|
@ -86,14 +86,14 @@ struct audio_substream_data {
|
||||
u16 num_of_pages;
|
||||
u16 direction;
|
||||
uint64_t size;
|
||||
u64 renderbytescount;
|
||||
u64 capturebytescount;
|
||||
u64 i2ssp_renderbytescount;
|
||||
u64 i2ssp_capturebytescount;
|
||||
void __iomem *acp_mmio;
|
||||
};
|
||||
|
||||
struct audio_drv_data {
|
||||
struct snd_pcm_substream *play_stream;
|
||||
struct snd_pcm_substream *capture_stream;
|
||||
struct snd_pcm_substream *play_i2ssp_stream;
|
||||
struct snd_pcm_substream *capture_i2ssp_stream;
|
||||
void __iomem *acp_mmio;
|
||||
u32 asic_type;
|
||||
};
|
||||
|
@ -32,6 +32,7 @@ struct atmel_classd {
|
||||
struct regmap *regmap;
|
||||
struct clk *pclk;
|
||||
struct clk *gclk;
|
||||
struct device *dev;
|
||||
int irq;
|
||||
const struct atmel_classd_pdata *pdata;
|
||||
};
|
||||
@ -165,7 +166,7 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream,
|
||||
struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
if (params_physical_width(params) != 16) {
|
||||
dev_err(rtd->platform->dev,
|
||||
dev_err(dd->dev,
|
||||
"only supports 16-bit audio data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -247,9 +248,9 @@ static const char * const pwm_type[] = {
|
||||
"Single ended", "Differential"
|
||||
};
|
||||
|
||||
static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
|
||||
static int atmel_classd_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
|
||||
struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
|
||||
const struct atmel_classd_pdata *pdata = dd->pdata;
|
||||
u32 mask, val;
|
||||
@ -283,16 +284,16 @@ static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
|
||||
default:
|
||||
val |= (CLASSD_MR_NOVR_VAL_10NS
|
||||
<< CLASSD_MR_NOVR_VAL_SHIFT);
|
||||
dev_warn(codec->dev,
|
||||
dev_warn(component->dev,
|
||||
"non-overlapping value %d is invalid, the default value 10 is specified\n",
|
||||
pdata->non_overlap_time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, CLASSD_MR, mask, val);
|
||||
snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
|
||||
|
||||
dev_info(codec->dev,
|
||||
dev_info(component->dev,
|
||||
"PWM modulation type is %s, non-overlapping is %s\n",
|
||||
pwm_type[pdata->pwm_type],
|
||||
pdata->non_overlap_enable?"enabled":"disabled");
|
||||
@ -300,21 +301,23 @@ static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_classd_codec_resume(struct snd_soc_codec *codec)
|
||||
static int atmel_classd_component_resume(struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
|
||||
struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
|
||||
|
||||
return regcache_sync(dd->regmap);
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_classd = {
|
||||
.probe = atmel_classd_codec_probe,
|
||||
.resume = atmel_classd_codec_resume,
|
||||
.component_driver = {
|
||||
.controls = atmel_classd_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(atmel_classd_snd_controls),
|
||||
},
|
||||
static struct snd_soc_component_driver soc_component_dev_classd = {
|
||||
.probe = atmel_classd_component_probe,
|
||||
.resume = atmel_classd_component_resume,
|
||||
.controls = atmel_classd_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(atmel_classd_snd_controls),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
/* codec dai component */
|
||||
@ -330,7 +333,7 @@ static int atmel_classd_codec_dai_startup(struct snd_pcm_substream *substream,
|
||||
static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
|
||||
int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
u32 mask, val;
|
||||
|
||||
mask = CLASSD_MR_LMUTE_MASK | CLASSD_MR_RMUTE_MASK;
|
||||
@ -340,7 +343,7 @@ static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
|
||||
else
|
||||
val = 0;
|
||||
|
||||
snd_soc_update_bits(codec, CLASSD_MR, mask, val);
|
||||
snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -379,7 +382,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
int fs;
|
||||
int i, best, best_val, cur_val, ret;
|
||||
u32 mask, val;
|
||||
@ -397,7 +400,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev,
|
||||
dev_dbg(component->dev,
|
||||
"Selected SAMPLE_RATE of %dHz, GCLK_RATE of %ldHz\n",
|
||||
sample_rates[best].rate, sample_rates[best].gclk_rate);
|
||||
|
||||
@ -411,7 +414,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
val = (sample_rates[best].dsp_clk << CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT)
|
||||
| (sample_rates[best].sample_rate << CLASSD_INTPMR_FRAME_SHIFT);
|
||||
|
||||
snd_soc_update_bits(codec, CLASSD_INTPMR, mask, val);
|
||||
snd_soc_component_update_bits(component, CLASSD_INTPMR, mask, val);
|
||||
|
||||
return clk_prepare_enable(dd->gclk);
|
||||
}
|
||||
@ -429,9 +432,9 @@ atmel_classd_codec_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *codec_dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
|
||||
snd_soc_update_bits(codec, CLASSD_MR,
|
||||
snd_soc_component_update_bits(component, CLASSD_MR,
|
||||
CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK,
|
||||
(CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT)
|
||||
|(CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT));
|
||||
@ -442,7 +445,7 @@ static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream,
|
||||
static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *codec_dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
u32 mask, val;
|
||||
|
||||
mask = CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK;
|
||||
@ -463,7 +466,7 @@ static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, CLASSD_MR, mask, val);
|
||||
snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -580,13 +583,11 @@ static int atmel_classd_probe(struct platform_device *pdev)
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
io_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(io_base)) {
|
||||
ret = PTR_ERR(io_base);
|
||||
dev_err(dev, "failed to remap register memory: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(io_base))
|
||||
return PTR_ERR(io_base);
|
||||
|
||||
dd->phy_base = res->start;
|
||||
dd->dev = dev;
|
||||
|
||||
dd->regmap = devm_regmap_init_mmio(dev, io_base,
|
||||
&atmel_classd_regmap_config);
|
||||
@ -612,10 +613,10 @@ static int atmel_classd_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(dev, &soc_codec_dev_classd,
|
||||
ret = devm_snd_soc_register_component(dev, &soc_component_dev_classd,
|
||||
&atmel_classd_codec_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not register codec: %d\n", ret);
|
||||
dev_err(dev, "could not register component: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -643,13 +644,11 @@ static int atmel_classd_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
unregister_codec:
|
||||
snd_soc_unregister_codec(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_classd_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -393,7 +393,7 @@ static const struct snd_pcm_ops atmel_pcm_ops = {
|
||||
.mmap = atmel_pcm_mmap,
|
||||
};
|
||||
|
||||
static struct snd_soc_platform_driver atmel_soc_platform = {
|
||||
static struct snd_soc_component_driver atmel_soc_platform = {
|
||||
.ops = &atmel_pcm_ops,
|
||||
.pcm_new = atmel_pcm_new,
|
||||
.pcm_free = atmel_pcm_free,
|
||||
@ -401,13 +401,13 @@ static struct snd_soc_platform_driver atmel_soc_platform = {
|
||||
|
||||
int atmel_pcm_pdc_platform_register(struct device *dev)
|
||||
{
|
||||
return snd_soc_register_platform(dev, &atmel_soc_platform);
|
||||
return devm_snd_soc_register_component(dev, &atmel_soc_platform,
|
||||
NULL, 0);
|
||||
}
|
||||
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);
|
||||
|
||||
|
@ -32,6 +32,7 @@ struct atmel_pdmic {
|
||||
struct regmap *regmap;
|
||||
struct clk *pclk;
|
||||
struct clk *gclk;
|
||||
struct device *dev;
|
||||
int irq;
|
||||
struct snd_pcm_substream *substream;
|
||||
const struct atmel_pdmic_pdata *pdata;
|
||||
@ -206,7 +207,7 @@ atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream,
|
||||
ret = snd_hwparams_to_dma_slave_config(substream, params,
|
||||
slave_config);
|
||||
if (ret) {
|
||||
dev_err(rtd->platform->dev,
|
||||
dev_err(dd->dev,
|
||||
"hw params to dma slave configure failed\n");
|
||||
return ret;
|
||||
}
|
||||
@ -288,14 +289,14 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
|
||||
static int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
unsigned int dgain_val, scale_val;
|
||||
int i;
|
||||
|
||||
dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
|
||||
dgain_val = (snd_soc_component_read32(component, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
|
||||
>> PDMIC_DSPR1_DGAIN_SHIFT;
|
||||
|
||||
scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
|
||||
scale_val = (snd_soc_component_read32(component, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
|
||||
>> PDMIC_DSPR0_SCALE_SHIFT;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) {
|
||||
@ -312,7 +313,7 @@ static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
int max = mc->max;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
@ -322,12 +323,12 @@ static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
|
||||
if (val > max)
|
||||
return -EINVAL;
|
||||
|
||||
ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
|
||||
ret = snd_soc_component_update_bits(component, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
|
||||
mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
|
||||
ret = snd_soc_component_update_bits(component, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
|
||||
mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -346,23 +347,25 @@ SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0,
|
||||
SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1),
|
||||
};
|
||||
|
||||
static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec)
|
||||
static int atmel_pdmic_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
|
||||
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
|
||||
snd_soc_component_update_bits(component, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
|
||||
(u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_pdmic = {
|
||||
.probe = atmel_pdmic_codec_probe,
|
||||
.component_driver = {
|
||||
.controls = atmel_pdmic_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls),
|
||||
},
|
||||
static struct snd_soc_component_driver soc_component_dev_pdmic = {
|
||||
.probe = atmel_pdmic_component_probe,
|
||||
.controls = atmel_pdmic_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
/* codec dai component */
|
||||
@ -375,7 +378,7 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
unsigned int rate_min = substream->runtime->hw.rate_min;
|
||||
unsigned int rate_max = substream->runtime->hw.rate_max;
|
||||
int fs = params_rate(params);
|
||||
@ -385,13 +388,13 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal;
|
||||
|
||||
if (params_channels(params) != 1) {
|
||||
dev_err(codec->dev,
|
||||
dev_err(component->dev,
|
||||
"only supports one channel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((fs < rate_min) || (fs > rate_max)) {
|
||||
dev_err(codec->dev,
|
||||
dev_err(component->dev,
|
||||
"sample rate is %dHz, min rate is %dHz, max rate is %dHz\n",
|
||||
fs, rate_min, rate_max);
|
||||
|
||||
@ -436,10 +439,10 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, PDMIC_MR,
|
||||
snd_soc_component_update_bits(component, PDMIC_MR,
|
||||
PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val);
|
||||
|
||||
snd_soc_update_bits(codec, PDMIC_DSPR0,
|
||||
snd_soc_component_update_bits(component, PDMIC_DSPR0,
|
||||
PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val);
|
||||
|
||||
return 0;
|
||||
@ -448,9 +451,9 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *codec_dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
|
||||
snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
|
||||
snd_soc_component_update_bits(component, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
|
||||
PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
|
||||
|
||||
return 0;
|
||||
@ -459,7 +462,7 @@ static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
|
||||
static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *codec_dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
u32 val;
|
||||
|
||||
switch (cmd) {
|
||||
@ -477,7 +480,7 @@ static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
|
||||
snd_soc_component_update_bits(component, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -596,6 +599,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dd->pdata = pdata;
|
||||
dd->dev = dev;
|
||||
|
||||
dd->irq = platform_get_irq(pdev, 0);
|
||||
if (dd->irq < 0) {
|
||||
@ -629,11 +633,8 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
io_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(io_base)) {
|
||||
ret = PTR_ERR(io_base);
|
||||
dev_err(dev, "failed to remap register memory: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(io_base))
|
||||
return PTR_ERR(io_base);
|
||||
|
||||
dd->phy_base = res->start;
|
||||
|
||||
@ -679,10 +680,10 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
|
||||
/* register codec and codec dai */
|
||||
atmel_pdmic_codec_dai.capture.rate_min = rate_min;
|
||||
atmel_pdmic_codec_dai.capture.rate_max = rate_max;
|
||||
ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic,
|
||||
ret = devm_snd_soc_register_component(dev, &soc_component_dev_pdmic,
|
||||
&atmel_pdmic_codec_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not register codec: %d\n", ret);
|
||||
dev_err(dev, "could not register component: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -710,13 +711,11 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
unregister_codec:
|
||||
snd_soc_unregister_codec(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_pdmic_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,8 @@
|
||||
|
||||
/*#define PCM_DEBUG*/
|
||||
|
||||
#define DRV_NAME "dbdma2"
|
||||
|
||||
#define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x)
|
||||
#ifdef PCM_DEBUG
|
||||
#define DBG MSG
|
||||
@ -187,8 +189,8 @@ out:
|
||||
static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
struct au1xpsc_audio_dmadata *pcd =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component);
|
||||
return &pcd[ss->stream];
|
||||
}
|
||||
|
||||
@ -327,7 +329,8 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
|
||||
/* au1xpsc audio platform */
|
||||
static struct snd_soc_platform_driver au1xpsc_soc_platform = {
|
||||
static struct snd_soc_component_driver au1xpsc_soc_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &au1xpsc_pcm_ops,
|
||||
.pcm_new = au1xpsc_pcm_new,
|
||||
};
|
||||
@ -344,8 +347,8 @@ static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, dmadata);
|
||||
|
||||
return devm_snd_soc_register_platform(&pdev->dev,
|
||||
&au1xpsc_soc_platform);
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&au1xpsc_soc_component, NULL, 0);
|
||||
}
|
||||
|
||||
static struct platform_driver au1xpsc_pcm_driver = {
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
#define DRV_NAME "au1x_dma"
|
||||
|
||||
struct pcm_period {
|
||||
u32 start;
|
||||
u32 relative_end; /* relative to start of buffer */
|
||||
@ -174,7 +176,8 @@ static const struct snd_pcm_hardware alchemy_pcm_hardware = {
|
||||
static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
return snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
return snd_soc_component_get_drvdata(component);
|
||||
}
|
||||
|
||||
static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss)
|
||||
@ -297,7 +300,8 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
|
||||
static struct snd_soc_component_driver alchemy_pcm_soc_component = {
|
||||
.name = DRV_NAME,
|
||||
.ops = &alchemy_pcm_ops,
|
||||
.pcm_new = alchemy_pcm_new,
|
||||
};
|
||||
@ -312,8 +316,8 @@ static int alchemy_pcm_drvprobe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
return devm_snd_soc_register_platform(&pdev->dev,
|
||||
&alchemy_pcm_soc_platform);
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&alchemy_pcm_soc_component, NULL, 0);
|
||||
}
|
||||
|
||||
static struct platform_driver alchemy_pcmdma_driver = {
|
||||
|
@ -820,7 +820,7 @@ static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_platform_driver cygnus_soc_platform = {
|
||||
static struct snd_soc_component_driver cygnus_soc_platform = {
|
||||
.ops = &cygnus_pcm_ops,
|
||||
.pcm_new = cygnus_dma_new,
|
||||
.pcm_free = cygnus_dma_free_dma_buffers,
|
||||
@ -840,7 +840,8 @@ int cygnus_soc_platform_register(struct device *dev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = snd_soc_register_platform(dev, &cygnus_soc_platform);
|
||||
rc = devm_snd_soc_register_component(dev, &cygnus_soc_platform,
|
||||
NULL, 0);
|
||||
if (rc) {
|
||||
dev_err(dev, "%s failed\n", __func__);
|
||||
return rc;
|
||||
@ -851,8 +852,6 @@ int cygnus_soc_platform_register(struct device *dev,
|
||||
|
||||
int cygnus_soc_platform_unregister(struct device *dev)
|
||||
{
|
||||
snd_soc_unregister_platform(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1281,7 +1281,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *child_node;
|
||||
struct resource *res = pdev->resource;
|
||||
struct resource *res;
|
||||
struct cygnus_audio *cygaud;
|
||||
int err = -EINVAL;
|
||||
int node_count;
|
||||
|
@ -1,205 +0,0 @@
|
||||
config SND_BF5XX_I2S
|
||||
tristate "SoC I2S Audio for the ADI Blackfin chip"
|
||||
depends on BLACKFIN
|
||||
select SND_BF5XX_SOC_SPORT if !BF60x
|
||||
select SND_BF6XX_SOC_SPORT if BF60x
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the Blackfin SPORT (synchronous serial ports) interface in I2S
|
||||
mode (supports single stereo In/Out).
|
||||
You will also need to select the audio interfaces to support below.
|
||||
|
||||
config SND_BF5XX_SOC_SSM2602
|
||||
tristate "SoC SSM2602 Audio Codec Add-On Card support"
|
||||
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
|
||||
select SND_BF5XX_SOC_I2S if !BF60x
|
||||
select SND_BF6XX_SOC_I2S if BF60x
|
||||
select SND_SOC_SSM2602_SPI if SPI_MASTER
|
||||
select SND_SOC_SSM2602_I2C if I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices
|
||||
SSM2602 Audio Codec Add-On Card.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1701
|
||||
tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1701
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1373
|
||||
tristate "Support for the EVAL-ADAU1373 board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1373
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1373
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that first ADAU1373 DAI is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1X61
|
||||
tristate "Support for the EVAL-ADAU1X61 board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1761_I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X61
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAU1X61 is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1X81
|
||||
tristate "Support for the EVAL-ADAU1X81 boards on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1781_I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X81
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAU1X81 is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAV80X
|
||||
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAV801 if SPI_MASTER
|
||||
select SND_SOC_ADAV803 if I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
|
||||
EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
|
||||
like the BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAV80X digital record and playback
|
||||
interfaces are connected to the first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_BF5XX_SOC_AD1836
|
||||
tristate "SoC AD1836 Audio support for BF5xx"
|
||||
depends on SND_BF5XX_I2S && SPI_MASTER
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_AD1836
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
|
||||
|
||||
config SND_BF5XX_SOC_AD193X
|
||||
tristate "SoC AD193X Audio support for Blackfin"
|
||||
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_AD193X_I2C if I2C
|
||||
select SND_SOC_AD193X_SPI if SPI_MASTER
|
||||
help
|
||||
Say Y if you want to add support for AD193X codec on Blackfin.
|
||||
This driver supports AD1936, AD1937, AD1938 and AD1939.
|
||||
|
||||
config SND_BF5XX_SOC_AD73311
|
||||
tristate "SoC AD73311 Audio support for Blackfin"
|
||||
depends on SND_BF5XX_I2S
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_AD73311
|
||||
help
|
||||
Say Y if you want to add support for AD73311 codec on Blackfin.
|
||||
|
||||
config SND_BFIN_AD73311_SE
|
||||
int "PF pin for AD73311L Chip Select"
|
||||
depends on SND_BF5XX_SOC_AD73311
|
||||
default 4
|
||||
help
|
||||
Enter the GPIO used to control AD73311's SE pin. Acceptable
|
||||
values are 0 to 7
|
||||
|
||||
config SND_BF5XX_AC97
|
||||
tristate "SoC AC97 Audio for the ADI BF5xx chip"
|
||||
depends on BLACKFIN
|
||||
select AC97_BUS
|
||||
select SND_SOC_AC97_BUS
|
||||
select SND_BF5XX_SOC_SPORT
|
||||
select SND_BF5XX_SOC_AC97
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the Blackfin SPORT (synchronous serial ports) interface in slot 16
|
||||
mode (pseudo AC97 interface).
|
||||
You will also need to select the audio interfaces to support below.
|
||||
|
||||
Note:
|
||||
AC97 codecs which do not implement the slot-16 mode will not function
|
||||
properly with this driver. This driver is known to work with the
|
||||
Analog Devices line of AC97 codecs.
|
||||
|
||||
config SND_BF5XX_MMAP_SUPPORT
|
||||
bool "Enable MMAP Support"
|
||||
depends on SND_BF5XX_AC97
|
||||
default y
|
||||
help
|
||||
Say y if you want AC97 driver to support mmap mode.
|
||||
We introduce an intermediate buffer to simulate mmap.
|
||||
|
||||
config SND_BF5XX_MULTICHAN_SUPPORT
|
||||
bool "Enable Multichannel Support"
|
||||
depends on SND_BF5XX_AC97
|
||||
default n
|
||||
help
|
||||
Say y if you want AC97 driver to support up to 5.1 channel audio.
|
||||
this mode will consume much more memory for DMA.
|
||||
|
||||
config SND_BF5XX_HAVE_COLD_RESET
|
||||
bool "BOARD has COLD Reset GPIO"
|
||||
depends on SND_BF5XX_AC97
|
||||
default y if BFIN548_EZKIT
|
||||
default n if !BFIN548_EZKIT
|
||||
|
||||
config SND_BF5XX_RESET_GPIO_NUM
|
||||
int "Set a GPIO for cold reset"
|
||||
depends on SND_BF5XX_HAVE_COLD_RESET
|
||||
range 0 159
|
||||
default 19 if BFIN548_EZKIT
|
||||
default 5 if BFIN537_STAMP
|
||||
default 0
|
||||
help
|
||||
Set the correct GPIO for RESET the sound chip.
|
||||
|
||||
config SND_BF5XX_SOC_AD1980
|
||||
tristate "SoC AD1980/1 Audio support for BF5xx (Obsolete)"
|
||||
depends on SND_BF5XX_AC97
|
||||
select SND_BF5XX_SOC_AC97
|
||||
select SND_SOC_AD1980
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
|
||||
|
||||
Warning:
|
||||
Because Analog Devices Inc. discontinued the ad1980 sound chip since
|
||||
Sep. 2009, this ad1980 driver is not maintained, tested and supported
|
||||
by ADI now.
|
||||
|
||||
config SND_BF5XX_SOC_SPORT
|
||||
tristate
|
||||
|
||||
config SND_BF6XX_SOC_SPORT
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SOC_I2S
|
||||
tristate
|
||||
|
||||
config SND_BF6XX_SOC_I2S
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SOC_AC97
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SPORT_NUM
|
||||
int "Set a SPORT for Sound chip"
|
||||
depends on (SND_BF5XX_SOC_SPORT || SND_BF6XX_SOC_SPORT)
|
||||
range 0 3 if BF54x
|
||||
range 0 1 if !BF54x
|
||||
default 0
|
||||
help
|
||||
Set the correct SPORT for sound chip.
|
@ -1,40 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Blackfin Platform Support
|
||||
snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
|
||||
snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
|
||||
snd-soc-bf5xx-sport-objs := bf5xx-sport.o
|
||||
snd-soc-bf6xx-sport-objs := bf6xx-sport.o
|
||||
snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
|
||||
snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
|
||||
snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
|
||||
|
||||
obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
|
||||
obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
|
||||
obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
|
||||
obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
|
||||
|
||||
# Blackfin Machine Support
|
||||
snd-ad1836-objs := bf5xx-ad1836.o
|
||||
snd-ad1980-objs := bf5xx-ad1980.o
|
||||
snd-ssm2602-objs := bf5xx-ssm2602.o
|
||||
snd-ad73311-objs := bf5xx-ad73311.o
|
||||
snd-ad193x-objs := bf5xx-ad193x.o
|
||||
snd-soc-bfin-eval-adau1373-objs := bfin-eval-adau1373.o
|
||||
snd-soc-bfin-eval-adau1x61-objs := bfin-eval-adau1x61.o
|
||||
snd-soc-bfin-eval-adau1x81-objs := bfin-eval-adau1x81.o
|
||||
snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
|
||||
snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
|
||||
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1373) += snd-soc-bfin-eval-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) += snd-soc-bfin-eval-adau1x61.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X81) += snd-soc-bfin-eval-adau1x81.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
|
@ -1,480 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ac97-pcm.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: DMA Driver for AC97 sound chip
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include "bf5xx-ac97.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
static unsigned int ac97_chan_mask[] = {
|
||||
SP_FL, /* Mono */
|
||||
SP_STEREO, /* Stereo */
|
||||
SP_2DOT1, /* 2.1*/
|
||||
SP_QUAD,/*Quadraquic*/
|
||||
SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */
|
||||
SP_5DOT1, /* 5.1 */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
|
||||
snd_pcm_uframes_t count)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf +
|
||||
sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos *
|
||||
runtime->channels, count, chan_mask);
|
||||
sport->tx_pos += runtime->period_size;
|
||||
if (sport->tx_pos >= runtime->buffer_size)
|
||||
sport->tx_pos %= runtime->buffer_size;
|
||||
sport->tx_delay_pos = sport->tx_pos;
|
||||
} else {
|
||||
bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf +
|
||||
sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos *
|
||||
runtime->channels, count);
|
||||
sport->rx_pos += runtime->period_size;
|
||||
if (sport->rx_pos >= runtime->buffer_size)
|
||||
sport->rx_pos %= runtime->buffer_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void bf5xx_dma_irq(void *data)
|
||||
{
|
||||
struct snd_pcm_substream *pcm = data;
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
struct snd_pcm_runtime *runtime = pcm->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
bf5xx_mmap_copy(pcm, runtime->period_size);
|
||||
if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (sport->once == 0) {
|
||||
snd_pcm_period_elapsed(pcm);
|
||||
bf5xx_mmap_copy(pcm, runtime->period_size);
|
||||
sport->once = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
snd_pcm_period_elapsed(pcm);
|
||||
}
|
||||
|
||||
/* The memory size for pure pcm data is 128*1024 = 0x20000 bytes.
|
||||
* The total rx/tx buffer is for ac97 frame to hold all pcm data
|
||||
* is 0x20000 * sizeof(struct ac97_frame) / 4.
|
||||
*/
|
||||
static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
||||
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 0x10000,
|
||||
.periods_min = 1,
|
||||
.periods_max = PAGE_SIZE/32,
|
||||
.buffer_bytes_max = 0x20000, /* 128 kbytes */
|
||||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max
|
||||
* sizeof(struct ac97_frame) / 4;
|
||||
|
||||
snd_pcm_lib_malloc_pages(substream, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport->once = 0;
|
||||
if (runtime->dma_area)
|
||||
memset(runtime->dma_area, 0, runtime->buffer_size);
|
||||
memset(sport->tx_dma_buf, 0, runtime->buffer_size *
|
||||
sizeof(struct ac97_frame));
|
||||
} else
|
||||
memset(sport->rx_dma_buf, 0, runtime->buffer_size *
|
||||
sizeof(struct ac97_frame));
|
||||
#endif
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
|
||||
/* An intermediate buffer is introduced for implementing mmap for
|
||||
* SPORT working in TMD mode(include AC97).
|
||||
*/
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
} else {
|
||||
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
}
|
||||
#else
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_tx_dma(sport, runtime->dma_area, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
} else {
|
||||
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_rx_dma(sport, runtime->dma_area, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
bf5xx_mmap_copy(substream, runtime->period_size);
|
||||
sport->tx_delay_pos = 0;
|
||||
#endif
|
||||
sport_tx_start(sport);
|
||||
} else
|
||||
sport_rx_start(sport);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
sport->tx_pos = 0;
|
||||
#endif
|
||||
sport_tx_stop(sport);
|
||||
} else {
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
sport->rx_pos = 0;
|
||||
#endif
|
||||
sport_rx_stop(sport);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
unsigned int curr;
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
curr = sport->tx_delay_pos;
|
||||
else
|
||||
curr = sport->rx_pos;
|
||||
#else
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
curr = sport_curr_offset_tx(sport) / sizeof(struct ac97_frame);
|
||||
else
|
||||
curr = sport_curr_offset_rx(sport) / sizeof(struct ac97_frame);
|
||||
|
||||
#endif
|
||||
return curr;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
|
||||
|
||||
ret = snd_pcm_hw_constraint_integer(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (sport_handle != NULL)
|
||||
runtime->private_data = sport_handle;
|
||||
else {
|
||||
pr_err("sport_handle is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
size_t size = vma->vm_end - vma->vm_start;
|
||||
vma->vm_start = (unsigned long)runtime->dma_area;
|
||||
vma->vm_end = vma->vm_start + size;
|
||||
vma->vm_flags |= VM_SHARED;
|
||||
return 0 ;
|
||||
}
|
||||
#else
|
||||
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void *buf, unsigned long count)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
|
||||
struct ac97_frame *dst;
|
||||
|
||||
pr_debug("%s copy pos:0x%lx count:0x%lx\n",
|
||||
substream->stream ? "Capture" : "Playback", pos, count);
|
||||
dst = (struct ac97_frame *)runtime->dma_area +
|
||||
bytes_to_frames(runtime, pos);
|
||||
count = bytes_to_frames(runtime, count);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
bf5xx_pcm_to_ac97(dst, buf, count, chan_mask);
|
||||
else
|
||||
bf5xx_ac97_to_pcm(dst, buf, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void __user *buf, unsigned long count)
|
||||
{
|
||||
return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
|
||||
.open = bf5xx_pcm_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = bf5xx_pcm_hw_params,
|
||||
.hw_free = bf5xx_pcm_hw_free,
|
||||
.prepare = bf5xx_pcm_prepare,
|
||||
.trigger = bf5xx_pcm_trigger,
|
||||
.pointer = bf5xx_pcm_pointer,
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
.mmap = bf5xx_pcm_mmap,
|
||||
#else
|
||||
.copy_user = bf5xx_pcm_copy_user,
|
||||
.copy_kernel = bf5xx_pcm_copy,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max
|
||||
* sizeof(struct ac97_frame) / 4;
|
||||
|
||||
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);
|
||||
if (!buf->area) {
|
||||
pr_err("Failed to allocate dma memory\n");
|
||||
pr_err("Please increase uncached DMA memory region\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
buf->bytes = size;
|
||||
|
||||
pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
|
||||
buf->area, buf->bytes);
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_handle->tx_buf = buf->area;
|
||||
else
|
||||
sport_handle->rx_buf = buf->area;
|
||||
|
||||
/*
|
||||
* Need to allocate local buffer when enable
|
||||
* MMAP for SPORT working in TMD mode (include AC97).
|
||||
*/
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (!sport_handle->tx_dma_buf) {
|
||||
sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
|
||||
size, &sport_handle->tx_dma_phy, GFP_KERNEL);
|
||||
if (!sport_handle->tx_dma_buf) {
|
||||
pr_err("Failed to allocate memory for tx dma buf - Please increase uncached DMA memory region\n");
|
||||
return -ENOMEM;
|
||||
} else
|
||||
memset(sport_handle->tx_dma_buf, 0, size);
|
||||
} else
|
||||
memset(sport_handle->tx_dma_buf, 0, size);
|
||||
} else {
|
||||
if (!sport_handle->rx_dma_buf) {
|
||||
sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \
|
||||
size, &sport_handle->rx_dma_phy, GFP_KERNEL);
|
||||
if (!sport_handle->rx_dma_buf) {
|
||||
pr_err("Failed to allocate memory for rx dma buf - Please increase uncached DMA memory region\n");
|
||||
return -ENOMEM;
|
||||
} else
|
||||
memset(sport_handle->rx_dma_buf, 0, size);
|
||||
} else
|
||||
memset(sport_handle->rx_dma_buf, 0, size);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
int stream;
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
|
||||
sizeof(struct ac97_frame) / 4;
|
||||
#endif
|
||||
for (stream = 0; stream < 2; stream++) {
|
||||
substream = pcm->streams[stream].substream;
|
||||
if (!substream)
|
||||
continue;
|
||||
|
||||
buf = &substream->dma_buffer;
|
||||
if (!buf->area)
|
||||
continue;
|
||||
dma_free_coherent(NULL, buf->bytes, buf->area, 0);
|
||||
buf->area = NULL;
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (sport_handle->tx_dma_buf)
|
||||
dma_free_coherent(NULL, size, \
|
||||
sport_handle->tx_dma_buf, 0);
|
||||
sport_handle->tx_dma_buf = NULL;
|
||||
} else {
|
||||
|
||||
if (sport_handle->rx_dma_buf)
|
||||
dma_free_coherent(NULL, size, \
|
||||
sport_handle->rx_dma_buf, 0);
|
||||
sport_handle->rx_dma_buf = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
|
||||
.ops = &bf5xx_pcm_ac97_ops,
|
||||
.pcm_new = bf5xx_pcm_ac97_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
|
||||
static int bf5xx_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return devm_snd_soc_register_platform(&pdev->dev,
|
||||
&bf5xx_ac97_soc_platform);
|
||||
}
|
||||
|
||||
static struct platform_driver bf5xx_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-ac97-pcm-audio",
|
||||
},
|
||||
|
||||
.probe = bf5xx_soc_platform_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bf5xx_pcm_driver);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,388 +0,0 @@
|
||||
/*
|
||||
* bf5xx-ac97.c -- AC97 support for the ADI blackfin chip.
|
||||
*
|
||||
* Author: Roy Huang
|
||||
* Created: 11th. June 2007
|
||||
* Copyright: Analog Device Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-ac97.h"
|
||||
|
||||
/* Anomaly notes:
|
||||
* 05000250 - AD1980 is running in TDM mode and RFS/TFS are generated by SPORT
|
||||
* contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1,
|
||||
* while the max AC97 data size is 13*16. The DIV is always larger
|
||||
* than data size. AD73311 and ad2602 are not running in TDM mode.
|
||||
* AD1836 and AD73322 depend on external RFS/TFS only. So, this
|
||||
* anomaly does not affect blackfin sound drivers.
|
||||
*/
|
||||
|
||||
static struct sport_device *ac97_sport_handle;
|
||||
|
||||
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
|
||||
size_t count, unsigned int chan_mask)
|
||||
{
|
||||
while (count--) {
|
||||
dst->ac97_tag = TAG_VALID;
|
||||
if (chan_mask & SP_FL) {
|
||||
dst->ac97_pcm_r = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_RIGHT;
|
||||
}
|
||||
if (chan_mask & SP_FR) {
|
||||
dst->ac97_pcm_l = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_LEFT;
|
||||
|
||||
}
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
if (chan_mask & SP_SR) {
|
||||
dst->ac97_sl = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_SL;
|
||||
}
|
||||
if (chan_mask & SP_SL) {
|
||||
dst->ac97_sr = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_SR;
|
||||
}
|
||||
if (chan_mask & SP_LFE) {
|
||||
dst->ac97_lfe = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_LFE;
|
||||
}
|
||||
if (chan_mask & SP_FC) {
|
||||
dst->ac97_center = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_CENTER;
|
||||
}
|
||||
#endif
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
|
||||
|
||||
void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst,
|
||||
size_t count)
|
||||
{
|
||||
while (count--) {
|
||||
*(dst++) = src->ac97_pcm_l;
|
||||
*(dst++) = src->ac97_pcm_r;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
|
||||
|
||||
static unsigned int sport_tx_curr_frag(struct sport_device *sport)
|
||||
{
|
||||
return sport->tx_curr_frag = sport_curr_offset_tx(sport) /
|
||||
sport->tx_fragsize;
|
||||
}
|
||||
|
||||
static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
|
||||
{
|
||||
struct sport_device *sport = ac97_sport_handle;
|
||||
int *cmd_count = sport->private_data;
|
||||
int nextfrag = sport_tx_curr_frag(sport);
|
||||
struct ac97_frame *nextwrite;
|
||||
|
||||
sport_incfrag(sport, &nextfrag, 1);
|
||||
|
||||
nextwrite = (struct ac97_frame *)(sport->tx_buf +
|
||||
nextfrag * sport->tx_fragsize);
|
||||
pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
|
||||
sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
|
||||
nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD;
|
||||
nextwrite[cmd_count[nextfrag]].ac97_addr = addr;
|
||||
nextwrite[cmd_count[nextfrag]].ac97_data = data;
|
||||
++cmd_count[nextfrag];
|
||||
pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n",
|
||||
addr >> 8, data, nextfrag);
|
||||
}
|
||||
|
||||
static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
|
||||
unsigned short reg)
|
||||
{
|
||||
struct sport_device *sport_handle = ac97_sport_handle;
|
||||
struct ac97_frame out_frame[2], in_frame[2];
|
||||
|
||||
pr_debug("%s enter 0x%x\n", __func__, reg);
|
||||
|
||||
/* When dma descriptor is enabled, the register should not be read */
|
||||
if (sport_handle->tx_run || sport_handle->rx_run) {
|
||||
pr_err("Could you send a mail to cliff.cai@analog.com "
|
||||
"to report this?\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
memset(&out_frame, 0, 2 * sizeof(struct ac97_frame));
|
||||
memset(&in_frame, 0, 2 * sizeof(struct ac97_frame));
|
||||
out_frame[0].ac97_tag = TAG_VALID | TAG_CMD;
|
||||
out_frame[0].ac97_addr = ((reg << 8) | 0x8000);
|
||||
sport_send_and_recv(sport_handle, (unsigned char *)&out_frame,
|
||||
(unsigned char *)&in_frame,
|
||||
2 * sizeof(struct ac97_frame));
|
||||
return in_frame[1].ac97_data;
|
||||
}
|
||||
|
||||
void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||
unsigned short val)
|
||||
{
|
||||
struct sport_device *sport_handle = ac97_sport_handle;
|
||||
|
||||
pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
|
||||
|
||||
if (sport_handle->tx_run) {
|
||||
enqueue_cmd(ac97, (reg << 8), val); /* write */
|
||||
enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */
|
||||
} else {
|
||||
struct ac97_frame frame;
|
||||
memset(&frame, 0, sizeof(struct ac97_frame));
|
||||
frame.ac97_tag = TAG_VALID | TAG_CMD;
|
||||
frame.ac97_addr = (reg << 8);
|
||||
frame.ac97_data = val;
|
||||
sport_send_and_recv(sport_handle, (unsigned char *)&frame, \
|
||||
NULL, sizeof(struct ac97_frame));
|
||||
}
|
||||
}
|
||||
|
||||
static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
struct sport_device *sport_handle = ac97_sport_handle;
|
||||
u16 gpio = P_IDENT(sport_handle->pin_req[3]);
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
peripheral_free_list(sport_handle->pin_req);
|
||||
gpio_request(gpio, "bf5xx-ac97");
|
||||
gpio_direction_output(gpio, 1);
|
||||
udelay(2);
|
||||
gpio_set_value(gpio, 0);
|
||||
udelay(1);
|
||||
gpio_free(gpio);
|
||||
peripheral_request_list(sport_handle->pin_req, "soc-audio");
|
||||
}
|
||||
|
||||
static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
/* It is specified for bf548-ezkit */
|
||||
gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0);
|
||||
/* Keep reset pin low for 1 ms */
|
||||
mdelay(1);
|
||||
gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
|
||||
/* Wait for bit clock recover */
|
||||
mdelay(1);
|
||||
#else
|
||||
pr_info("%s: Not implemented\n", __func__);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct snd_ac97_bus_ops bf5xx_ac97_ops = {
|
||||
.read = bf5xx_ac97_read,
|
||||
.write = bf5xx_ac97_write,
|
||||
.warm_reset = bf5xx_ac97_warm_reset,
|
||||
.reset = bf5xx_ac97_cold_reset,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport);
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
ret = sport_set_multichannel(sport, 16, 0x3FF, 0x3FF, 1);
|
||||
#else
|
||||
ret = sport_set_multichannel(sport, 16, 0x1F, 0x1F, 1);
|
||||
#endif
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define bf5xx_ac97_suspend NULL
|
||||
#define bf5xx_ac97_resume NULL
|
||||
#endif
|
||||
|
||||
static struct snd_soc_dai_driver bfin_ac97_dai = {
|
||||
.bus_control = true,
|
||||
.suspend = bf5xx_ac97_suspend,
|
||||
.resume = bf5xx_ac97_resume,
|
||||
.playback = {
|
||||
.stream_name = "AC97 Playback",
|
||||
.channels_min = 2,
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
.channels_max = 6,
|
||||
#else
|
||||
.channels_max = 2,
|
||||
#endif
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
.capture = {
|
||||
.stream_name = "AC97 Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bfin_ac97_component = {
|
||||
.name = "bfin-ac97",
|
||||
};
|
||||
|
||||
static int asoc_bfin_ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
|
||||
/* Request PB3 as reset pin */
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
CONFIG_SND_BF5XX_RESET_GPIO_NUM,
|
||||
GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to request GPIO_%d for reset: %d\n",
|
||||
CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
|
||||
PAGE_SIZE);
|
||||
if (!sport_handle) {
|
||||
ret = -ENODEV;
|
||||
goto sport_err;
|
||||
}
|
||||
|
||||
/*SPORT works in TDM mode to simulate AC97 transfers*/
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 0x3FF, 1);
|
||||
#else
|
||||
ret = sport_set_multichannel(sport_handle, 16, 0x1F, 0x1F, 1);
|
||||
#endif
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
ret = -EBUSY;
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
ret = -EBUSY;
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
ret = -EBUSY;
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_set_ac97_ops(&bf5xx_ac97_ops);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
|
||||
&bfin_ac97_dai, 1);
|
||||
if (ret) {
|
||||
pr_err("Failed to register DAI: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ac97_sport_handle = sport_handle;
|
||||
|
||||
return 0;
|
||||
|
||||
sport_config_err:
|
||||
sport_done(sport_handle);
|
||||
sport_err:
|
||||
snd_soc_set_ac97_ops(NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asoc_bfin_ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_done(sport_handle);
|
||||
snd_soc_set_ac97_ops(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver asoc_bfin_ac97_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-ac97",
|
||||
},
|
||||
|
||||
.probe = asoc_bfin_ac97_probe,
|
||||
.remove = asoc_bfin_ac97_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(asoc_bfin_ac97_driver);
|
||||
|
||||
MODULE_AUTHOR("Roy Huang");
|
||||
MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* sound/soc/blackfin/bf5xx-ac97.h
|
||||
*
|
||||
* 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 _BF5XX_AC97_H
|
||||
#define _BF5XX_AC97_H
|
||||
|
||||
/* Frame format in memory, only support stereo currently */
|
||||
struct ac97_frame {
|
||||
u16 ac97_tag; /* slot 0 */
|
||||
u16 ac97_addr; /* slot 1 */
|
||||
u16 ac97_data; /* slot 2 */
|
||||
u16 ac97_pcm_l; /*slot 3:front left*/
|
||||
u16 ac97_pcm_r; /*slot 4:front left*/
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
u16 ac97_mdm_l1;
|
||||
u16 ac97_center; /*slot 6:center*/
|
||||
u16 ac97_sl; /*slot 7:surround left*/
|
||||
u16 ac97_sr; /*slot 8:surround right*/
|
||||
u16 ac97_lfe; /*slot 9:lfe*/
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Speaker location */
|
||||
#define SP_FL 0x0001
|
||||
#define SP_FR 0x0010
|
||||
#define SP_FC 0x0002
|
||||
#define SP_LFE 0x0020
|
||||
#define SP_SL 0x0004
|
||||
#define SP_SR 0x0040
|
||||
|
||||
#define SP_STEREO (SP_FL | SP_FR)
|
||||
#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE)
|
||||
#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR)
|
||||
#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR)
|
||||
|
||||
#define TAG_VALID 0x8000
|
||||
#define TAG_CMD 0x6000
|
||||
#define TAG_PCM_LEFT 0x1000
|
||||
#define TAG_PCM_RIGHT 0x0800
|
||||
#define TAG_PCM_MDM_L1 0x0400
|
||||
#define TAG_PCM_CENTER 0x0200
|
||||
#define TAG_PCM_SL 0x0100
|
||||
#define TAG_PCM_SR 0x0080
|
||||
#define TAG_PCM_LFE 0x0040
|
||||
|
||||
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
|
||||
size_t count, unsigned int chan_mask);
|
||||
|
||||
void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \
|
||||
size_t count);
|
||||
|
||||
#endif
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad1836.c
|
||||
* Author: Barry Song <Barry.Song@analog.com>
|
||||
*
|
||||
* Created: Aug 4 2009
|
||||
* Description: Board driver for ad1836 sound chip
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "../codecs/ad1836.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ad1836;
|
||||
|
||||
static int bf5xx_ad1836_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
|
||||
int ret = 0;
|
||||
|
||||
/* set cpu DAI channel mapping */
|
||||
ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
|
||||
channel_map, ARRAY_SIZE(channel_map), channel_map);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ad1836_dai = {
|
||||
.name = "ad1836",
|
||||
.stream_name = "AD1836",
|
||||
.codec_dai_name = "ad1836-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.dai_fmt = BF5XX_AD1836_DAIFMT,
|
||||
.init = bf5xx_ad1836_init,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad1836 = {
|
||||
.name = "bfin-ad1836",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_ad1836_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static int bf5xx_ad1836_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bf5xx_ad1836;
|
||||
const char **link_name;
|
||||
int ret;
|
||||
|
||||
link_name = pdev->dev.platform_data;
|
||||
if (!link_name) {
|
||||
dev_err(&pdev->dev, "No platform data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
bf5xx_ad1836_dai.cpu_dai_name = link_name[0];
|
||||
bf5xx_ad1836_dai.codec_name = link_name[1];
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, card);
|
||||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to register card\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver bf5xx_ad1836_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-snd-ad1836",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bf5xx_ad1836_driver_probe,
|
||||
};
|
||||
module_platform_driver(bf5xx_ad1836_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Barry Song");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD1836 board driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad193x.c
|
||||
* Author: Barry Song <Barry.Song@analog.com>
|
||||
*
|
||||
* Created: Thur June 4 2009
|
||||
* Description: Board driver for ad193x sound chip
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "../codecs/ad193x.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ad193x;
|
||||
|
||||
static int bf5xx_ad193x_link_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
/* set the codec system clock for DAC and ADC */
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set codec DAI slots, 8 channels, all channels are enabled */
|
||||
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
|
||||
{
|
||||
.name = "ad193x",
|
||||
.stream_name = "AD193X",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name ="ad193x-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "spi0.5",
|
||||
.dai_fmt = BF5XX_AD193X_DAIFMT,
|
||||
.init = bf5xx_ad193x_link_init,
|
||||
},
|
||||
{
|
||||
.name = "ad193x",
|
||||
.stream_name = "AD193X",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name ="ad193x-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "spi0.5",
|
||||
.dai_fmt = BF5XX_AD193X_DAIFMT,
|
||||
.init = bf5xx_ad193x_link_init,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad193x = {
|
||||
.name = "bfin-ad193x",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bfxx_ad193x_snd_device;
|
||||
|
||||
static int __init bf5xx_ad193x_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bfxx_ad193x_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bfxx_ad193x_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
|
||||
ret = platform_device_add(bfxx_ad193x_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bfxx_ad193x_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_ad193x_exit(void)
|
||||
{
|
||||
platform_device_unregister(bfxx_ad193x_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_ad193x_init);
|
||||
module_exit(bf5xx_ad193x_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Barry Song");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD193X board driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad1980.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: Board driver for AD1980/1 audio codec
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
*
|
||||
* Because Analog Devices Inc. discontinued the ad1980 sound chip since
|
||||
* Sep. 2009, this ad1980 driver is not maintained, tested and supported
|
||||
* by ADI now.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "bf5xx-ac97.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_board;
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_board_dai[] = {
|
||||
{
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai_name = "bfin-ac97.0",
|
||||
.codec_dai_name = "ad1980-hifi",
|
||||
.platform_name = "bfin-ac97-pcm-audio",
|
||||
.codec_name = "ad1980",
|
||||
},
|
||||
{
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai_name = "bfin-ac97.1",
|
||||
.codec_dai_name = "ad1980-hifi",
|
||||
.platform_name = "bfin-ac97-pcm-audio",
|
||||
.codec_name = "ad1980",
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_board = {
|
||||
.name = "bfin-ad1980",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_board_snd_device;
|
||||
|
||||
static int __init bf5xx_board_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bf5xx_board_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bf5xx_board_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
|
||||
ret = platform_device_add(bf5xx_board_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bf5xx_board_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_board_exit(void)
|
||||
{
|
||||
platform_device_unregister(bf5xx_board_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_board_init);
|
||||
module_exit(bf5xx_board_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board (Obsolete)");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad73311.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Thur Sep 25 2008
|
||||
* Description: Board driver for ad73311 sound chip
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "../codecs/ad73311.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
|
||||
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
|
||||
#define bfin_read_SPORT_TCR1 bfin_read_SPORT0_TCR1
|
||||
#define bfin_write_SPORT_TCR2 bfin_write_SPORT0_TCR2
|
||||
#define bfin_write_SPORT_TX16 bfin_write_SPORT0_TX16
|
||||
#define bfin_read_SPORT_STAT bfin_read_SPORT0_STAT
|
||||
#else
|
||||
#define bfin_write_SPORT_TCR1 bfin_write_SPORT1_TCR1
|
||||
#define bfin_read_SPORT_TCR1 bfin_read_SPORT1_TCR1
|
||||
#define bfin_write_SPORT_TCR2 bfin_write_SPORT1_TCR2
|
||||
#define bfin_write_SPORT_TX16 bfin_write_SPORT1_TX16
|
||||
#define bfin_read_SPORT_STAT bfin_read_SPORT1_STAT
|
||||
#endif
|
||||
|
||||
#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
|
||||
|
||||
static struct snd_soc_card bf5xx_ad73311;
|
||||
|
||||
static int snd_ad73311_startup(void)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
/* Pull up SE pin on AD73311L */
|
||||
gpio_set_value(GPIO_SE, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ad73311_configure(void)
|
||||
{
|
||||
unsigned short ctrl_regs[6];
|
||||
unsigned short status = 0;
|
||||
int count = 0;
|
||||
|
||||
/* DMCLK = MCLK = 16.384 MHz
|
||||
* SCLK = DMCLK/8 = 2.048 MHz
|
||||
* Sample Rate = DMCLK/2048 = 8 KHz
|
||||
*/
|
||||
ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
|
||||
REGB_SCDIV(0) | REGB_DIRATE(0);
|
||||
ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
|
||||
REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
|
||||
ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
|
||||
REGD_IGS(2);
|
||||
ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
|
||||
ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
|
||||
ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
|
||||
|
||||
local_irq_disable();
|
||||
snd_ad73311_startup();
|
||||
udelay(1);
|
||||
|
||||
bfin_write_SPORT_TCR1(TFSR);
|
||||
bfin_write_SPORT_TCR2(0xF);
|
||||
SSYNC();
|
||||
|
||||
/* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
|
||||
* FIFO before enable SPORT to transfer the data
|
||||
*/
|
||||
for (count = 0; count < 6; count++)
|
||||
bfin_write_SPORT_TX16(ctrl_regs[count]);
|
||||
SSYNC();
|
||||
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
|
||||
SSYNC();
|
||||
|
||||
/* When TUVF is set, the data is already send out */
|
||||
while (!(status & TUVF) && ++count < 10000) {
|
||||
udelay(1);
|
||||
status = bfin_read_SPORT_STAT();
|
||||
SSYNC();
|
||||
}
|
||||
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
|
||||
SSYNC();
|
||||
local_irq_enable();
|
||||
|
||||
if (count >= 10000) {
|
||||
printk(KERN_ERR "ad73311: failed to configure codec\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_probe(struct snd_soc_card *card)
|
||||
{
|
||||
int err;
|
||||
if (gpio_request(GPIO_SE, "AD73311_SE")) {
|
||||
printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
gpio_direction_output(GPIO_SE, 0);
|
||||
|
||||
err = snd_ad73311_configure();
|
||||
if (err < 0)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_AD7311_DAI_FMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
|
||||
{
|
||||
.name = "ad73311",
|
||||
.stream_name = "AD73311",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "ad73311-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ad73311",
|
||||
.dai_fmt = BF5XX_AD7311_DAI_FMT,
|
||||
},
|
||||
{
|
||||
.name = "ad73311",
|
||||
.stream_name = "AD73311",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name = "ad73311-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ad73311",
|
||||
.dai_fmt = BF5XX_AD7311_DAI_FMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad73311 = {
|
||||
.name = "bfin-ad73311",
|
||||
.owner = THIS_MODULE,
|
||||
.probe = bf5xx_probe,
|
||||
.dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ad73311_snd_device;
|
||||
|
||||
static int __init bf5xx_ad73311_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bf5xx_ad73311_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
|
||||
ret = platform_device_add(bf5xx_ad73311_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bf5xx_ad73311_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_ad73311_exit(void)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
platform_device_unregister(bf5xx_ad73311_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_ad73311_init);
|
||||
module_exit(bf5xx_ad73311_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1,373 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-i2s-pcm.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: DMA driver for i2s codec
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
|
||||
static void bf5xx_dma_irq(void *data)
|
||||
{
|
||||
struct snd_pcm_substream *pcm = data;
|
||||
snd_pcm_period_elapsed(pcm);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 0x10000,
|
||||
.periods_min = 1,
|
||||
.periods_max = PAGE_SIZE/32,
|
||||
.buffer_bytes_max = 0x20000, /* 128 kbytes */
|
||||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
unsigned int buffer_size = params_buffer_bytes(params);
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode)
|
||||
buffer_size = buffer_size / params_channels(params) * 8;
|
||||
|
||||
return snd_pcm_lib_malloc_pages(substream, buffer_size);
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
int period_bytes = frames_to_bytes(runtime, runtime->period_size);
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode)
|
||||
period_bytes = period_bytes / runtime->channels * 8;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_tx_dma(sport, runtime->dma_area,
|
||||
runtime->periods, period_bytes);
|
||||
} else {
|
||||
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_rx_dma(sport, runtime->dma_area,
|
||||
runtime->periods, period_bytes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_tx_start(sport);
|
||||
else
|
||||
sport_rx_start(sport);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_tx_stop(sport);
|
||||
else
|
||||
sport_rx_stop(sport);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
unsigned int diff;
|
||||
snd_pcm_uframes_t frames;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
diff = sport_curr_offset_tx(sport);
|
||||
} else {
|
||||
diff = sport_curr_offset_rx(sport);
|
||||
}
|
||||
|
||||
/*
|
||||
* TX at least can report one frame beyond the end of the
|
||||
* buffer if we hit the wraparound case - clamp to within the
|
||||
* buffer as the ALSA APIs require.
|
||||
*/
|
||||
if (diff == snd_pcm_lib_buffer_bytes(substream))
|
||||
diff = 0;
|
||||
|
||||
frames = bytes_to_frames(substream->runtime, diff);
|
||||
if (dma_data->tdm_mode)
|
||||
frames = frames * runtime->channels / 8;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
int ret;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
|
||||
if (dma_data->tdm_mode)
|
||||
runtime->hw.buffer_bytes_max /= 4;
|
||||
else
|
||||
runtime->hw.info |= SNDRV_PCM_INFO_MMAP;
|
||||
|
||||
ret = snd_pcm_hw_constraint_integer(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (sport_handle != NULL) {
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_handle->tx_buf = buf->area;
|
||||
else
|
||||
sport_handle->rx_buf = buf->area;
|
||||
|
||||
runtime->private_data = sport_handle;
|
||||
} else {
|
||||
pr_err("sport_handle is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
size_t size = vma->vm_end - vma->vm_start;
|
||||
vma->vm_start = (unsigned long)runtime->dma_area;
|
||||
vma->vm_end = vma->vm_start + size;
|
||||
vma->vm_flags |= VM_SHARED;
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void *buf, unsigned long count)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int sample_size = runtime->sample_bits / 8;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
unsigned int i;
|
||||
void *src, *dst;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode) {
|
||||
pos = bytes_to_frames(runtime, pos);
|
||||
count = bytes_to_frames(runtime, count);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
src = buf;
|
||||
dst = runtime->dma_area;
|
||||
dst += pos * sample_size * 8;
|
||||
|
||||
while (count--) {
|
||||
for (i = 0; i < runtime->channels; i++) {
|
||||
memcpy(dst + dma_data->map[i] *
|
||||
sample_size, src, sample_size);
|
||||
src += sample_size;
|
||||
}
|
||||
dst += 8 * sample_size;
|
||||
}
|
||||
} else {
|
||||
src = runtime->dma_area;
|
||||
src += pos * sample_size * 8;
|
||||
dst = buf;
|
||||
|
||||
while (count--) {
|
||||
for (i = 0; i < runtime->channels; i++) {
|
||||
memcpy(dst, src + dma_data->map[i] *
|
||||
sample_size, sample_size);
|
||||
dst += sample_size;
|
||||
}
|
||||
src += 8 * sample_size;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
src = buf;
|
||||
dst = runtime->dma_area;
|
||||
dst += pos;
|
||||
} else {
|
||||
src = runtime->dma_area;
|
||||
src += pos;
|
||||
dst = buf;
|
||||
}
|
||||
|
||||
memcpy(dst, src, count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void __user *buf, unsigned long count)
|
||||
{
|
||||
return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count);
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
unsigned long count)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int sample_size = runtime->sample_bits / 8;
|
||||
void *buf = runtime->dma_area;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
unsigned int offset, samples;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode) {
|
||||
offset = bytes_to_frames(runtime, pos) * 8 * sample_size;
|
||||
samples = bytes_to_frames(runtime, count) * 8;
|
||||
} else {
|
||||
offset = pos;
|
||||
samples = bytes_to_samples(runtime, count);
|
||||
}
|
||||
|
||||
snd_pcm_format_set_silence(runtime->format, buf + offset, samples);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
|
||||
.open = bf5xx_pcm_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = bf5xx_pcm_hw_params,
|
||||
.hw_free = bf5xx_pcm_hw_free,
|
||||
.prepare = bf5xx_pcm_prepare,
|
||||
.trigger = bf5xx_pcm_trigger,
|
||||
.pointer = bf5xx_pcm_pointer,
|
||||
.mmap = bf5xx_pcm_mmap,
|
||||
.copy_user = bf5xx_pcm_copy_user,
|
||||
.copy_kernel = bf5xx_pcm_copy,
|
||||
.fill_silence = bf5xx_pcm_silence,
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
|
||||
SNDRV_DMA_TYPE_DEV, card->dev, size, size);
|
||||
}
|
||||
|
||||
static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
|
||||
.ops = &bf5xx_pcm_i2s_ops,
|
||||
.pcm_new = bf5xx_pcm_i2s_new,
|
||||
};
|
||||
|
||||
static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return devm_snd_soc_register_platform(&pdev->dev,
|
||||
&bf5xx_i2s_soc_platform);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-i2s-pcm-audio",
|
||||
},
|
||||
|
||||
.probe = bfin_i2s_soc_platform_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_i2s_pcm_driver);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* 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 _BF5XX_TDM_PCM_H
|
||||
#define _BF5XX_TDM_PCM_H
|
||||
|
||||
#define BFIN_TDM_DAI_MAX_SLOTS 8
|
||||
|
||||
struct bf5xx_i2s_pcm_data {
|
||||
unsigned int map[BFIN_TDM_DAI_MAX_SLOTS];
|
||||
bool tdm_mode;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,391 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-i2s.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: Blackfin I2S CPU DAI driver
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
|
||||
struct bf5xx_i2s_port {
|
||||
u16 tcr1;
|
||||
u16 rcr1;
|
||||
u16 tcr2;
|
||||
u16 rcr2;
|
||||
int configured;
|
||||
|
||||
unsigned int slots;
|
||||
unsigned int tx_mask;
|
||||
unsigned int rx_mask;
|
||||
|
||||
struct bf5xx_i2s_pcm_data tx_dma_data;
|
||||
struct bf5xx_i2s_pcm_data rx_dma_data;
|
||||
};
|
||||
|
||||
static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
int ret = 0;
|
||||
|
||||
/* interface format:support I2S,slave mode */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
bf5xx_i2s->tcr1 |= TFSR | TCKFE;
|
||||
bf5xx_i2s->rcr1 |= RFSR | RCKFE;
|
||||
bf5xx_i2s->tcr2 |= TSFSE;
|
||||
bf5xx_i2s->rcr2 |= RSFSE;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
bf5xx_i2s->tcr1 |= TFSR;
|
||||
bf5xx_i2s->rcr1 |= RFSR;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
dev_err(cpu_dai->dev, "%s: Unknown DAI format type\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
dev_err(cpu_dai->dev, "%s: Unknown DAI master type\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
int ret = 0;
|
||||
|
||||
bf5xx_i2s->tcr2 &= ~0x1f;
|
||||
bf5xx_i2s->rcr2 &= ~0x1f;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
bf5xx_i2s->tcr2 |= 7;
|
||||
bf5xx_i2s->rcr2 |= 7;
|
||||
sport_handle->wdsize = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
bf5xx_i2s->tcr2 |= 15;
|
||||
bf5xx_i2s->rcr2 |= 15;
|
||||
sport_handle->wdsize = 2;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
bf5xx_i2s->tcr2 |= 23;
|
||||
bf5xx_i2s->rcr2 |= 23;
|
||||
sport_handle->wdsize = 3;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
bf5xx_i2s->tcr2 |= 31;
|
||||
bf5xx_i2s->rcr2 |= 31;
|
||||
sport_handle->wdsize = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bf5xx_i2s->configured) {
|
||||
/*
|
||||
* TX and RX are not independent,they are enabled at the
|
||||
* same time, even if only one side is running. So, we
|
||||
* need to configure both of them at the time when the first
|
||||
* stream is opened.
|
||||
*
|
||||
* CPU DAI:slave mode.
|
||||
*/
|
||||
bf5xx_i2s->configured = 1;
|
||||
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
|
||||
bf5xx_i2s->rcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
|
||||
bf5xx_i2s->tcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
|
||||
dev_dbg(dai->dev, "%s enter\n", __func__);
|
||||
/* No active stream, SPORT is allowed to be configured again. */
|
||||
if (!dai->active)
|
||||
bf5xx_i2s->configured = 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, unsigned int *tx_slot,
|
||||
unsigned int rx_num, unsigned int *rx_slot)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
unsigned int tx_mapped = 0, rx_mapped = 0;
|
||||
unsigned int slot;
|
||||
int i;
|
||||
|
||||
if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
|
||||
(rx_num > BFIN_TDM_DAI_MAX_SLOTS))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < tx_num; i++) {
|
||||
slot = tx_slot[i];
|
||||
if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
|
||||
(!(tx_mapped & (1 << slot)))) {
|
||||
bf5xx_i2s->tx_dma_data.map[i] = slot;
|
||||
tx_mapped |= 1 << slot;
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < rx_num; i++) {
|
||||
slot = rx_slot[i];
|
||||
if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
|
||||
(!(rx_mapped & (1 << slot)))) {
|
||||
bf5xx_i2s->rx_dma_data.map[i] = slot;
|
||||
rx_mapped |= 1 << slot;
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
unsigned int rx_mask, int slots, int width)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
|
||||
if (slots % 8 != 0 || slots > 8)
|
||||
return -EINVAL;
|
||||
|
||||
if (width != 32)
|
||||
return -EINVAL;
|
||||
|
||||
bf5xx_i2s->slots = slots;
|
||||
bf5xx_i2s->tx_mask = tx_mask;
|
||||
bf5xx_i2s->rx_mask = rx_mask;
|
||||
|
||||
bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0;
|
||||
bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0;
|
||||
|
||||
return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
|
||||
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport_handle);
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
|
||||
|
||||
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
|
||||
bf5xx_i2s->rcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
|
||||
bf5xx_i2s->tcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return sport_set_multichannel(sport_handle, bf5xx_i2s->slots,
|
||||
bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
#define bf5xx_i2s_suspend NULL
|
||||
#define bf5xx_i2s_resume NULL
|
||||
#endif
|
||||
|
||||
static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) {
|
||||
bf5xx_i2s->tx_dma_data.map[i] = i;
|
||||
bf5xx_i2s->rx_dma_data.map[i] = i;
|
||||
}
|
||||
|
||||
dai->playback_dma_data = &bf5xx_i2s->tx_dma_data;
|
||||
dai->capture_dma_data = &bf5xx_i2s->rx_dma_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
|
||||
SNDRV_PCM_RATE_96000)
|
||||
|
||||
#define BF5XX_I2S_FORMATS \
|
||||
(SNDRV_PCM_FMTBIT_S8 | \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
|
||||
.shutdown = bf5xx_i2s_shutdown,
|
||||
.hw_params = bf5xx_i2s_hw_params,
|
||||
.set_fmt = bf5xx_i2s_set_dai_fmt,
|
||||
.set_tdm_slot = bf5xx_i2s_set_tdm_slot,
|
||||
.set_channel_map = bf5xx_i2s_set_channel_map,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver bf5xx_i2s_dai = {
|
||||
.probe = bf5xx_i2s_dai_probe,
|
||||
.suspend = bf5xx_i2s_suspend,
|
||||
.resume = bf5xx_i2s_resume,
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = BF5XX_I2S_RATES,
|
||||
.formats = BF5XX_I2S_FORMATS,},
|
||||
.capture = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = BF5XX_I2S_RATES,
|
||||
.formats = BF5XX_I2S_FORMATS,},
|
||||
.ops = &bf5xx_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bf5xx_i2s_component = {
|
||||
.name = "bf5xx-i2s",
|
||||
};
|
||||
|
||||
static int bf5xx_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle;
|
||||
int ret;
|
||||
|
||||
/* configure SPORT for I2S */
|
||||
sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
|
||||
sizeof(struct bf5xx_i2s_port));
|
||||
if (!sport_handle)
|
||||
return -ENODEV;
|
||||
|
||||
/* register with the ASoC layers */
|
||||
ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
|
||||
&bf5xx_i2s_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
|
||||
sport_done(sport_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle = platform_get_drvdata(pdev);
|
||||
|
||||
dev_dbg(&pdev->dev, "%s enter\n", __func__);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_done(sport_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_driver = {
|
||||
.probe = bf5xx_i2s_probe,
|
||||
.remove = bf5xx_i2s_remove,
|
||||
.driver = {
|
||||
.name = "bfin-i2s",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_i2s_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("I2S driver for ADI Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,174 +0,0 @@
|
||||
/*
|
||||
* File: bf5xx_sport.h
|
||||
* Based on:
|
||||
* Author: Roy Huang <roy.huang@analog.com>
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2004-2007 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __BF5XX_SPORT_H__
|
||||
#define __BF5XX_SPORT_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/bfin_sport.h>
|
||||
|
||||
#define DESC_ELEMENT_COUNT 9
|
||||
|
||||
struct sport_device {
|
||||
int num;
|
||||
int dma_rx_chan;
|
||||
int dma_tx_chan;
|
||||
int err_irq;
|
||||
const unsigned short *pin_req;
|
||||
struct sport_register *regs;
|
||||
|
||||
unsigned char *rx_buf;
|
||||
unsigned char *tx_buf;
|
||||
unsigned int rx_fragsize;
|
||||
unsigned int tx_fragsize;
|
||||
unsigned int rx_frags;
|
||||
unsigned int tx_frags;
|
||||
unsigned int wdsize;
|
||||
|
||||
/* for dummy dma transfer */
|
||||
void *dummy_buf;
|
||||
unsigned int dummy_count;
|
||||
|
||||
/* DMA descriptor ring head of current audio stream*/
|
||||
struct dmasg *dma_rx_desc;
|
||||
struct dmasg *dma_tx_desc;
|
||||
unsigned int rx_desc_bytes;
|
||||
unsigned int tx_desc_bytes;
|
||||
|
||||
unsigned int rx_run:1; /* rx is running */
|
||||
unsigned int tx_run:1; /* tx is running */
|
||||
|
||||
struct dmasg *dummy_rx_desc;
|
||||
struct dmasg *dummy_tx_desc;
|
||||
|
||||
struct dmasg *curr_rx_desc;
|
||||
struct dmasg *curr_tx_desc;
|
||||
|
||||
int rx_curr_frag;
|
||||
int tx_curr_frag;
|
||||
|
||||
unsigned int rcr1;
|
||||
unsigned int rcr2;
|
||||
int rx_tdm_count;
|
||||
|
||||
unsigned int tcr1;
|
||||
unsigned int tcr2;
|
||||
int tx_tdm_count;
|
||||
|
||||
void (*rx_callback)(void *data);
|
||||
void *rx_data;
|
||||
void (*tx_callback)(void *data);
|
||||
void *tx_data;
|
||||
void (*err_callback)(void *data);
|
||||
void *err_data;
|
||||
unsigned char *tx_dma_buf;
|
||||
unsigned char *rx_dma_buf;
|
||||
#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT
|
||||
dma_addr_t tx_dma_phy;
|
||||
dma_addr_t rx_dma_phy;
|
||||
int tx_pos;/*pcm sample count*/
|
||||
int rx_pos;
|
||||
unsigned int tx_buffer_size;
|
||||
unsigned int rx_buffer_size;
|
||||
int tx_delay_pos;
|
||||
int once;
|
||||
#endif
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
struct sport_param {
|
||||
int num;
|
||||
int dma_rx_chan;
|
||||
int dma_tx_chan;
|
||||
int err_irq;
|
||||
const unsigned short *pin_req;
|
||||
struct sport_register *regs;
|
||||
unsigned int wdsize;
|
||||
unsigned int dummy_count;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
struct sport_device *sport_init(struct platform_device *pdev,
|
||||
unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
|
||||
|
||||
void sport_done(struct sport_device *sport);
|
||||
|
||||
/* first use these ...*/
|
||||
|
||||
/* note: multichannel is in units of 8 channels, tdm_count is number of channels
|
||||
* NOT / 8 ! all channels are enabled by default */
|
||||
int sport_set_multichannel(struct sport_device *sport, int tdm_count,
|
||||
u32 tx_mask, u32 rx_mask, int packed);
|
||||
|
||||
int sport_config_rx(struct sport_device *sport,
|
||||
unsigned int rcr1, unsigned int rcr2,
|
||||
unsigned int clkdiv, unsigned int fsdiv);
|
||||
|
||||
int sport_config_tx(struct sport_device *sport,
|
||||
unsigned int tcr1, unsigned int tcr2,
|
||||
unsigned int clkdiv, unsigned int fsdiv);
|
||||
|
||||
/* ... then these: */
|
||||
|
||||
/* buffer size (in bytes) == fragcount * fragsize_bytes */
|
||||
|
||||
/* this is not a very general api, it sets the dma to 2d autobuffer mode */
|
||||
|
||||
int sport_config_rx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize_bytes);
|
||||
|
||||
int sport_config_tx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize_bytes);
|
||||
|
||||
int sport_tx_start(struct sport_device *sport);
|
||||
int sport_tx_stop(struct sport_device *sport);
|
||||
int sport_rx_start(struct sport_device *sport);
|
||||
int sport_rx_stop(struct sport_device *sport);
|
||||
|
||||
/* for use in interrupt handler */
|
||||
unsigned long sport_curr_offset_rx(struct sport_device *sport);
|
||||
unsigned long sport_curr_offset_tx(struct sport_device *sport);
|
||||
|
||||
void sport_incfrag(struct sport_device *sport, int *frag, int tx);
|
||||
void sport_decfrag(struct sport_device *sport, int *frag, int tx);
|
||||
|
||||
int sport_set_rx_callback(struct sport_device *sport,
|
||||
void (*rx_callback)(void *), void *rx_data);
|
||||
int sport_set_tx_callback(struct sport_device *sport,
|
||||
void (*tx_callback)(void *), void *tx_data);
|
||||
int sport_set_err_callback(struct sport_device *sport,
|
||||
void (*err_callback)(void *), void *err_data);
|
||||
|
||||
int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
|
||||
u8 *in_data, int len);
|
||||
#endif /* BF53X_SPORT_H */
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ssm2602.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: board driver for SSM2602 sound chip
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <linux/gpio.h>
|
||||
#include "../codecs/ssm2602.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602;
|
||||
|
||||
static int bf5xx_ssm2602_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
/*
|
||||
* If you are using a crystal source which frequency is not 12MHz
|
||||
* then modify the below case statement with frequency of the crystal.
|
||||
*
|
||||
* If you are using the SPORT to generate clocking then this is
|
||||
* where to do it.
|
||||
*/
|
||||
return snd_soc_dai_set_sysclk(rtd->codec_dai, SSM2602_SYSCLK, 12000000,
|
||||
SND_SOC_CLOCK_IN);
|
||||
}
|
||||
|
||||
/* CODEC is master for BCLK and LRC in this configuration. */
|
||||
#define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
|
||||
{
|
||||
.name = "ssm2602",
|
||||
.stream_name = "SSM2602",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "ssm2602-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ssm2602.0-001b",
|
||||
.init = bf5xx_ssm2602_dai_init,
|
||||
.dai_fmt = BF5XX_SSM2602_DAIFMT,
|
||||
},
|
||||
{
|
||||
.name = "ssm2602",
|
||||
.stream_name = "SSM2602",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name = "ssm2602-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ssm2602.0-001b",
|
||||
.init = bf5xx_ssm2602_dai_init,
|
||||
.dai_fmt = BF5XX_SSM2602_DAIFMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602 = {
|
||||
.name = "bfin-ssm2602",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ssm2602_snd_device;
|
||||
|
||||
static int __init bf5xx_ssm2602_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
bf5xx_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bf5xx_ssm2602_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
|
||||
ret = platform_device_add(bf5xx_ssm2602_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bf5xx_ssm2602_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_ssm2602_exit(void)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
platform_device_unregister(bf5xx_ssm2602_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_ssm2602_init);
|
||||
module_exit(bf5xx_ssm2602_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ALSA SoC SSM2602 BF527-EZKIT");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1,239 +0,0 @@
|
||||
/*
|
||||
* bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver
|
||||
*
|
||||
* Copyright (c) 2012 Analog Devices Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
#include "bf6xx-sport.h"
|
||||
|
||||
struct sport_params param;
|
||||
|
||||
static int bfin_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret = 0;
|
||||
|
||||
param.spctl &= ~(SPORT_CTL_OPMODE | SPORT_CTL_CKRE | SPORT_CTL_FSR
|
||||
| SPORT_CTL_LFS | SPORT_CTL_LAFS);
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_CKRE
|
||||
| SPORT_CTL_LFS;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
param.spctl |= SPORT_CTL_FSR;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_LFS
|
||||
| SPORT_CTL_LAFS;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "%s: Unknown DAI format type\n", __func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
param.spctl &= ~(SPORT_CTL_ICLK | SPORT_CTL_IFS);
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "%s: Unknown DAI master type\n", __func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret = 0;
|
||||
|
||||
param.spctl &= ~SPORT_CTL_SLEN;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
param.spctl |= 0x70;
|
||||
sport->wdsize = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
param.spctl |= 0xf0;
|
||||
sport->wdsize = 2;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
param.spctl |= 0x170;
|
||||
sport->wdsize = 3;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
param.spctl |= 0x1f0;
|
||||
sport->wdsize = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ret = sport_set_tx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT tx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = sport_set_rx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT rx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bfin_i2s_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport);
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_i2s_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = sport_set_tx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT tx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
ret = sport_set_rx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT rx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define bfin_i2s_suspend NULL
|
||||
#define bfin_i2s_resume NULL
|
||||
#endif
|
||||
|
||||
#define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
|
||||
SNDRV_PCM_RATE_96000)
|
||||
|
||||
#define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops bfin_i2s_dai_ops = {
|
||||
.hw_params = bfin_i2s_hw_params,
|
||||
.set_fmt = bfin_i2s_set_dai_fmt,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver bfin_i2s_dai = {
|
||||
.suspend = bfin_i2s_suspend,
|
||||
.resume = bfin_i2s_resume,
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = BFIN_I2S_RATES,
|
||||
.formats = BFIN_I2S_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = BFIN_I2S_RATES,
|
||||
.formats = BFIN_I2S_FORMATS,
|
||||
},
|
||||
.ops = &bfin_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bfin_i2s_component = {
|
||||
.name = "bfin-i2s",
|
||||
};
|
||||
|
||||
static int bfin_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
sport = sport_create(pdev);
|
||||
if (!sport)
|
||||
return -ENODEV;
|
||||
|
||||
/* register with the ASoC layers */
|
||||
ret = snd_soc_register_component(dev, &bfin_i2s_component,
|
||||
&bfin_i2s_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register DAI: %d\n", ret);
|
||||
sport_delete(sport);
|
||||
return ret;
|
||||
}
|
||||
platform_set_drvdata(pdev, sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_delete(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_driver = {
|
||||
.probe = bfin_i2s_probe,
|
||||
.remove = bfin_i2s_remove,
|
||||
.driver = {
|
||||
.name = "bfin-i2s",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_i2s_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
|
||||
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1,425 +0,0 @@
|
||||
/*
|
||||
* bf6xx_sport.c Analog Devices BF6XX SPORT driver
|
||||
*
|
||||
* Copyright (c) 2012 Analog Devices Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "bf6xx-sport.h"
|
||||
|
||||
int sport_set_tx_params(struct sport_device *sport,
|
||||
struct sport_params *params)
|
||||
{
|
||||
if (sport->tx_regs->spctl & SPORT_CTL_SPENPRI)
|
||||
return -EBUSY;
|
||||
sport->tx_regs->spctl = params->spctl | SPORT_CTL_SPTRAN;
|
||||
sport->tx_regs->div = params->div;
|
||||
SSYNC();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_tx_params);
|
||||
|
||||
int sport_set_rx_params(struct sport_device *sport,
|
||||
struct sport_params *params)
|
||||
{
|
||||
if (sport->rx_regs->spctl & SPORT_CTL_SPENPRI)
|
||||
return -EBUSY;
|
||||
sport->rx_regs->spctl = params->spctl & ~SPORT_CTL_SPTRAN;
|
||||
sport->rx_regs->div = params->div;
|
||||
SSYNC();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_rx_params);
|
||||
|
||||
static int compute_wdsize(size_t wdsize)
|
||||
{
|
||||
switch (wdsize) {
|
||||
case 1:
|
||||
return WDSIZE_8 | PSIZE_8;
|
||||
case 2:
|
||||
return WDSIZE_16 | PSIZE_16;
|
||||
default:
|
||||
return WDSIZE_32 | PSIZE_32;
|
||||
}
|
||||
}
|
||||
|
||||
void sport_tx_start(struct sport_device *sport)
|
||||
{
|
||||
set_dma_next_desc_addr(sport->tx_dma_chan, sport->tx_desc);
|
||||
set_dma_config(sport->tx_dma_chan, DMAFLOW_LIST | DI_EN
|
||||
| compute_wdsize(sport->wdsize) | NDSIZE_6);
|
||||
enable_dma(sport->tx_dma_chan);
|
||||
sport->tx_regs->spctl |= SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(sport_tx_start);
|
||||
|
||||
void sport_rx_start(struct sport_device *sport)
|
||||
{
|
||||
set_dma_next_desc_addr(sport->rx_dma_chan, sport->rx_desc);
|
||||
set_dma_config(sport->rx_dma_chan, DMAFLOW_LIST | DI_EN | WNR
|
||||
| compute_wdsize(sport->wdsize) | NDSIZE_6);
|
||||
enable_dma(sport->rx_dma_chan);
|
||||
sport->rx_regs->spctl |= SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(sport_rx_start);
|
||||
|
||||
void sport_tx_stop(struct sport_device *sport)
|
||||
{
|
||||
sport->tx_regs->spctl &= ~SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
disable_dma(sport->tx_dma_chan);
|
||||
}
|
||||
EXPORT_SYMBOL(sport_tx_stop);
|
||||
|
||||
void sport_rx_stop(struct sport_device *sport)
|
||||
{
|
||||
sport->rx_regs->spctl &= ~SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
disable_dma(sport->rx_dma_chan);
|
||||
}
|
||||
EXPORT_SYMBOL(sport_rx_stop);
|
||||
|
||||
void sport_set_tx_callback(struct sport_device *sport,
|
||||
void (*tx_callback)(void *), void *tx_data)
|
||||
{
|
||||
sport->tx_callback = tx_callback;
|
||||
sport->tx_data = tx_data;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_tx_callback);
|
||||
|
||||
void sport_set_rx_callback(struct sport_device *sport,
|
||||
void (*rx_callback)(void *), void *rx_data)
|
||||
{
|
||||
sport->rx_callback = rx_callback;
|
||||
sport->rx_data = rx_data;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_rx_callback);
|
||||
|
||||
static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
|
||||
size_t fragsize, unsigned int cfg,
|
||||
unsigned int count, size_t wdsize)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fragcount; ++i) {
|
||||
desc[i].next_desc_addr = &(desc[i + 1]);
|
||||
desc[i].start_addr = (unsigned long)buf + i * fragsize;
|
||||
desc[i].cfg = cfg;
|
||||
desc[i].x_count = count;
|
||||
desc[i].x_modify = wdsize;
|
||||
desc[i].y_count = 0;
|
||||
desc[i].y_modify = 0;
|
||||
}
|
||||
|
||||
/* make circular */
|
||||
desc[fragcount - 1].next_desc_addr = desc;
|
||||
}
|
||||
|
||||
int sport_config_tx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize)
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned int cfg;
|
||||
dma_addr_t addr;
|
||||
|
||||
count = fragsize / sport->wdsize;
|
||||
|
||||
if (sport->tx_desc)
|
||||
dma_free_coherent(NULL, sport->tx_desc_size,
|
||||
sport->tx_desc, 0);
|
||||
|
||||
sport->tx_desc = dma_alloc_coherent(NULL,
|
||||
fragcount * sizeof(struct dmasg), &addr, 0);
|
||||
sport->tx_desc_size = fragcount * sizeof(struct dmasg);
|
||||
if (!sport->tx_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
sport->tx_buf = buf;
|
||||
sport->tx_fragsize = fragsize;
|
||||
sport->tx_frags = fragcount;
|
||||
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
|
||||
|
||||
setup_desc(sport->tx_desc, buf, fragcount, fragsize,
|
||||
cfg | DMAEN, count, sport->wdsize);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_config_tx_dma);
|
||||
|
||||
int sport_config_rx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize)
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned int cfg;
|
||||
dma_addr_t addr;
|
||||
|
||||
count = fragsize / sport->wdsize;
|
||||
|
||||
if (sport->rx_desc)
|
||||
dma_free_coherent(NULL, sport->rx_desc_size,
|
||||
sport->rx_desc, 0);
|
||||
|
||||
sport->rx_desc = dma_alloc_coherent(NULL,
|
||||
fragcount * sizeof(struct dmasg), &addr, 0);
|
||||
sport->rx_desc_size = fragcount * sizeof(struct dmasg);
|
||||
if (!sport->rx_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
sport->rx_buf = buf;
|
||||
sport->rx_fragsize = fragsize;
|
||||
sport->rx_frags = fragcount;
|
||||
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize)
|
||||
| WNR | NDSIZE_6;
|
||||
|
||||
setup_desc(sport->rx_desc, buf, fragcount, fragsize,
|
||||
cfg | DMAEN, count, sport->wdsize);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_config_rx_dma);
|
||||
|
||||
unsigned long sport_curr_offset_tx(struct sport_device *sport)
|
||||
{
|
||||
unsigned long curr = get_dma_curr_addr(sport->tx_dma_chan);
|
||||
|
||||
return (unsigned char *)curr - sport->tx_buf;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_curr_offset_tx);
|
||||
|
||||
unsigned long sport_curr_offset_rx(struct sport_device *sport)
|
||||
{
|
||||
unsigned long curr = get_dma_curr_addr(sport->rx_dma_chan);
|
||||
|
||||
return (unsigned char *)curr - sport->rx_buf;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_curr_offset_rx);
|
||||
|
||||
static irqreturn_t sport_tx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_device *sport = dev_id;
|
||||
static unsigned long status;
|
||||
|
||||
status = get_dma_curr_irqstat(sport->tx_dma_chan);
|
||||
if (status & (DMA_DONE | DMA_ERR)) {
|
||||
clear_dma_irqstat(sport->tx_dma_chan);
|
||||
SSYNC();
|
||||
}
|
||||
if (sport->tx_callback)
|
||||
sport->tx_callback(sport->tx_data);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t sport_rx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_device *sport = dev_id;
|
||||
unsigned long status;
|
||||
|
||||
status = get_dma_curr_irqstat(sport->rx_dma_chan);
|
||||
if (status & (DMA_DONE | DMA_ERR)) {
|
||||
clear_dma_irqstat(sport->rx_dma_chan);
|
||||
SSYNC();
|
||||
}
|
||||
if (sport->rx_callback)
|
||||
sport->rx_callback(sport->rx_data);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t sport_err_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_device *sport = dev_id;
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
|
||||
if (sport->tx_regs->spctl & SPORT_CTL_DERRPRI)
|
||||
dev_err(dev, "sport error: TUVF\n");
|
||||
if (sport->rx_regs->spctl & SPORT_CTL_DERRPRI)
|
||||
dev_err(dev, "sport error: ROVF\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sport_get_resource(struct sport_device *sport)
|
||||
{
|
||||
struct platform_device *pdev = sport->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bfin_snd_platform_data *pdata = dev->platform_data;
|
||||
struct resource *res;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(dev, "No platform data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->pin_req = pdata->pin_req;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "No tx MEM resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->tx_regs = (struct sport_register *)res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "No rx MEM resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->rx_regs = (struct sport_register *)res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "No tx DMA resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->tx_dma_chan = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "No rx DMA resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->rx_dma_chan = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "No tx error irq resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->tx_err_irq = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "No rx error irq resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->rx_err_irq = res->start;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sport_request_resource(struct sport_device *sport)
|
||||
{
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = peripheral_request_list(sport->pin_req, "soc-audio");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to request sport pin\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_dma(sport->tx_dma_chan, "SPORT TX Data");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate DMA channel for sport tx\n");
|
||||
goto err_tx_dma;
|
||||
}
|
||||
set_dma_callback(sport->tx_dma_chan, sport_tx_irq, sport);
|
||||
|
||||
ret = request_dma(sport->rx_dma_chan, "SPORT RX Data");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate DMA channel for sport rx\n");
|
||||
goto err_rx_dma;
|
||||
}
|
||||
set_dma_callback(sport->rx_dma_chan, sport_rx_irq, sport);
|
||||
|
||||
ret = request_irq(sport->tx_err_irq, sport_err_irq,
|
||||
0, "SPORT TX ERROR", sport);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate tx error IRQ for sport\n");
|
||||
goto err_tx_irq;
|
||||
}
|
||||
|
||||
ret = request_irq(sport->rx_err_irq, sport_err_irq,
|
||||
0, "SPORT RX ERROR", sport);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate rx error IRQ for sport\n");
|
||||
goto err_rx_irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_rx_irq:
|
||||
free_irq(sport->tx_err_irq, sport);
|
||||
err_tx_irq:
|
||||
free_dma(sport->rx_dma_chan);
|
||||
err_rx_dma:
|
||||
free_dma(sport->tx_dma_chan);
|
||||
err_tx_dma:
|
||||
peripheral_free_list(sport->pin_req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sport_free_resource(struct sport_device *sport)
|
||||
{
|
||||
free_irq(sport->rx_err_irq, sport);
|
||||
free_irq(sport->tx_err_irq, sport);
|
||||
free_dma(sport->rx_dma_chan);
|
||||
free_dma(sport->tx_dma_chan);
|
||||
peripheral_free_list(sport->pin_req);
|
||||
}
|
||||
|
||||
struct sport_device *sport_create(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sport_device *sport;
|
||||
int ret;
|
||||
|
||||
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
|
||||
if (!sport)
|
||||
return NULL;
|
||||
|
||||
sport->pdev = pdev;
|
||||
|
||||
ret = sport_get_resource(sport);
|
||||
if (ret)
|
||||
goto free_data;
|
||||
|
||||
ret = sport_request_resource(sport);
|
||||
if (ret)
|
||||
goto free_data;
|
||||
|
||||
dev_dbg(dev, "SPORT create success\n");
|
||||
return sport;
|
||||
free_data:
|
||||
kfree(sport);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_create);
|
||||
|
||||
void sport_delete(struct sport_device *sport)
|
||||
{
|
||||
if (sport->tx_desc)
|
||||
dma_free_coherent(NULL, sport->tx_desc_size,
|
||||
sport->tx_desc, 0);
|
||||
if (sport->rx_desc)
|
||||
dma_free_coherent(NULL, sport->rx_desc_size,
|
||||
sport->rx_desc, 0);
|
||||
sport_free_resource(sport);
|
||||
kfree(sport);
|
||||
}
|
||||
EXPORT_SYMBOL(sport_delete);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices BF6XX SPORT driver");
|
||||
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* bf6xx_sport - Analog Devices BF6XX SPORT driver
|
||||
*
|
||||
* Copyright (c) 2012 Analog Devices Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _BF6XX_SPORT_H_
|
||||
#define _BF6XX_SPORT_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/bfin_sport3.h>
|
||||
|
||||
struct sport_device {
|
||||
struct platform_device *pdev;
|
||||
const unsigned short *pin_req;
|
||||
struct sport_register *tx_regs;
|
||||
struct sport_register *rx_regs;
|
||||
int tx_dma_chan;
|
||||
int rx_dma_chan;
|
||||
int tx_err_irq;
|
||||
int rx_err_irq;
|
||||
|
||||
void (*tx_callback)(void *data);
|
||||
void *tx_data;
|
||||
void (*rx_callback)(void *data);
|
||||
void *rx_data;
|
||||
|
||||
struct dmasg *tx_desc;
|
||||
struct dmasg *rx_desc;
|
||||
unsigned int tx_desc_size;
|
||||
unsigned int rx_desc_size;
|
||||
unsigned char *tx_buf;
|
||||
unsigned char *rx_buf;
|
||||
unsigned int tx_fragsize;
|
||||
unsigned int rx_fragsize;
|
||||
unsigned int tx_frags;
|
||||
unsigned int rx_frags;
|
||||
unsigned int wdsize;
|
||||
};
|
||||
|
||||
struct sport_params {
|
||||
u32 spctl;
|
||||
u32 div;
|
||||
};
|
||||
|
||||
struct sport_device *sport_create(struct platform_device *pdev);
|
||||
void sport_delete(struct sport_device *sport);
|
||||
int sport_set_tx_params(struct sport_device *sport,
|
||||
struct sport_params *params);
|
||||
int sport_set_rx_params(struct sport_device *sport,
|
||||
struct sport_params *params);
|
||||
void sport_tx_start(struct sport_device *sport);
|
||||
void sport_rx_start(struct sport_device *sport);
|
||||
void sport_tx_stop(struct sport_device *sport);
|
||||
void sport_rx_stop(struct sport_device *sport);
|
||||
void sport_set_tx_callback(struct sport_device *sport,
|
||||
void (*tx_callback)(void *), void *tx_data);
|
||||
void sport_set_rx_callback(struct sport_device *sport,
|
||||
void (*rx_callback)(void *), void *rx_data);
|
||||
int sport_config_tx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize);
|
||||
int sport_config_rx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize);
|
||||
unsigned long sport_curr_offset_tx(struct sport_device *sport);
|
||||
unsigned long sport_curr_offset_rx(struct sport_device *sport);
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAU1373 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau1373.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1373_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line In1", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In2", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In3", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In4", NULL),
|
||||
|
||||
SND_SOC_DAPM_LINE("Line Out1", NULL),
|
||||
SND_SOC_DAPM_LINE("Line Out2", NULL),
|
||||
SND_SOC_DAPM_LINE("Stereo Out", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
SND_SOC_DAPM_HP("Earpiece", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1373_dapm_routes[] = {
|
||||
{ "AIN1L", NULL, "Line In1" },
|
||||
{ "AIN1R", NULL, "Line In1" },
|
||||
{ "AIN2L", NULL, "Line In2" },
|
||||
{ "AIN2R", NULL, "Line In2" },
|
||||
{ "AIN3L", NULL, "Line In3" },
|
||||
{ "AIN3R", NULL, "Line In3" },
|
||||
{ "AIN4L", NULL, "Line In4" },
|
||||
{ "AIN4R", NULL, "Line In4" },
|
||||
|
||||
/* MICBIAS can be connected via a jumper to the line-in jack, since w
|
||||
don't know which one is going to be used, just power both. */
|
||||
{ "Line In1", NULL, "MICBIAS1" },
|
||||
{ "Line In2", NULL, "MICBIAS1" },
|
||||
{ "Line In3", NULL, "MICBIAS1" },
|
||||
{ "Line In4", NULL, "MICBIAS1" },
|
||||
{ "Line In1", NULL, "MICBIAS2" },
|
||||
{ "Line In2", NULL, "MICBIAS2" },
|
||||
{ "Line In3", NULL, "MICBIAS2" },
|
||||
{ "Line In4", NULL, "MICBIAS2" },
|
||||
|
||||
{ "Line Out1", NULL, "LOUT1L" },
|
||||
{ "Line Out1", NULL, "LOUT1R" },
|
||||
{ "Line Out2", NULL, "LOUT2L" },
|
||||
{ "Line Out2", NULL, "LOUT2R" },
|
||||
{ "Headphone", NULL, "HPL" },
|
||||
{ "Headphone", NULL, "HPR" },
|
||||
{ "Earpiece", NULL, "EP" },
|
||||
{ "Speaker", NULL, "SPKL" },
|
||||
{ "Stereo Out", NULL, "SPKR" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1373_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
int pll_rate;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
|
||||
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_eval_adau1373_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int pll_rate = 48000 * 1024;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
|
||||
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static const struct snd_soc_ops bfin_eval_adau1373_ops = {
|
||||
.hw_params = bfin_eval_adau1373_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1373_dai = {
|
||||
.name = "adau1373",
|
||||
.stream_name = "adau1373",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau1373-aif1",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1373.0-001a",
|
||||
.ops = &bfin_eval_adau1373_ops,
|
||||
.init = bfin_eval_adau1373_codec_init,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1373 = {
|
||||
.name = "bfin-eval-adau1373",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bfin_eval_adau1373_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1373_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1373_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1373_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1373_dapm_routes),
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1373_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bfin_eval_adau1373;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1373);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1373_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1373",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1373_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_eval_adau1373_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1373 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1373");
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau1701.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_LINE("Line Out", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = {
|
||||
{ "Speaker", NULL, "OUT0" },
|
||||
{ "Speaker", NULL, "OUT1" },
|
||||
{ "Line Out", NULL, "OUT2" },
|
||||
{ "Line Out", NULL, "OUT3" },
|
||||
|
||||
{ "IN0", NULL, "Line In" },
|
||||
{ "IN1", NULL, "Line In" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1701_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops bfin_eval_adau1701_ops = {
|
||||
.hw_params = bfin_eval_adau1701_hw_params,
|
||||
};
|
||||
|
||||
#define BFIN_EVAL_ADAU1701_DAI_FMT (SND_SOC_DAIFMT_I2S | \
|
||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = {
|
||||
{
|
||||
.name = "adau1701",
|
||||
.stream_name = "adau1701",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau1701",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1701.0-0034",
|
||||
.ops = &bfin_eval_adau1701_ops,
|
||||
.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
|
||||
},
|
||||
{
|
||||
.name = "adau1701",
|
||||
.stream_name = "adau1701",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name = "adau1701",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1701.0-0034",
|
||||
.ops = &bfin_eval_adau1701_ops,
|
||||
.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1701 = {
|
||||
.name = "bfin-eval-adau1701",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1701_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1701_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes),
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1701_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bfin_eval_adau1701;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1701);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1701_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1701",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1701_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_eval_adau1701_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1701");
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAU1x61MINIZ on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau17x1.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1x61_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("In 1", NULL),
|
||||
SND_SOC_DAPM_LINE("In 2", NULL),
|
||||
SND_SOC_DAPM_LINE("In 3-4", NULL),
|
||||
|
||||
SND_SOC_DAPM_LINE("Diff Out L", NULL),
|
||||
SND_SOC_DAPM_LINE("Diff Out R", NULL),
|
||||
SND_SOC_DAPM_LINE("Stereo Out", NULL),
|
||||
SND_SOC_DAPM_HP("Capless HP Out", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1x61_dapm_routes[] = {
|
||||
{ "LAUX", NULL, "In 3-4" },
|
||||
{ "RAUX", NULL, "In 3-4" },
|
||||
{ "LINP", NULL, "In 1" },
|
||||
{ "LINN", NULL, "In 1"},
|
||||
{ "RINP", NULL, "In 2" },
|
||||
{ "RINN", NULL, "In 2" },
|
||||
|
||||
{ "In 1", NULL, "MICBIAS" },
|
||||
{ "In 2", NULL, "MICBIAS" },
|
||||
|
||||
{ "Capless HP Out", NULL, "LHP" },
|
||||
{ "Capless HP Out", NULL, "RHP" },
|
||||
{ "Diff Out L", NULL, "LOUT" },
|
||||
{ "Diff Out R", NULL, "ROUT" },
|
||||
{ "Stereo Out", NULL, "LOUT" },
|
||||
{ "Stereo Out", NULL, "ROUT" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x61_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int pll_rate;
|
||||
int ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 96000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
case 88200:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
|
||||
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adau1x61_ops = {
|
||||
.hw_params = bfin_eval_adau1x61_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1x61_dai = {
|
||||
.name = "adau1x61",
|
||||
.stream_name = "adau1x61",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1761.0-0038",
|
||||
.ops = &bfin_eval_adau1x61_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1x61 = {
|
||||
.name = "bfin-eval-adau1x61",
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "eval-adau1x61",
|
||||
.dai_link = &bfin_eval_adau1x61_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1x61_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x61_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1x61_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x61_dapm_routes),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x61_probe(struct platform_device *pdev)
|
||||
{
|
||||
bfin_eval_adau1x61.dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x61);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1x61_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1x61",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1x61_probe,
|
||||
};
|
||||
module_platform_driver(bfin_eval_adau1x61_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1x61 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1x61");
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAU1x81 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau17x1.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1x81_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Stereo In", NULL),
|
||||
SND_SOC_DAPM_LINE("Beep", NULL),
|
||||
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1x81_dapm_routes[] = {
|
||||
{ "BEEP", NULL, "Beep" },
|
||||
{ "LMIC", NULL, "Stereo In" },
|
||||
{ "LMIC", NULL, "Stereo In" },
|
||||
|
||||
{ "Headphone", NULL, "AOUTL" },
|
||||
{ "Headphone", NULL, "AOUTR" },
|
||||
{ "Speaker", NULL, "SP" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x81_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int pll_rate;
|
||||
int ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 96000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
case 88200:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
|
||||
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adau1x81_ops = {
|
||||
.hw_params = bfin_eval_adau1x81_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1x81_dai = {
|
||||
.name = "adau1x81",
|
||||
.stream_name = "adau1x81",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1781.0-0038",
|
||||
.ops = &bfin_eval_adau1x81_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1x81 = {
|
||||
.name = "bfin-eval-adau1x81",
|
||||
.driver_name = "eval-adau1x81",
|
||||
.dai_link = &bfin_eval_adau1x81_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1x81_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x81_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1x81_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x81_dapm_routes),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x81_probe(struct platform_device *pdev)
|
||||
{
|
||||
bfin_eval_adau1x81.dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x81);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1x81_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1x81",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1x81_probe,
|
||||
};
|
||||
module_platform_driver(bfin_eval_adau1x81_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1x81 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1x81");
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAV801 and EVAL-ADAV803 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "../codecs/adav80x.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adav80x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line Out", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adav80x_dapm_routes[] = {
|
||||
{ "Line Out", NULL, "VOUTL" },
|
||||
{ "Line Out", NULL, "VOUTR" },
|
||||
|
||||
{ "VINL", NULL, "Line In" },
|
||||
{ "VINR", NULL, "Line In" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adav80x_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL,
|
||||
27000000, params_rate(params) * 256);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_PLL1,
|
||||
params_rate(params) * 256, SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK1, 0,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK2, 0,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK3, 0,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_XTAL, 2700000, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adav80x_ops = {
|
||||
.hw_params = bfin_eval_adav80x_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = {
|
||||
{
|
||||
.name = "adav80x",
|
||||
.stream_name = "ADAV80x HiFi",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adav80x-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.init = bfin_eval_adav80x_codec_init,
|
||||
.ops = &bfin_eval_adav80x_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adav80x = {
|
||||
.name = "bfin-eval-adav80x",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = bfin_eval_adav80x_dais,
|
||||
.num_links = ARRAY_SIZE(bfin_eval_adav80x_dais),
|
||||
|
||||
.dapm_widgets = bfin_eval_adav80x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adav80x_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adav80x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adav80x_dapm_routes),
|
||||
};
|
||||
|
||||
enum bfin_eval_adav80x_type {
|
||||
BFIN_EVAL_ADAV801,
|
||||
BFIN_EVAL_ADAV803,
|
||||
};
|
||||
|
||||
static int bfin_eval_adav80x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bfin_eval_adav80x;
|
||||
const char *codec_name;
|
||||
|
||||
switch (platform_get_device_id(pdev)->driver_data) {
|
||||
case BFIN_EVAL_ADAV801:
|
||||
codec_name = "spi0.1";
|
||||
break;
|
||||
case BFIN_EVAL_ADAV803:
|
||||
codec_name = "adav803.0-0034";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bfin_eval_adav80x_dais[0].codec_name = codec_name;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adav80x);
|
||||
}
|
||||
|
||||
static const struct platform_device_id bfin_eval_adav80x_ids[] = {
|
||||
{ "bfin-eval-adav801", BFIN_EVAL_ADAV801 },
|
||||
{ "bfin-eval-adav803", BFIN_EVAL_ADAV803 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bfin_eval_adav80x_ids);
|
||||
|
||||
static struct platform_driver bfin_eval_adav80x_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adav80x",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adav80x_probe,
|
||||
.id_table = bfin_eval_adav80x_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_eval_adav80x_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -139,7 +139,7 @@ struct pm860x_priv {
|
||||
unsigned int pcmclk;
|
||||
unsigned int dir;
|
||||
unsigned int filter;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_component *component;
|
||||
struct i2c_client *i2c;
|
||||
struct regmap *regmap;
|
||||
struct pm860x_chip *chip;
|
||||
@ -272,15 +272,15 @@ static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
unsigned int reg = mc->reg;
|
||||
unsigned int reg2 = mc->rreg;
|
||||
int val[2], val2[2], i;
|
||||
|
||||
val[0] = snd_soc_read(codec, reg) & 0x3f;
|
||||
val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
|
||||
val2[0] = snd_soc_read(codec, reg2) & 0x3f;
|
||||
val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
|
||||
val[0] = snd_soc_component_read32(component, reg) & 0x3f;
|
||||
val[1] = (snd_soc_component_read32(component, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
|
||||
val2[0] = snd_soc_component_read32(component, reg2) & 0x3f;
|
||||
val2[1] = (snd_soc_component_read32(component, PM860X_SIDETONE_SHIFT)) & 0xf;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(st_table); i++) {
|
||||
if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
|
||||
@ -296,7 +296,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
unsigned int reg = mc->reg;
|
||||
unsigned int reg2 = mc->rreg;
|
||||
int err;
|
||||
@ -308,18 +308,18 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
|
||||
if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table))
|
||||
return -EINVAL;
|
||||
|
||||
err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
|
||||
err = snd_soc_component_update_bits(component, reg, 0x3f, st_table[val].m);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
|
||||
err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0xf0,
|
||||
st_table[val].n << 4);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
|
||||
err = snd_soc_component_update_bits(component, reg2, 0x3f, st_table[val2].m);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
|
||||
err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0x0f,
|
||||
st_table[val2].n);
|
||||
return err;
|
||||
}
|
||||
@ -329,15 +329,15 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
unsigned int reg = mc->reg;
|
||||
unsigned int reg2 = mc->rreg;
|
||||
unsigned int shift = mc->shift;
|
||||
int max = mc->max, val, val2;
|
||||
unsigned int mask = (1 << fls(max)) - 1;
|
||||
|
||||
val = snd_soc_read(codec, reg) >> shift;
|
||||
val2 = snd_soc_read(codec, reg2) >> shift;
|
||||
val = snd_soc_component_read32(component, reg) >> shift;
|
||||
val2 = snd_soc_component_read32(component, reg2) >> shift;
|
||||
ucontrol->value.integer.value[0] = (max - val) & mask;
|
||||
ucontrol->value.integer.value[1] = (max - val2) & mask;
|
||||
|
||||
@ -349,7 +349,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
unsigned int reg = mc->reg;
|
||||
unsigned int reg2 = mc->rreg;
|
||||
unsigned int shift = mc->shift;
|
||||
@ -365,11 +365,11 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
|
||||
val = val << shift;
|
||||
val2 = val2 << shift;
|
||||
|
||||
err = snd_soc_update_bits(codec, reg, val_mask, val);
|
||||
err = snd_soc_component_update_bits(component, reg, val_mask, val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_soc_update_bits(codec, reg2, val_mask, val2);
|
||||
err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -382,7 +382,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
|
||||
static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
|
||||
/*
|
||||
* In order to avoid current on the load, mute power-on and power-off
|
||||
@ -390,8 +390,8 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
|
||||
* Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
|
||||
* finished.
|
||||
*/
|
||||
snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
|
||||
snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
|
||||
snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, DAC_MUTE, 0);
|
||||
snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
|
||||
RSYNC_CHANGE, RSYNC_CHANGE);
|
||||
return 0;
|
||||
}
|
||||
@ -399,7 +399,7 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
|
||||
static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
unsigned int dac = 0;
|
||||
int data;
|
||||
|
||||
@ -412,28 +412,28 @@ static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
|
||||
if (dac) {
|
||||
/* Auto mute in power-on sequence. */
|
||||
dac |= MODULATOR;
|
||||
snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
|
||||
snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
|
||||
DAC_MUTE, DAC_MUTE);
|
||||
snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
|
||||
snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
|
||||
RSYNC_CHANGE, RSYNC_CHANGE);
|
||||
/* update dac */
|
||||
snd_soc_update_bits(codec, PM860X_DAC_EN_2,
|
||||
snd_soc_component_update_bits(component, PM860X_DAC_EN_2,
|
||||
dac, dac);
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
if (dac) {
|
||||
/* Auto mute in power-off sequence. */
|
||||
snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
|
||||
snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
|
||||
DAC_MUTE, DAC_MUTE);
|
||||
snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
|
||||
snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
|
||||
RSYNC_CHANGE, RSYNC_CHANGE);
|
||||
/* update dac */
|
||||
data = snd_soc_read(codec, PM860X_DAC_EN_2);
|
||||
data = snd_soc_component_read32(component, PM860X_DAC_EN_2);
|
||||
data &= ~dac;
|
||||
if (!(data & (DAC_LEFT | DAC_RIGHT)))
|
||||
data &= ~MODULATOR;
|
||||
snd_soc_write(codec, PM860X_DAC_EN_2, data);
|
||||
snd_soc_component_write(component, PM860X_DAC_EN_2, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -922,13 +922,13 @@ static const struct snd_soc_dapm_route pm860x_dapm_routes[] = {
|
||||
*/
|
||||
static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
|
||||
|
||||
if (mute)
|
||||
data = mask;
|
||||
snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
|
||||
snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
|
||||
snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, mask, data);
|
||||
snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
|
||||
RSYNC_CHANGE, RSYNC_CHANGE);
|
||||
return 0;
|
||||
}
|
||||
@ -937,7 +937,7 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct snd_soc_component *component = dai->component;
|
||||
unsigned char inf = 0, mask = 0;
|
||||
|
||||
/* bit size */
|
||||
@ -952,7 +952,7 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
mask |= PCM_INF2_18WL;
|
||||
snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
|
||||
snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
|
||||
|
||||
/* sample rate */
|
||||
switch (params_rate(params)) {
|
||||
@ -971,7 +971,7 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
|
||||
snd_soc_component_update_bits(component, PM860X_PCM_RATE, 0x0f, inf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -979,8 +979,8 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
unsigned char inf = 0, mask = 0;
|
||||
int ret = -EINVAL;
|
||||
|
||||
@ -1012,15 +1012,15 @@ static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
mask |= PCM_MODE_MASK;
|
||||
if (ret)
|
||||
return ret;
|
||||
snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
|
||||
snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (dir == PM860X_CLK_DIR_OUT)
|
||||
pm860x->dir = PM860X_CLK_DIR_OUT;
|
||||
@ -1034,7 +1034,7 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct snd_soc_component *component = dai->component;
|
||||
unsigned char inf;
|
||||
|
||||
/* bit size */
|
||||
@ -1048,7 +1048,7 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
|
||||
snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
|
||||
|
||||
/* sample rate */
|
||||
switch (params_rate(params)) {
|
||||
@ -1076,7 +1076,7 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
|
||||
snd_soc_component_update_bits(component, PM860X_I2S_IFACE_4, 0xf, inf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1084,8 +1084,8 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
unsigned char inf = 0, mask = 0;
|
||||
|
||||
mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
|
||||
@ -1116,14 +1116,14 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
return -EINVAL;
|
||||
}
|
||||
mask |= PCM_MODE_MASK;
|
||||
snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
|
||||
snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, mask, inf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm860x_set_bias_level(struct snd_soc_codec *codec,
|
||||
static int pm860x_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
int data;
|
||||
|
||||
switch (level) {
|
||||
@ -1134,7 +1134,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
|
||||
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
|
||||
/* Enable Audio PLL & Audio section */
|
||||
data = AUDIO_PLL | AUDIO_SECTION_ON;
|
||||
pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
|
||||
@ -1216,7 +1216,7 @@ static struct snd_soc_dai_driver pm860x_dai[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static irqreturn_t pm860x_codec_handler(int irq, void *data)
|
||||
static irqreturn_t pm860x_component_handler(int irq, void *data)
|
||||
{
|
||||
struct pm860x_priv *pm860x = data;
|
||||
int status, shrt, report = 0, mic_report = 0;
|
||||
@ -1230,7 +1230,7 @@ static irqreturn_t pm860x_codec_handler(int irq, void *data)
|
||||
#ifndef CONFIG_SND_SOC_88PM860X_MODULE
|
||||
if (status & (HEADSET_STATUS | MIC_STATUS | SHORT_HS1 | SHORT_HS2 |
|
||||
SHORT_LO1 | SHORT_LO2))
|
||||
trace_snd_soc_jack_irq(dev_name(pm860x->codec->dev));
|
||||
trace_snd_soc_jack_irq(dev_name(pm860x->component->dev));
|
||||
#endif
|
||||
|
||||
if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
|
||||
@ -1256,17 +1256,17 @@ static irqreturn_t pm860x_codec_handler(int irq, void *data)
|
||||
snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
|
||||
SND_JACK_MICROPHONE);
|
||||
|
||||
dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
|
||||
dev_dbg(pm860x->component->dev, "headphone report:0x%x, mask:%x\n",
|
||||
report, mask);
|
||||
dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
|
||||
dev_dbg(pm860x->component->dev, "microphone report:0x%x\n", mic_report);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
|
||||
int pm860x_hs_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack,
|
||||
int det, int hook, int hs_shrt, int lo_shrt)
|
||||
{
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
int data;
|
||||
|
||||
pm860x->det.hp_jack = jack;
|
||||
@ -1290,15 +1290,15 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
|
||||
}
|
||||
|
||||
/* sync status */
|
||||
pm860x_codec_handler(0, pm860x);
|
||||
pm860x_component_handler(0, pm860x);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
|
||||
|
||||
int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
|
||||
int pm860x_mic_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, int det)
|
||||
{
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
|
||||
pm860x->det.mic_jack = jack;
|
||||
pm860x->det.mic_det = det;
|
||||
@ -1308,25 +1308,25 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
|
||||
MICDET_MASK, MICDET_MASK);
|
||||
|
||||
/* sync status */
|
||||
pm860x_codec_handler(0, pm860x);
|
||||
pm860x_component_handler(0, pm860x);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
|
||||
|
||||
static int pm860x_probe(struct snd_soc_codec *codec)
|
||||
static int pm860x_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
int i, ret;
|
||||
|
||||
pm860x->codec = codec;
|
||||
snd_soc_codec_init_regmap(codec, pm860x->regmap);
|
||||
pm860x->component = component;
|
||||
snd_soc_component_init_regmap(component, pm860x->regmap);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = request_threaded_irq(pm860x->irq[i], NULL,
|
||||
pm860x_codec_handler, IRQF_ONESHOT,
|
||||
pm860x_component_handler, IRQF_ONESHOT,
|
||||
pm860x->name[i], pm860x);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to request IRQ!\n");
|
||||
dev_err(component->dev, "Failed to request IRQ!\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -1339,29 +1339,29 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pm860x_remove(struct snd_soc_codec *codec)
|
||||
static void pm860x_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
|
||||
int i;
|
||||
|
||||
for (i = 3; i >= 0; i--)
|
||||
free_irq(pm860x->irq[i], pm860x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_pm860x = {
|
||||
.probe = pm860x_probe,
|
||||
.remove = pm860x_remove,
|
||||
.set_bias_level = pm860x_set_bias_level,
|
||||
|
||||
.component_driver = {
|
||||
.controls = pm860x_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(pm860x_snd_controls),
|
||||
.dapm_widgets = pm860x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets),
|
||||
.dapm_routes = pm860x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes),
|
||||
},
|
||||
static const struct snd_soc_component_driver soc_component_dev_pm860x = {
|
||||
.probe = pm860x_probe,
|
||||
.remove = pm860x_remove,
|
||||
.set_bias_level = pm860x_set_bias_level,
|
||||
.controls = pm860x_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(pm860x_snd_controls),
|
||||
.dapm_widgets = pm860x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets),
|
||||
.dapm_routes = pm860x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static int pm860x_codec_probe(struct platform_device *pdev)
|
||||
@ -1393,10 +1393,11 @@ static int pm860x_codec_probe(struct platform_device *pdev)
|
||||
strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
|
||||
ret = devm_snd_soc_register_component(&pdev->dev,
|
||||
&soc_component_dev_pm860x,
|
||||
pm860x_dai, ARRAY_SIZE(pm860x_dai));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register codec\n");
|
||||
dev_err(&pdev->dev, "Failed to register component\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
@ -1404,7 +1405,6 @@ static int pm860x_codec_probe(struct platform_device *pdev)
|
||||
|
||||
static int pm860x_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user