sound updates for 4.8
Majority of this update is about ASoC, including a few new drivers, and the rest are mostly minor changes. The only substantial change in ALSA core is about the additional error handling in the compress-offload API. Below are highlights: - Add the error propagating support in compress-offload API - HD-audio: a usual Dell headset fixup, an Intel HDMI/DP fix, and the default mixer setup change ot turn off the loopback - Lots of updates for ASoC Intel drivers, mostly board support and bug fixing, and to the NAU8825 driver - Work on generalizing bits of simple-card to allow more code sharing with the Renesas rsrc-card (which can't use simple-card due to DPCM) - Removal of the Odroid X2 driver due to replacement with simple-card - Support for several new Mediatek platforms and associated boards - New ASoC drivers for Allwinner A10, Analog Devices ADAU7002, Broadcom Cygnus, Cirrus Logic CS35L33 and CS53L30, Maxim MAX8960 and MAX98504, Realtek RT5514 and Wolfson WM8758 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIrBAABCAAVBQJXnaohDhx0aXdhaUBzdXNlLmRlAAoJEGwxgFQ9KSmkdh0P+wde 9YXRP7lugnai2keRR5ibev118qHvwcoLycdNSSutjydK1gbZtRNcVOiAO9KRKqxs nv4lM7TduFHDjsBrD26iMxFHqdnyuI2Xd5nddpPfTteCLtLLu72RYrRrubZB/SC9 Pi2PwMg+FkwaAG+/HXcWFIDNIxqhUXg2jHIhWlvWyvEvIZgJntvZaD1vw3NQqmE/ EAbafpdNXewY2IPxsQ+4zVD6JUTh4RTY790R4vZptO7E0oRksmffzAbX+XiYpiam pVwZAhyj05jy4DGsio89ufA51EC58oV8xfo6jxQh6wiXjr7ArhBh/60EoV7VMYh7 aouFQ+EOox3p/rcoyaaHbGROnCk0WIc2milQHM41F3Q6iC0fxOep14kSjxOXXqYg tgIjduptExh9XsEdpTCHfnmOyXEq+7PFbqmfluoKvG1q//k4u3d8SEicBfJMuWO+ Fb/v2ngii0r3D7rwsl4ONEShJdVd+mbpg2d6DoOu1/UYMfTGaxR/vF3DD7gCmn0A qikZkOnmmVttDVc8YlsmMZyo2ATU3AWsnNhdZGDGGT5IaAppZ+h3H5JZKNhxo5my cK6JbSMCljkmcc8GM990P6BNngya3doiu5aox8hM2uWugHcWYvjyoigGUhGVJdlT DgGtxlZ+5dQptdP0gAe5qO/Fzn9gfwvZQZxgSdaS =zx3K -----END PGP SIGNATURE----- Merge tag 'sound-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "The majority of this update is about ASoC, including a few new drivers, and the rest are mostly minor changes. The only substantial change in ALSA core is about the additional error handling in the compress-offload API. Below are highlights: - Add the error propagating support in compress-offload API - HD-audio: a usual Dell headset fixup, an Intel HDMI/DP fix, and the default mixer setup change ot turn off the loopback - Lots of updates for ASoC Intel drivers, mostly board support and bug fixing, and to the NAU8825 driver - Work on generalizing bits of simple-card to allow more code sharing with the Renesas rsrc-card (which can't use simple-card due to DPCM) - Removal of the Odroid X2 driver due to replacement with simple-card - Support for several new Mediatek platforms and associated boards - New ASoC drivers for Allwinner A10, Analog Devices ADAU7002, Broadcom Cygnus, Cirrus Logic CS35L33 and CS53L30, Maxim MAX8960 and MAX98504, Realtek RT5514 and Wolfson WM8758" * tag 'sound-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (278 commits) sound: oss: Use kernel_read_file_from_path() for mod_firmware_load() ASoC: Intel: Skylake: Delete an unnecessary check before the function call "release_firmware" ASoC: Intel: Skylake: Fix NULL Pointer exception in dynamic_debug. ASoC: samsung: Specify DMA channels through struct snd_dmaengine_pcm_config ASoC: samsung: Fix error paths in the I2S driver's probe() ASoC: cs53l30: Fix bit shift issue of TDM mode ASoC: cs53l30: Fix a bug for TDM slot location validation ASoC: rockchip: correct the spdif clk ALSA: echoaudio: purge contradictions between dimension matrix members and total number of members ASoC: rsrc-card: use asoc_simple_card_parse_card_name() ASoC: rsrc-card: use asoc_simple_dai instead of rsrc_card_dai ASoC: rsrc-card: use asoc_simple_card_parse_dailink_name() ASoC: simple-card: use asoc_simple_card_parse_card_name() ASoC: simple-card-utils: add asoc_simple_card_parse_card_name() ASoC: simple-card: use asoc_simple_card_parse_dailink_name() ASoC: simple-card-utils: add asoc_simple_card_set_dailink_name() ASoC: nau8825: drop redundant idiom when converting integer to boolean ASoC: nau8825: jack connection decision with different insertion logic ASoC: mediatek: Add HDMI dai-links to the mt8173-rt5650 machine driver ASoC: mediatek: mt2701: fix non static symbol warning ...
This commit is contained in:
commit
c9b95e5961
@ -13,6 +13,11 @@ Required properties:
|
||||
- reg: The i2c address. Value depends on the state of ADDR0
|
||||
and ADDR1, as wired in hardware.
|
||||
|
||||
Optional properties:
|
||||
- clock-names: If provided must be "mclk".
|
||||
- clocks: phandle + clock-specifiers for the clock that provides
|
||||
the audio master clock for the device.
|
||||
|
||||
Examples:
|
||||
#include <dt-bindings/sound/adau17x1.h>
|
||||
|
||||
@ -20,5 +25,8 @@ Examples:
|
||||
adau1361@38 {
|
||||
compatible = "adi,adau1761";
|
||||
reg = <0x38>;
|
||||
|
||||
clock-names = "mclk";
|
||||
clocks = <&audio_clock>;
|
||||
};
|
||||
};
|
||||
|
19
Documentation/devicetree/bindings/sound/adi,adau7002.txt
Normal file
19
Documentation/devicetree/bindings/sound/adi,adau7002.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "adi,adau7002"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- IOVDD-supply: Phandle and specifier for the power supply providing the IOVDD
|
||||
supply as covered in Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
If this property is not present it is assumed that the supply pin is
|
||||
hardwired to always on.
|
||||
|
||||
Example:
|
||||
adau7002: pdm-to-i2s {
|
||||
compatible = "adi,adau7002";
|
||||
IOVDD-supply = <&supply>;
|
||||
};
|
@ -0,0 +1,67 @@
|
||||
BROADCOM Cygnus Audio I2S/TDM/SPDIF controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "brcm,cygnus-audio"
|
||||
- #address-cells: 32bit valued, 1 cell.
|
||||
- #size-cells: 32bit valued, 0 cell.
|
||||
- reg : Should contain audio registers location and length
|
||||
- reg-names: names of the registers listed in "reg" property
|
||||
Valid names are "aud" and "i2s_in". "aud" contains a
|
||||
set of DMA, I2S_OUT and SPDIF registers. "i2s_in" contains
|
||||
a set of I2S_IN registers.
|
||||
- clocks: PLL and leaf clocks used by audio ports
|
||||
- assigned-clocks: PLL and leaf clocks
|
||||
- assigned-clock-parents: parent clocks of the assigned clocks
|
||||
(usually the PLL)
|
||||
- assigned-clock-rates: List of clock frequencies of the
|
||||
assigned clocks
|
||||
- clock-names: names of 3 leaf clocks used by audio ports
|
||||
Valid names are "ch0_audio", "ch1_audio", "ch2_audio"
|
||||
- interrupts: audio DMA interrupt number
|
||||
|
||||
SSP Subnode properties:
|
||||
- reg: The index of ssp port interface to use
|
||||
Valid value are 0, 1, 2, or 3 (for spdif)
|
||||
|
||||
Example:
|
||||
cygnus_audio: audio@180ae000 {
|
||||
compatible = "brcm,cygnus-audio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x180ae000 0xafd>, <0x180aec00 0x1f8>;
|
||||
reg-names = "aud", "i2s_in";
|
||||
clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>,
|
||||
<&audiopll BCM_CYGNUS_AUDIOPLL_CH1>,
|
||||
<&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
|
||||
assigned-clocks = <&audiopll BCM_CYGNUS_AUDIOPLL>,
|
||||
<&audiopll BCM_CYGNUS_AUDIOPLL_CH0>,
|
||||
<&audiopll BCM_CYGNUS_AUDIOPLL_CH1>,
|
||||
<&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
|
||||
assigned-clock-parents = <&audiopll BCM_CYGNUS_AUDIOPLL>;
|
||||
assigned-clock-rates = <1769470191>,
|
||||
<0>,
|
||||
<0>,
|
||||
<0>;
|
||||
clock-names = "ch0_audio", "ch1_audio", "ch2_audio";
|
||||
interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
ssp0: ssp_port@0 {
|
||||
reg = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ssp1: ssp_port@1 {
|
||||
reg = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
ssp2: ssp_port@2 {
|
||||
reg = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spdif: spdif_port@3 {
|
||||
reg = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
@ -4,7 +4,7 @@ This device support generic Bluetooth SCO link.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "delta,dfbmcs320"
|
||||
- compatible : "delta,dfbmcs320" or "linux,bt-sco"
|
||||
|
||||
Example:
|
||||
|
||||
|
126
Documentation/devicetree/bindings/sound/cs35l33.txt
Normal file
126
Documentation/devicetree/bindings/sound/cs35l33.txt
Normal file
@ -0,0 +1,126 @@
|
||||
CS35L33 Speaker Amplifier
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "cirrus,cs35l33"
|
||||
|
||||
- reg : the I2C address of the device for I2C
|
||||
|
||||
- VA-supply, VP-supply : power supplies for the device,
|
||||
as covered in
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios : gpio used to reset the amplifier
|
||||
|
||||
- interrupt-parent : Specifies the phandle of the interrupt controller to
|
||||
which the IRQs from CS35L33 are delivered to.
|
||||
- interrupts : IRQ line info CS35L33.
|
||||
(See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
for further information relating to interrupt properties)
|
||||
|
||||
- cirrus,boost-ctl : Booster voltage use to supply the amp. If the value is
|
||||
0, then VBST = VP. If greater than 0, the boost voltage will be 3300mV with
|
||||
a value of 1 and will increase at a step size of 100mV until a maximum of
|
||||
8000mV.
|
||||
|
||||
- cirrus,ramp-rate : On power up, it affects the time from when the power
|
||||
up sequence begins to the time the audio reaches a full-scale output.
|
||||
On power down, it affects the time from when the power-down sequence
|
||||
begins to when the amplifier disables the PWM outputs. If this property
|
||||
is not set then soft ramping will be disabled and ramp time would be
|
||||
20ms. If this property is set to 0,1,2,3 then ramp times would be 40ms,
|
||||
60ms,100ms,175ms respectively for 48KHz sample rate.
|
||||
|
||||
- cirrus,boost-ipk : The maximum current allowed for the boost converter.
|
||||
The range starts at 1850000uA and goes to a maximum of 3600000uA
|
||||
with a step size of 15625uA. The default is 2500000uA.
|
||||
|
||||
- cirrus,imon-adc-scale : Configures the scaling of data bits from the IMON
|
||||
ADC data word. This property can be set as a value of 0 for bits 15 down
|
||||
to 0, 6 for 21 down to 6, 7, for 22 down to 7, 8 for 23 down to 8.
|
||||
|
||||
|
||||
Optional H/G Algorithm sub-node:
|
||||
|
||||
The cs35l33 node can have a single "cirrus,hg-algo" sub-node that will enable
|
||||
the internal H/G Algorithm.
|
||||
|
||||
- cirrus,hg-algo : Sub-node for internal Class H/G algorithm that
|
||||
controls the amplifier supplies.
|
||||
|
||||
Optional properties for the "cirrus,hg-algo" sub-node:
|
||||
|
||||
- cirrus,mem-depth : Memory depth for the Class H/G algorithm measured in
|
||||
LRCLK cycles. If this property is set to 0, 1, 2, or 3 then the memory
|
||||
depths will be 1, 4, 8, 16 LRCLK cycles. The default is 16 LRCLK cycles.
|
||||
|
||||
cirrus,release-rate : The number of consecutive LRCLK periods before
|
||||
allowing release condition tracking updates. The number of LRCLK periods
|
||||
start at 3 to a maximum of 255.
|
||||
|
||||
- cirrus,ldo-thld : Configures the signal threshold at which the PWM output
|
||||
stage enters LDO operation. Starts as a default value of 50mV for a value
|
||||
of 1 and increases with a step size of 50mV to a maximum of 750mV (value of
|
||||
0xF).
|
||||
|
||||
- cirrus,ldo-path-disable : This is a boolean property. If present, the H/G
|
||||
algorithm uses the max detection path. If not present, the LDO
|
||||
detection path is used.
|
||||
|
||||
- cirrus,ldo-entry-delay : The LDO entry delay in milliseconds before the H/G
|
||||
algorithm switches to the LDO voltage. This property can be set to values
|
||||
from 0 to 7 for delays of 5ms, 10ms, 50ms, 100ms, 200ms, 500ms, 1000ms.
|
||||
The default is 100ms.
|
||||
|
||||
- cirrus,vp-hg-auto : This is a boolean property. When set, class H/G VPhg
|
||||
automatic updating is enabled.
|
||||
|
||||
- cirrus,vp-hg : Class H/G algorithm VPhg. Controls the H/G algorithm's
|
||||
reference to the VP voltage for when to start generating a boosted VBST.
|
||||
The reference voltage starts at 3000mV with a value of 0x3 and is increased
|
||||
by 100mV per step to a maximum of 5500mV.
|
||||
|
||||
- cirrus,vp-hg-rate : The rate (number of LRCLK periods) at which the VPhg is
|
||||
allowed to increase to a higher voltage when using VPhg automatic
|
||||
tracking. This property can be set to values from 0 to 3 with rates of 128
|
||||
periods, 2048 periods, 32768 periods, and 524288 periods.
|
||||
The default is 32768 periods.
|
||||
|
||||
- cirrus,vp-hg-va : VA calculation reference for automatic VPhg tracking
|
||||
using VPMON. This property can be set to values from 0 to 6 starting at
|
||||
1800mV with a step size of 50mV up to a maximum value of 1750mV.
|
||||
Default is 1800mV.
|
||||
|
||||
Example:
|
||||
|
||||
cs35l33: cs35l33@40 {
|
||||
compatible = "cirrus,cs35l33";
|
||||
reg = <0x40>;
|
||||
|
||||
VA-supply = <&ldo5_reg>;
|
||||
VP-supply = <&ldo5_reg>;
|
||||
|
||||
interrupt-parent = <&gpio8>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
reset-gpios = <&cs47l91 34 0>;
|
||||
|
||||
cirrus,ramp-rate = <0x0>;
|
||||
cirrus,boost-ctl = <0x30>; /* VBST = 8000mV */
|
||||
cirrus,boost-ipk = <0xE0>; /* 3600mA */
|
||||
cirrus,imon-adc-scale = <0> /* Bits 15 down to 0 */
|
||||
|
||||
cirrus,hg-algo {
|
||||
cirrus,mem-depth = <0x3>;
|
||||
cirrus,release-rate = <0x3>;
|
||||
cirrus,ldo-thld = <0x1>;
|
||||
cirrus,ldo-path-disable = <0x0>;
|
||||
cirrus,ldo-entry-delay=<0x4>;
|
||||
cirrus,vp-hg-auto;
|
||||
cirrus,vp-hg=<0xF>;
|
||||
cirrus,vp-hg-rate=<0x2>;
|
||||
cirrus,vp-hg-va=<0x0>;
|
||||
};
|
||||
};
|
44
Documentation/devicetree/bindings/sound/cs53l30.txt
Normal file
44
Documentation/devicetree/bindings/sound/cs53l30.txt
Normal file
@ -0,0 +1,44 @@
|
||||
CS53L30 audio CODEC
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "cirrus,cs53l30"
|
||||
|
||||
- reg : the I2C address of the device
|
||||
|
||||
- VA-supply, VP-supply : power supplies for the device,
|
||||
as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios : a GPIO spec for the reset pin.
|
||||
|
||||
- mute-gpios : a GPIO spec for the MUTE pin. The active state can be either
|
||||
GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW, which would be handled
|
||||
by the driver automatically.
|
||||
|
||||
- cirrus,micbias-lvl : Set the output voltage level on the MICBIAS Pin.
|
||||
0 = Hi-Z
|
||||
1 = 1.80 V
|
||||
2 = 2.75 V
|
||||
|
||||
- cirrus,use-sdout2 : This is a boolean property. If present, it indicates
|
||||
the hardware design connects both SDOUT1 and SDOUT2
|
||||
pins to output data. Otherwise, it indicates that
|
||||
only SDOUT1 is connected for data output.
|
||||
* CS53l30 supports 4-channel data output in the same
|
||||
* frame using two different ways:
|
||||
* 1) Normal I2S mode on two data pins -- each SDOUT
|
||||
* carries 2-channel data in the same time.
|
||||
* 2) TDM mode on one signle data pin -- SDOUT1 carries
|
||||
* 4-channel data per frame.
|
||||
|
||||
Example:
|
||||
|
||||
codec: cs53l30@48 {
|
||||
compatible = "cirrus,cs53l30";
|
||||
reg = <0x48>;
|
||||
reset-gpios = <&gpio 54 0>;
|
||||
VA-supply = <&cs53l30_va>;
|
||||
VP-supply = <&cs53l30_vp>;
|
||||
};
|
@ -12,6 +12,10 @@ Required properties:
|
||||
one for receive.
|
||||
- dma-names : "tx" for the transmit channel, "rx" for the receive channel.
|
||||
|
||||
Optional properties:
|
||||
- interrupts: The interrupt line number for the I2S controller. Add this
|
||||
parameter if the I2S controller that you are using does not support DMA.
|
||||
|
||||
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
|
||||
properties please check:
|
||||
* resource-names.txt
|
||||
|
@ -58,7 +58,7 @@ Required properties:
|
||||
* DMIC (stands for Digital Microphone Jack)
|
||||
|
||||
Note: The "Mic Jack" and "AMIC" are redundant while
|
||||
coexsiting in order to support the old bindings
|
||||
coexisting in order to support the old bindings
|
||||
of wm8962 and sgtl5000.
|
||||
|
||||
Optional properties:
|
||||
|
44
Documentation/devicetree/bindings/sound/max98504.txt
Normal file
44
Documentation/devicetree/bindings/sound/max98504.txt
Normal file
@ -0,0 +1,44 @@
|
||||
Maxim MAX98504 class D mono speaker amplifier
|
||||
|
||||
This device supports I2C control interface and an IRQ output signal. It features
|
||||
a PCM and PDM digital audio interface (DAI) and a differential analog input.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "maxim,max98504"
|
||||
- reg : should contain the I2C slave device address
|
||||
- DVDD-supply, DIOVDD-supply, PVDD-supply: power supplies for the device,
|
||||
as covered in ../regulator/regulator.txt
|
||||
- interrupts : should specify the interrupt line the device is connected to,
|
||||
as described in ../interrupt-controller/interrupts.txt
|
||||
|
||||
Optional properties:
|
||||
|
||||
- maxim,brownout-threshold - the PVDD brownout threshold, the value must be
|
||||
from 0, 1...21 range, corresponding to 2.6V, 2.65V...3.65V voltage range
|
||||
- maxim,brownout-attenuation - the brownout attenuation to the speaker gain
|
||||
applied during the "attack hold" and "timed hold" phase, the value must be
|
||||
from 0...6 (dB) range
|
||||
- maxim,brownout-attack-hold-ms - the brownout attack hold phase time in ms,
|
||||
0...255 (VBATBROWN_ATTK_HOLD, register 0x0018)
|
||||
- maxim,brownout-timed-hold-ms - the brownout timed hold phase time in ms,
|
||||
0...255 (VBATBROWN_TIME_HOLD, register 0x0019)
|
||||
- maxim,brownout-release-rate-ms - the brownout release phase step time in ms,
|
||||
0...255 (VBATBROWN_RELEASE, register 0x001A)
|
||||
|
||||
The default value when the above properties are not specified is 0,
|
||||
the maxim,brownout-threshold property must be specified to actually enable
|
||||
the PVDD brownout protection.
|
||||
|
||||
Example:
|
||||
|
||||
max98504@31 {
|
||||
compatible = "maxim,max98504";
|
||||
reg = <0x31>;
|
||||
interrupt-parent = <&gpio_bank_0>;
|
||||
interrupts = <2 0>;
|
||||
|
||||
DVDD-supply = <®ulator>;
|
||||
DIOVDD-supply = <®ulator>;
|
||||
PVDD-supply = <®ulator>;
|
||||
};
|
28
Documentation/devicetree/bindings/sound/max9860.txt
Normal file
28
Documentation/devicetree/bindings/sound/max9860.txt
Normal file
@ -0,0 +1,28 @@
|
||||
MAX9860 Mono Audio Voice Codec
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "maxim,max9860"
|
||||
|
||||
- reg : the I2C address of the device
|
||||
|
||||
- AVDD-supply, DVDD-supply and DVDDIO-supply : power supplies for
|
||||
the device, as covered in bindings/regulator/regulator.txt
|
||||
|
||||
- clock-names : Required element: "mclk".
|
||||
|
||||
- clocks : A clock specifier for the clock connected as MCLK.
|
||||
|
||||
Examples:
|
||||
|
||||
max9860: max9860@10 {
|
||||
compatible = "maxim,max9860";
|
||||
reg = <0x10>;
|
||||
|
||||
AVDD-supply = <®_1v8>;
|
||||
DVDD-supply = <®_1v8>;
|
||||
DVDDIO-supply = <®_3v0>;
|
||||
|
||||
clock-names = "mclk";
|
||||
clocks = <&pck2>;
|
||||
};
|
150
Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt
Normal file
150
Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt
Normal file
@ -0,0 +1,150 @@
|
||||
Mediatek AFE PCM controller for mt2701
|
||||
|
||||
Required properties:
|
||||
- compatible = "mediatek,mt2701-audio";
|
||||
- reg: register location and size
|
||||
- interrupts: Should contain AFE interrupt
|
||||
- clock-names: should have these clock names:
|
||||
"infra_sys_audio_clk",
|
||||
"top_audio_mux1_sel",
|
||||
"top_audio_mux2_sel",
|
||||
"top_audio_mux1_div",
|
||||
"top_audio_mux2_div",
|
||||
"top_audio_48k_timing",
|
||||
"top_audio_44k_timing",
|
||||
"top_audpll_mux_sel",
|
||||
"top_apll_sel",
|
||||
"top_aud1_pll_98M",
|
||||
"top_aud2_pll_90M",
|
||||
"top_hadds2_pll_98M",
|
||||
"top_hadds2_pll_294M",
|
||||
"top_audpll",
|
||||
"top_audpll_d4",
|
||||
"top_audpll_d8",
|
||||
"top_audpll_d16",
|
||||
"top_audpll_d24",
|
||||
"top_audintbus_sel",
|
||||
"clk_26m",
|
||||
"top_syspll1_d4",
|
||||
"top_aud_k1_src_sel",
|
||||
"top_aud_k2_src_sel",
|
||||
"top_aud_k3_src_sel",
|
||||
"top_aud_k4_src_sel",
|
||||
"top_aud_k5_src_sel",
|
||||
"top_aud_k6_src_sel",
|
||||
"top_aud_k1_src_div",
|
||||
"top_aud_k2_src_div",
|
||||
"top_aud_k3_src_div",
|
||||
"top_aud_k4_src_div",
|
||||
"top_aud_k5_src_div",
|
||||
"top_aud_k6_src_div",
|
||||
"top_aud_i2s1_mclk",
|
||||
"top_aud_i2s2_mclk",
|
||||
"top_aud_i2s3_mclk",
|
||||
"top_aud_i2s4_mclk",
|
||||
"top_aud_i2s5_mclk",
|
||||
"top_aud_i2s6_mclk",
|
||||
"top_asm_m_sel",
|
||||
"top_asm_h_sel",
|
||||
"top_univpll2_d4",
|
||||
"top_univpll2_d2",
|
||||
"top_syspll_d5";
|
||||
|
||||
Example:
|
||||
|
||||
afe: mt2701-afe-pcm@11220000 {
|
||||
compatible = "mediatek,mt2701-audio";
|
||||
reg = <0 0x11220000 0 0x2000>,
|
||||
<0 0x112A0000 0 0x20000>;
|
||||
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&infracfg CLK_INFRA_AUDIO>,
|
||||
<&topckgen CLK_TOP_AUD_MUX1_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_MUX2_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_MUX1_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_MUX2_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_48K_TIMING>,
|
||||
<&topckgen CLK_TOP_AUD_44K_TIMING>,
|
||||
<&topckgen CLK_TOP_AUDPLL_MUX_SEL>,
|
||||
<&topckgen CLK_TOP_APLL_SEL>,
|
||||
<&topckgen CLK_TOP_AUD1PLL_98M>,
|
||||
<&topckgen CLK_TOP_AUD2PLL_90M>,
|
||||
<&topckgen CLK_TOP_HADDS2PLL_98M>,
|
||||
<&topckgen CLK_TOP_HADDS2PLL_294M>,
|
||||
<&topckgen CLK_TOP_AUDPLL>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D4>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D8>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D16>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D24>,
|
||||
<&topckgen CLK_TOP_AUDINTBUS_SEL>,
|
||||
<&clk26m>,
|
||||
<&topckgen CLK_TOP_SYSPLL1_D4>,
|
||||
<&topckgen CLK_TOP_AUD_K1_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K2_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K3_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K4_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K5_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K6_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K1_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K2_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K3_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K4_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K5_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K6_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_I2S1_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S2_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S3_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S4_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S5_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S6_MCLK>,
|
||||
<&topckgen CLK_TOP_ASM_M_SEL>,
|
||||
<&topckgen CLK_TOP_ASM_H_SEL>,
|
||||
<&topckgen CLK_TOP_UNIVPLL2_D4>,
|
||||
<&topckgen CLK_TOP_UNIVPLL2_D2>,
|
||||
<&topckgen CLK_TOP_SYSPLL_D5>;
|
||||
|
||||
clock-names = "infra_sys_audio_clk",
|
||||
"top_audio_mux1_sel",
|
||||
"top_audio_mux2_sel",
|
||||
"top_audio_mux1_div",
|
||||
"top_audio_mux2_div",
|
||||
"top_audio_48k_timing",
|
||||
"top_audio_44k_timing",
|
||||
"top_audpll_mux_sel",
|
||||
"top_apll_sel",
|
||||
"top_aud1_pll_98M",
|
||||
"top_aud2_pll_90M",
|
||||
"top_hadds2_pll_98M",
|
||||
"top_hadds2_pll_294M",
|
||||
"top_audpll",
|
||||
"top_audpll_d4",
|
||||
"top_audpll_d8",
|
||||
"top_audpll_d16",
|
||||
"top_audpll_d24",
|
||||
"top_audintbus_sel",
|
||||
"clk_26m",
|
||||
"top_syspll1_d4",
|
||||
"top_aud_k1_src_sel",
|
||||
"top_aud_k2_src_sel",
|
||||
"top_aud_k3_src_sel",
|
||||
"top_aud_k4_src_sel",
|
||||
"top_aud_k5_src_sel",
|
||||
"top_aud_k6_src_sel",
|
||||
"top_aud_k1_src_div",
|
||||
"top_aud_k2_src_div",
|
||||
"top_aud_k3_src_div",
|
||||
"top_aud_k4_src_div",
|
||||
"top_aud_k5_src_div",
|
||||
"top_aud_k6_src_div",
|
||||
"top_aud_i2s1_mclk",
|
||||
"top_aud_i2s2_mclk",
|
||||
"top_aud_i2s3_mclk",
|
||||
"top_aud_i2s4_mclk",
|
||||
"top_aud_i2s5_mclk",
|
||||
"top_aud_i2s6_mclk",
|
||||
"top_asm_m_sel",
|
||||
"top_asm_h_sel",
|
||||
"top_univpll2_d4",
|
||||
"top_univpll2_d2",
|
||||
"top_syspll_d5";
|
||||
};
|
43
Documentation/devicetree/bindings/sound/mt2701-cs42448.txt
Normal file
43
Documentation/devicetree/bindings/sound/mt2701-cs42448.txt
Normal file
@ -0,0 +1,43 @@
|
||||
MT2701 with CS42448 CODEC
|
||||
|
||||
Required properties:
|
||||
- compatible: "mediatek,mt2701-cs42448-machine"
|
||||
- mediatek,platform: the phandle of MT2701 ASoC platform
|
||||
- audio-routing: a list of the connections between audio
|
||||
- mediatek,audio-codec: the phandles of cs42448 codec
|
||||
- mediatek,audio-codec-bt-mrg the phandles of bt-sco dummy codec
|
||||
- pinctrl-names: Should contain only one value - "default"
|
||||
- pinctrl-0: Should specify pin control groups used for this controller.
|
||||
- i2s1-in-sel-gpio1, i2s1-in-sel-gpio2: Should specify two gpio pins to
|
||||
control I2S1-in mux.
|
||||
|
||||
Example:
|
||||
|
||||
sound:sound {
|
||||
compatible = "mediatek,mt2701-cs42448-machine";
|
||||
mediatek,platform = <&afe>;
|
||||
/* CS42448 Machine name */
|
||||
audio-routing =
|
||||
"Line Out Jack", "AOUT1L",
|
||||
"Line Out Jack", "AOUT1R",
|
||||
"Line Out Jack", "AOUT2L",
|
||||
"Line Out Jack", "AOUT2R",
|
||||
"Line Out Jack", "AOUT3L",
|
||||
"Line Out Jack", "AOUT3R",
|
||||
"Line Out Jack", "AOUT4L",
|
||||
"Line Out Jack", "AOUT4R",
|
||||
"AIN1L", "AMIC",
|
||||
"AIN1R", "AMIC",
|
||||
"AIN2L", "Tuner In",
|
||||
"AIN2R", "Tuner In",
|
||||
"AIN3L", "Satellite Tuner In",
|
||||
"AIN3R", "Satellite Tuner In",
|
||||
"AIN3L", "AUX In",
|
||||
"AIN3R", "AUX In";
|
||||
mediatek,audio-codec = <&cs42448>;
|
||||
mediatek,audio-codec-bt-mrg = <&bt_sco_codec>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&aud_pins_default>;
|
||||
i2s1-in-sel-gpio1 = <&pio 53 0>;
|
||||
i2s1-in-sel-gpio2 = <&pio 54 0>;
|
||||
};
|
@ -1,8 +1,9 @@
|
||||
MT8173 with RT5650 CODECS
|
||||
MT8173 with RT5650 CODECS and HDMI via I2S
|
||||
|
||||
Required properties:
|
||||
- compatible : "mediatek,mt8173-rt5650"
|
||||
- mediatek,audio-codec: the phandles of rt5650 codecs
|
||||
and of the hdmi encoder node
|
||||
- mediatek,platform: the phandle of MT8173 ASoC platform
|
||||
|
||||
Optional subnodes:
|
||||
@ -12,12 +13,17 @@ Required codec-capture subnode properties:
|
||||
<&rt5650 0> : Default setting. Connect rt5650 I2S1 for capture. (dai_name = rt5645-aif1)
|
||||
<&rt5650 1> : Connect rt5650 I2S2 for capture. (dai_name = rt5645-aif2)
|
||||
|
||||
- mediatek,mclk: the MCLK source
|
||||
0 : external oscillator, MCLK = 12.288M
|
||||
1 : internal source from mt8173, MCLK = sampling rate*256
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "mediatek,mt8173-rt5650";
|
||||
mediatek,audio-codec = <&rt5650>;
|
||||
mediatek,audio-codec = <&rt5650 &hdmi0>;
|
||||
mediatek,platform = <&afe>;
|
||||
mediatek,mclk = <0>;
|
||||
codec-capture {
|
||||
sound-dai = <&rt5650 1>;
|
||||
};
|
||||
|
@ -8,6 +8,8 @@ Required properties:
|
||||
- interrupts: Interrupt number for McPDM
|
||||
- interrupt-parent: The parent interrupt controller
|
||||
- ti,hwmods: Name of the hwmod associated to the McPDM
|
||||
- clocks: phandle for the pdmclk provider, likely <&twl6040>
|
||||
- clock-names: Must be "pdmclk"
|
||||
|
||||
Example:
|
||||
|
||||
@ -19,3 +21,11 @@ mcpdm: mcpdm@40132000 {
|
||||
interrupt-parent = <&gic>;
|
||||
ti,hwmods = "mcpdm";
|
||||
};
|
||||
|
||||
In board DTS file the pdmclk needs to be added:
|
||||
|
||||
&mcpdm {
|
||||
clocks = <&twl6040>;
|
||||
clock-names = "pdmclk";
|
||||
status = "okay";
|
||||
};
|
||||
|
@ -373,6 +373,8 @@ Optional properties:
|
||||
- #clock-cells : it must be 0 if your system has audio_clkout
|
||||
it must be 1 if your system has audio_clkout0/1/2/3
|
||||
- clock-frequency : for all audio_clkout0/1/2/3
|
||||
- clkout-lr-asynchronous : boolean property. it indicates that audio_clkoutn
|
||||
is asynchronizes with lr-clock.
|
||||
|
||||
SSI subnode properties:
|
||||
- interrupts : Should contain SSI interrupt for PIO transfer
|
||||
|
@ -23,6 +23,11 @@ Required properties:
|
||||
- rockchip,playback-channels: max playback channels, if not set, 8 channels default.
|
||||
- rockchip,capture-channels: max capture channels, if not set, 2 channels default.
|
||||
|
||||
Required properties for controller which support multi channels
|
||||
playback/capture:
|
||||
|
||||
- rockchip,grf: the phandle of the syscon node for GRF register.
|
||||
|
||||
Example for rk3288 I2S controller:
|
||||
|
||||
i2s@ff890000 {
|
||||
|
@ -8,6 +8,11 @@ Required properties:
|
||||
|
||||
- reg : The I2C address of the device.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks: The phandle of the master clock to the CODEC
|
||||
- clock-names: Should be "mclk"
|
||||
|
||||
Pins on the device (for linking into audio routes) for RT5514:
|
||||
|
||||
* DMIC1L
|
||||
|
@ -1,35 +0,0 @@
|
||||
Samsung Exynos Odroid X2/U3 audio complex with MAX98090 codec
|
||||
|
||||
Required properties:
|
||||
- compatible : "samsung,odroidx2-audio" - for Odroid X2 board,
|
||||
"samsung,odroidu3-audio" - for Odroid U3 board
|
||||
- samsung,model : the user-visible name of this sound complex
|
||||
- samsung,i2s-controller : the phandle of the I2S controller
|
||||
- samsung,audio-codec : the phandle of the MAX98090 audio codec
|
||||
- samsung,audio-routing : a list of the connections between audio
|
||||
components; each entry is a pair of strings, the first being the
|
||||
connection's sink, the second being the connection's source;
|
||||
valid names for sources and sinks are the MAX98090's pins (as
|
||||
documented in its binding), and the jacks on the board
|
||||
For Odroid X2:
|
||||
* Headphone Jack
|
||||
* Mic Jack
|
||||
* DMIC
|
||||
|
||||
For Odroid U3:
|
||||
* Headphone Jack
|
||||
* Speakers
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "samsung,odroidu3-audio";
|
||||
samsung,i2s-controller = <&i2s0>;
|
||||
samsung,audio-codec = <&max98090>;
|
||||
samsung,model = "Odroid-X2";
|
||||
samsung,audio-routing =
|
||||
"Headphone Jack", "HPL",
|
||||
"Headphone Jack", "HPR",
|
||||
"IN1", "Mic Jack",
|
||||
"Mic Jack", "MICBIAS";
|
||||
};
|
@ -7,6 +7,14 @@ Required properties:
|
||||
|
||||
- clocks : the clock provider of SYS_MCLK
|
||||
|
||||
- VDDA-supply : the regulator provider of VDDA
|
||||
|
||||
- VDDIO-supply: the regulator provider of VDDIO
|
||||
|
||||
Optional properties:
|
||||
|
||||
- VDDD-supply : the regulator provider of VDDD
|
||||
|
||||
- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs
|
||||
The resistor can take values of 2k, 4k or 8k.
|
||||
If set to 0 it will be off.
|
||||
@ -15,17 +23,9 @@ Required properties:
|
||||
|
||||
- micbias-voltage-m-volts : the bias voltage to be used in mVolts
|
||||
The voltage can take values from 1.25V to 3V by 250mV steps
|
||||
If this node is not mentionned or the value is unknown, then
|
||||
If this node is not mentioned or the value is unknown, then
|
||||
the value is set to 1.25V.
|
||||
|
||||
- VDDA-supply : the regulator provider of VDDA
|
||||
|
||||
- VDDIO-supply: the regulator provider of VDDIO
|
||||
|
||||
Optional properties:
|
||||
|
||||
- VDDD-supply : the regulator provider of VDDD
|
||||
|
||||
Example:
|
||||
|
||||
codec: sgtl5000@0a {
|
||||
|
@ -33,11 +33,11 @@ Required properties:
|
||||
"tx" for "st,sti-uni-player" compatibility
|
||||
"rx" for "st,sti-uni-reader" compatibility
|
||||
|
||||
- version: IP version integrated in SOC.
|
||||
- st,version: IP version integrated in SOC.
|
||||
|
||||
- dai-name: DAI name that describes the IP.
|
||||
|
||||
- IP mode: IP working mode depending on associated codec.
|
||||
- st,mode: IP working mode depending on associated codec.
|
||||
"HDMI" connected to HDMI codec and support IEC HDMI formats (player only).
|
||||
"SPDIF" connected to SPDIF codec and support SPDIF formats (player only).
|
||||
"PCM" PCM standard mode for I2S or TDM bus.
|
||||
@ -47,7 +47,7 @@ Required properties ("st,sti-uni-player" compatibility only):
|
||||
- clocks: CPU_DAI IP clock source, listed in the same order than the
|
||||
CPU_DAI properties.
|
||||
|
||||
- uniperiph-id: internal SOC IP instance ID.
|
||||
- st,uniperiph-id: internal SOC IP instance ID.
|
||||
|
||||
Optional properties:
|
||||
- pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for
|
||||
@ -84,9 +84,9 @@ Example:
|
||||
dmas = <&fdma0 4 0 1>;
|
||||
dai-name = "Uni Player #2 (DAC)";
|
||||
dma-names = "tx";
|
||||
uniperiph-id = <2>;
|
||||
version = <5>;
|
||||
mode = "PCM";
|
||||
st,uniperiph-id = <2>;
|
||||
st,version = <5>;
|
||||
st,mode = "PCM";
|
||||
};
|
||||
|
||||
sti_uni_player3: sti-uni-player@3 {
|
||||
@ -100,9 +100,9 @@ Example:
|
||||
dmas = <&fdma0 7 0 1>;
|
||||
dma-names = "tx";
|
||||
dai-name = "Uni Player #3 (SPDIF)";
|
||||
uniperiph-id = <3>;
|
||||
version = <5>;
|
||||
mode = "SPDIF";
|
||||
st,uniperiph-id = <3>;
|
||||
st,version = <5>;
|
||||
st,mode = "SPDIF";
|
||||
};
|
||||
|
||||
sti_uni_reader1: sti-uni-reader@1 {
|
||||
@ -115,7 +115,7 @@ Example:
|
||||
dmas = <&fdma0 6 0 1>;
|
||||
dma-names = "rx";
|
||||
dai-name = "Uni Reader #1 (HDMI RX)";
|
||||
version = <3>;
|
||||
st,version = <3>;
|
||||
st,mode = "PCM";
|
||||
};
|
||||
|
||||
|
34
Documentation/devicetree/bindings/sound/sun4i-i2s.txt
Normal file
34
Documentation/devicetree/bindings/sound/sun4i-i2s.txt
Normal file
@ -0,0 +1,34 @@
|
||||
* Allwinner A10 I2S controller
|
||||
|
||||
The I2S bus (Inter-IC sound bus) is a serial link for digital
|
||||
audio data transfer between devices in the system.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of the followings
|
||||
- "allwinner,sun4i-a10-i2s"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: should contain the I2S interrupt.
|
||||
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
|
||||
Documentation/devicetree/bindings/dma/dma.txt
|
||||
- dma-names: should include "tx" and "rx".
|
||||
- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names.
|
||||
- clock-names: should contain followings:
|
||||
- "apb" : clock for the I2S bus interface
|
||||
- "mod" : module clock for the I2S controller
|
||||
- #sound-dai-cells : Must be equal to 0
|
||||
|
||||
Example:
|
||||
|
||||
i2s0: i2s@01c22400 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-i2s";
|
||||
reg = <0x01c22400 0x400>;
|
||||
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&apb0_gates 3>, <&i2s0_clk>;
|
||||
clock-names = "apb", "mod";
|
||||
dmas = <&dma SUN4I_DMA_NORMAL 3>,
|
||||
<&dma SUN4I_DMA_NORMAL 3>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
@ -3,7 +3,7 @@ ASoC Machine Driver
|
||||
|
||||
The ASoC machine (or board) driver is the code that glues together all the
|
||||
component drivers (e.g. codecs, platforms and DAIs). It also describes the
|
||||
relationships between each componnent which include audio paths, GPIOs,
|
||||
relationships between each component which include audio paths, GPIOs,
|
||||
interrupts, clocking, jacks and voltage regulators.
|
||||
|
||||
The machine driver can contain codec and platform specific code. It registers
|
||||
|
@ -14,7 +14,7 @@ provides a refined estimate with a delay.
|
||||
event or application query.
|
||||
The difference (tstamp - trigger_tstamp) defines the elapsed time.
|
||||
|
||||
The ALSA API provides reports two basic pieces of information, avail
|
||||
The ALSA API provides two basic pieces of information, avail
|
||||
and delay, which combined with the trigger and current system
|
||||
timestamps allow for applications to keep track of the 'fullness' of
|
||||
the ring buffer and the amount of queued samples.
|
||||
@ -53,21 +53,21 @@ case):
|
||||
The analog time is taken at the last stage of the playback, as close
|
||||
as possible to the actual transducer
|
||||
|
||||
The link time is taken at the output of the SOC/chipset as the samples
|
||||
The link time is taken at the output of the SoC/chipset as the samples
|
||||
are pushed on a link. The link time can be directly measured if
|
||||
supported in hardware by sample counters or wallclocks (e.g. with
|
||||
HDAudio 24MHz or PTP clock for networked solutions) or indirectly
|
||||
estimated (e.g. with the frame counter in USB).
|
||||
|
||||
The DMA time is measured using counters - typically the least reliable
|
||||
of all measurements due to the bursty natured of DMA transfers.
|
||||
of all measurements due to the bursty nature of DMA transfers.
|
||||
|
||||
The app time corresponds to the time tracked by an application after
|
||||
writing in the ring buffer.
|
||||
|
||||
The application can query what the hardware supports, define which
|
||||
The application can query the hardware capabilities, define which
|
||||
audio time it wants reported by selecting the relevant settings in
|
||||
audio_tstamp_config fields, get an estimate of the timestamp
|
||||
audio_tstamp_config fields, thus get an estimate of the timestamp
|
||||
accuracy. It can also request the delay-to-analog be included in the
|
||||
measurement. Direct access to the link time is very interesting on
|
||||
platforms that provide an embedded DSP; measuring directly the link
|
||||
@ -169,7 +169,7 @@ playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -51
|
||||
Example 1 shows that the timestamp at the DMA level is close to 1ms
|
||||
ahead of the actual playback time (as a side time this sort of
|
||||
measurement can help define rewind safeguards). Compensating for the
|
||||
DMA-link delay in example 2 helps remove the hardware buffering abut
|
||||
DMA-link delay in example 2 helps remove the hardware buffering but
|
||||
the information is still very jittery, with up to one sample of
|
||||
error. In example 3 where the timestamps are measured with the link
|
||||
wallclock, the timestamps show a monotonic behavior and a lower
|
||||
|
11
MAINTAINERS
11
MAINTAINERS
@ -1611,7 +1611,6 @@ F: drivers/*/*/*s3c2410*
|
||||
F: drivers/memory/samsung/*
|
||||
F: drivers/soc/samsung/*
|
||||
F: drivers/spi/spi-s3c*
|
||||
F: sound/soc/samsung/*
|
||||
F: Documentation/arm/Samsung/
|
||||
F: Documentation/devicetree/bindings/arm/samsung/
|
||||
F: Documentation/devicetree/bindings/sram/samsung-sram.txt
|
||||
@ -7355,6 +7354,13 @@ F: Documentation/devicetree/bindings/i2c/max6697.txt
|
||||
F: drivers/hwmon/max6697.c
|
||||
F: include/linux/platform_data/max6697.h
|
||||
|
||||
MAX9860 MONO AUDIO VOICE CODEC DRIVER
|
||||
M: Peter Rosin <peda@axentia.se>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/max9860.txt
|
||||
F: sound/soc/codecs/max9860.*
|
||||
|
||||
MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
|
||||
M: Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
@ -10027,7 +10033,9 @@ S: Maintained
|
||||
F: drivers/platform/x86/samsung-laptop.c
|
||||
|
||||
SAMSUNG AUDIO (ASoC) DRIVERS
|
||||
M: Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
M: Sangbeom Kim <sbkim73@samsung.com>
|
||||
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: sound/soc/samsung/
|
||||
@ -10856,6 +10864,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
W: http://alsa-project.org/main/index.php/ASoC
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/sound/
|
||||
F: Documentation/sound/alsa/soc/
|
||||
F: sound/soc/
|
||||
F: include/sound/soc*
|
||||
|
@ -887,6 +887,34 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_get_next_child_node);
|
||||
|
||||
/**
|
||||
* device_get_named_child_node - Return first matching named child node handle
|
||||
* @dev: Device to find the named child node for.
|
||||
* @childname: String to match child node name against.
|
||||
*/
|
||||
struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
||||
const char *childname)
|
||||
{
|
||||
struct fwnode_handle *child;
|
||||
|
||||
/*
|
||||
* Find first matching named child node of this device.
|
||||
* For ACPI this will be a data only sub-node.
|
||||
*/
|
||||
device_for_each_child_node(dev, child) {
|
||||
if (is_of_node(child)) {
|
||||
if (!of_node_cmp(to_of_node(child)->name, childname))
|
||||
return child;
|
||||
} else if (is_acpi_data_node(child)) {
|
||||
if (acpi_data_node_match(child, childname))
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_get_named_child_node);
|
||||
|
||||
/**
|
||||
* fwnode_handle_put - Drop reference to a device node
|
||||
* @fwnode: Pointer to the device node to drop the reference to.
|
||||
|
@ -420,6 +420,13 @@ static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwn
|
||||
container_of(fwnode, struct acpi_data_node, fwnode) : NULL;
|
||||
}
|
||||
|
||||
static inline bool acpi_data_node_match(struct fwnode_handle *fwnode,
|
||||
const char *name)
|
||||
{
|
||||
return is_acpi_data_node(fwnode) ?
|
||||
(!strcmp(to_acpi_data_node(fwnode)->name, name)) : false;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
|
||||
{
|
||||
return &adev->fwnode;
|
||||
|
@ -608,6 +608,12 @@ static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwn
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool acpi_data_node_match(struct fwnode_handle *fwnode,
|
||||
const char *name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define _WM_ARIZONA_CORE_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mfd/arizona/pdata.h>
|
||||
@ -148,8 +149,17 @@ struct arizona {
|
||||
uint16_t dac_comp_coeff;
|
||||
uint8_t dac_comp_enabled;
|
||||
struct mutex dac_comp_lock;
|
||||
|
||||
struct blocking_notifier_head notifier;
|
||||
};
|
||||
|
||||
static inline int arizona_call_notifiers(struct arizona *arizona,
|
||||
unsigned long event,
|
||||
void *data)
|
||||
{
|
||||
return blocking_notifier_call_chain(&arizona->notifier, event, data);
|
||||
}
|
||||
|
||||
int arizona_clk32k_enable(struct arizona *arizona);
|
||||
int arizona_clk32k_disable(struct arizona *arizona);
|
||||
|
||||
|
@ -238,13 +238,6 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
|
||||
#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
|
||||
#endif
|
||||
|
||||
/* Default string compare functions, Allow arch asm/prom.h to override */
|
||||
#if !defined(of_compat_cmp)
|
||||
#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2))
|
||||
#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
|
||||
#define of_node_cmp(s1, s2) strcasecmp((s1), (s2))
|
||||
#endif
|
||||
|
||||
#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
|
||||
#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
|
||||
|
||||
@ -728,6 +721,13 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag
|
||||
#define of_match_node(_matches, _node) NULL
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/* Default string compare functions, Allow arch asm/prom.h to override */
|
||||
#if !defined(of_compat_cmp)
|
||||
#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2))
|
||||
#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
|
||||
#define of_node_cmp(s1, s2) strcasecmp((s1), (s2))
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_NUMA)
|
||||
extern int of_node_to_nid(struct device_node *np);
|
||||
#else
|
||||
|
@ -77,6 +77,9 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
||||
for (child = device_get_next_child_node(dev, NULL); child; \
|
||||
child = device_get_next_child_node(dev, child))
|
||||
|
||||
struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
||||
const char *childname);
|
||||
|
||||
void fwnode_handle_put(struct fwnode_handle *fwnode);
|
||||
|
||||
unsigned int device_get_child_node_count(struct device *dev);
|
||||
|
@ -68,6 +68,7 @@ struct snd_compr_runtime {
|
||||
* @ops: pointer to DSP callbacks
|
||||
* @runtime: pointer to runtime structure
|
||||
* @device: device pointer
|
||||
* @error_work: delayed work used when closing the stream due to an error
|
||||
* @direction: stream direction, playback/recording
|
||||
* @metadata_set: metadata set flag, true when set
|
||||
* @next_track: has userspace signal next track transition, true when set
|
||||
@ -78,6 +79,7 @@ struct snd_compr_stream {
|
||||
struct snd_compr_ops *ops;
|
||||
struct snd_compr_runtime *runtime;
|
||||
struct snd_compr *device;
|
||||
struct delayed_work error_work;
|
||||
enum snd_compr_direction direction;
|
||||
bool metadata_set;
|
||||
bool next_track;
|
||||
@ -187,4 +189,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
|
||||
wake_up(&stream->runtime->sleep);
|
||||
}
|
||||
|
||||
int snd_compr_stop_error(struct snd_compr_stream *stream,
|
||||
snd_pcm_state_t state);
|
||||
|
||||
#endif
|
||||
|
48
include/sound/cs35l33.h
Normal file
48
include/sound/cs35l33.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* linux/sound/cs35l33.h -- Platform data for CS35l33
|
||||
*
|
||||
* Copyright (c) 2016 Cirrus Logic 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.
|
||||
*/
|
||||
|
||||
#ifndef __CS35L33_H
|
||||
#define __CS35L33_H
|
||||
|
||||
struct cs35l33_hg {
|
||||
bool enable_hg_algo;
|
||||
unsigned int mem_depth;
|
||||
unsigned int release_rate;
|
||||
unsigned int hd_rm;
|
||||
unsigned int ldo_thld;
|
||||
unsigned int ldo_path_disable;
|
||||
unsigned int ldo_entry_delay;
|
||||
bool vp_hg_auto;
|
||||
unsigned int vp_hg;
|
||||
unsigned int vp_hg_rate;
|
||||
unsigned int vp_hg_va;
|
||||
};
|
||||
|
||||
struct cs35l33_pdata {
|
||||
/* Boost Controller Voltage Setting */
|
||||
unsigned int boost_ctl;
|
||||
|
||||
/* Boost Controller Peak Current */
|
||||
unsigned int boost_ipk;
|
||||
|
||||
/* Amplifier Drive Select */
|
||||
unsigned int amp_drv_sel;
|
||||
|
||||
/* soft volume ramp */
|
||||
unsigned int ramp_rate;
|
||||
|
||||
/* IMON adc scale */
|
||||
unsigned int imon_adc_scale;
|
||||
|
||||
/* H/G algo configuration */
|
||||
struct cs35l33_hg hg_config;
|
||||
};
|
||||
|
||||
#endif /* __CS35L33_H */
|
@ -53,18 +53,19 @@ struct hdmi_codec_params {
|
||||
int channels;
|
||||
};
|
||||
|
||||
struct hdmi_codec_pdata;
|
||||
struct hdmi_codec_ops {
|
||||
/*
|
||||
* Called when ASoC starts an audio stream setup.
|
||||
* Optional
|
||||
*/
|
||||
int (*audio_startup)(struct device *dev);
|
||||
int (*audio_startup)(struct device *dev, void *data);
|
||||
|
||||
/*
|
||||
* Configures HDMI-encoder for audio stream.
|
||||
* Mandatory
|
||||
*/
|
||||
int (*hw_params)(struct device *dev,
|
||||
int (*hw_params)(struct device *dev, void *data,
|
||||
struct hdmi_codec_daifmt *fmt,
|
||||
struct hdmi_codec_params *hparms);
|
||||
|
||||
@ -72,19 +73,20 @@ struct hdmi_codec_ops {
|
||||
* Shuts down the audio stream.
|
||||
* Mandatory
|
||||
*/
|
||||
void (*audio_shutdown)(struct device *dev);
|
||||
void (*audio_shutdown)(struct device *dev, void *data);
|
||||
|
||||
/*
|
||||
* Mute/unmute HDMI audio stream.
|
||||
* Optional
|
||||
*/
|
||||
int (*digital_mute)(struct device *dev, bool enable);
|
||||
int (*digital_mute)(struct device *dev, void *data, bool enable);
|
||||
|
||||
/*
|
||||
* Provides EDID-Like-Data from connected HDMI device.
|
||||
* Optional
|
||||
*/
|
||||
int (*get_eld)(struct device *dev, uint8_t *buf, size_t len);
|
||||
int (*get_eld)(struct device *dev, void *data,
|
||||
uint8_t *buf, size_t len);
|
||||
};
|
||||
|
||||
/* HDMI codec initalization data */
|
||||
@ -93,6 +95,7 @@ struct hdmi_codec_pdata {
|
||||
uint i2s:1;
|
||||
uint spdif:1;
|
||||
int max_i2s_channels;
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define HDMI_CODEC_DRV_NAME "hdmi-audio-codec"
|
||||
|
@ -13,16 +13,7 @@
|
||||
#define __SIMPLE_CARD_H
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct asoc_simple_dai {
|
||||
const char *name;
|
||||
unsigned int sysclk;
|
||||
int slots;
|
||||
int slot_width;
|
||||
unsigned int tx_slot_mask;
|
||||
unsigned int rx_slot_mask;
|
||||
struct clk *clk;
|
||||
};
|
||||
#include <sound/simple_card_utils.h>
|
||||
|
||||
struct asoc_simple_card_info {
|
||||
const char *name;
|
||||
|
36
include/sound/simple_card_utils.h
Normal file
36
include/sound/simple_card_utils.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* simple_card_core.h
|
||||
*
|
||||
* Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef __SIMPLE_CARD_CORE_H
|
||||
#define __SIMPLE_CARD_CORE_H
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct asoc_simple_dai {
|
||||
const char *name;
|
||||
unsigned int sysclk;
|
||||
int slots;
|
||||
int slot_width;
|
||||
unsigned int tx_slot_mask;
|
||||
unsigned int rx_slot_mask;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
int asoc_simple_card_parse_daifmt(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct device_node *codec,
|
||||
char *prefix,
|
||||
unsigned int *retfmt);
|
||||
int asoc_simple_card_set_dailink_name(struct device *dev,
|
||||
struct snd_soc_dai_link *dai_link,
|
||||
const char *fmt, ...);
|
||||
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
||||
char *prefix);
|
||||
|
||||
#endif /* __SIMPLE_CARD_CORE_H */
|
@ -358,6 +358,7 @@ struct snd_soc_dapm_context;
|
||||
struct regulator;
|
||||
struct snd_soc_dapm_widget_list;
|
||||
struct snd_soc_dapm_update;
|
||||
enum snd_soc_dapm_direction;
|
||||
|
||||
int dapm_regulator_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
@ -382,6 +383,9 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
|
||||
int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_widget *widget,
|
||||
int num);
|
||||
struct snd_soc_dapm_widget *snd_soc_dapm_new_control(
|
||||
struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_widget *widget);
|
||||
int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
|
||||
struct snd_soc_dai *dai);
|
||||
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
|
||||
@ -451,7 +455,9 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
|
||||
|
||||
/* dapm path query */
|
||||
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
|
||||
struct snd_soc_dapm_widget_list **list);
|
||||
struct snd_soc_dapm_widget_list **list,
|
||||
bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
|
||||
enum snd_soc_dapm_direction));
|
||||
|
||||
struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
|
||||
struct snd_kcontrol *kcontrol);
|
||||
|
@ -179,6 +179,17 @@
|
||||
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \
|
||||
xmin, xmax, xsign_bit, xinvert) }
|
||||
#define SOC_SINGLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = (unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xreg, .rreg = xreg, \
|
||||
.min = xmin, .max = xmax, .platform_max = xmax, \
|
||||
.sign_bit = 7,} }
|
||||
#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||
|
@ -2,7 +2,6 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SOUND) += soundcore.o
|
||||
obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
|
||||
obj-$(CONFIG_SOUND_PRIME) += oss/
|
||||
obj-$(CONFIG_DMASOUND) += oss/
|
||||
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
|
||||
|
@ -67,6 +67,8 @@ struct snd_compr_file {
|
||||
struct snd_compr_stream stream;
|
||||
};
|
||||
|
||||
static void error_delayed_work(struct work_struct *work);
|
||||
|
||||
/*
|
||||
* a note on stream states used:
|
||||
* we use following states in the compressed core
|
||||
@ -123,6 +125,9 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
||||
snd_card_unref(compr->card);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);
|
||||
|
||||
data->stream.ops = compr->ops;
|
||||
data->stream.direction = dirn;
|
||||
data->stream.private_data = compr->private_data;
|
||||
@ -153,6 +158,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
|
||||
struct snd_compr_file *data = f->private_data;
|
||||
struct snd_compr_runtime *runtime = data->stream.runtime;
|
||||
|
||||
cancel_delayed_work_sync(&data->stream.error_work);
|
||||
|
||||
switch (runtime->state) {
|
||||
case SNDRV_PCM_STATE_RUNNING:
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
@ -237,6 +244,15 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
|
||||
avail = snd_compr_calc_avail(stream, &ioctl_avail);
|
||||
ioctl_avail.avail = avail;
|
||||
|
||||
switch (stream->runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
return -EBADFD;
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
return -EPIPE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_to_user((__u64 __user *)arg,
|
||||
&ioctl_avail, sizeof(ioctl_avail)))
|
||||
return -EFAULT;
|
||||
@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
|
||||
switch (stream->runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
case SNDRV_PCM_STATE_PREPARED:
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
case SNDRV_PCM_STATE_SUSPENDED:
|
||||
case SNDRV_PCM_STATE_DISCONNECTED:
|
||||
retval = -EBADFD;
|
||||
goto out;
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
retval = -EPIPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
avail = snd_compr_get_avail(stream);
|
||||
@ -399,10 +417,16 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
|
||||
stream = &data->stream;
|
||||
|
||||
mutex_lock(&stream->device->lock);
|
||||
if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
|
||||
|
||||
switch (stream->runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
retval = snd_compr_get_poll(stream) | POLLERR;
|
||||
goto out;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
poll_wait(f, &stream->runtime->sleep, wait);
|
||||
|
||||
avail = snd_compr_get_avail(stream);
|
||||
@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void error_delayed_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_compr_stream *stream;
|
||||
|
||||
stream = container_of(work, struct snd_compr_stream, error_work.work);
|
||||
|
||||
mutex_lock(&stream->device->lock);
|
||||
|
||||
stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
|
||||
wake_up(&stream->runtime->sleep);
|
||||
|
||||
mutex_unlock(&stream->device->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* snd_compr_stop_error: Report a fatal error on a stream
|
||||
* @stream: pointer to stream
|
||||
* @state: state to transition the stream to
|
||||
*
|
||||
* Stop the stream and set its state.
|
||||
*
|
||||
* Should be called with compressed device lock held.
|
||||
*/
|
||||
int snd_compr_stop_error(struct snd_compr_stream *stream,
|
||||
snd_pcm_state_t state)
|
||||
{
|
||||
if (stream->runtime->state == state)
|
||||
return 0;
|
||||
|
||||
stream->runtime->state = state;
|
||||
|
||||
pr_debug("Changing state to: %d\n", state);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &stream->error_work, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_compr_stop_error);
|
||||
|
||||
static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
|
||||
{
|
||||
int ret;
|
||||
|
@ -807,6 +807,36 @@ static int snd_ctl_elem_list(struct snd_card *card,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool validate_element_member_dimension(struct snd_ctl_elem_info *info)
|
||||
{
|
||||
unsigned int members;
|
||||
unsigned int i;
|
||||
|
||||
if (info->dimen.d[0] == 0)
|
||||
return true;
|
||||
|
||||
members = 1;
|
||||
for (i = 0; i < ARRAY_SIZE(info->dimen.d); ++i) {
|
||||
if (info->dimen.d[i] == 0)
|
||||
break;
|
||||
members *= info->dimen.d[i];
|
||||
|
||||
/*
|
||||
* info->count should be validated in advance, to guarantee
|
||||
* calculation soundness.
|
||||
*/
|
||||
if (members > info->count)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (++i; i < ARRAY_SIZE(info->dimen.d); ++i) {
|
||||
if (info->dimen.d[i] > 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return members == info->count;
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
@ -1274,6 +1304,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||
if (info->count < 1 ||
|
||||
info->count > max_value_counts[info->type])
|
||||
return -EINVAL;
|
||||
if (!validate_element_member_dimension(info))
|
||||
return -EINVAL;
|
||||
private_size = value_sizes[info->type] * info->count;
|
||||
|
||||
/*
|
||||
|
@ -70,11 +70,11 @@ struct seq_oss_synth {
|
||||
static int max_synth_devs;
|
||||
static struct seq_oss_synth *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
|
||||
static struct seq_oss_synth midi_synth_dev = {
|
||||
-1, /* seq_device */
|
||||
SYNTH_TYPE_MIDI, /* synth_type */
|
||||
0, /* synth_subtype */
|
||||
16, /* nr_voices */
|
||||
"MIDI", /* name */
|
||||
.seq_device = -1,
|
||||
.synth_type = SYNTH_TYPE_MIDI,
|
||||
.synth_subtype = 0,
|
||||
.nr_voices = 16,
|
||||
.name = "MIDI",
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(register_lock);
|
||||
|
@ -165,7 +165,7 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
|
||||
snd_seq_timer_update_tick(&tmr->tick, resolution);
|
||||
|
||||
/* register actual time of this timer update */
|
||||
do_gettimeofday(&tmr->last_update);
|
||||
ktime_get_ts64(&tmr->last_update);
|
||||
|
||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
||||
|
||||
@ -392,7 +392,7 @@ static int seq_timer_start(struct snd_seq_timer *tmr)
|
||||
return -EINVAL;
|
||||
snd_timer_start(tmr->timeri, tmr->ticks);
|
||||
tmr->running = 1;
|
||||
do_gettimeofday(&tmr->last_update);
|
||||
ktime_get_ts64(&tmr->last_update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -420,7 +420,7 @@ static int seq_timer_continue(struct snd_seq_timer *tmr)
|
||||
}
|
||||
snd_timer_start(tmr->timeri, tmr->ticks);
|
||||
tmr->running = 1;
|
||||
do_gettimeofday(&tmr->last_update);
|
||||
ktime_get_ts64(&tmr->last_update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -444,17 +444,12 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
|
||||
spin_lock_irqsave(&tmr->lock, flags);
|
||||
cur_time = tmr->cur_time;
|
||||
if (tmr->running) {
|
||||
struct timeval tm;
|
||||
int usec;
|
||||
do_gettimeofday(&tm);
|
||||
usec = (int)(tm.tv_usec - tmr->last_update.tv_usec);
|
||||
if (usec < 0) {
|
||||
cur_time.tv_nsec += (1000000 + usec) * 1000;
|
||||
cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec - 1;
|
||||
} else {
|
||||
cur_time.tv_nsec += usec * 1000;
|
||||
cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec;
|
||||
}
|
||||
struct timespec64 tm;
|
||||
|
||||
ktime_get_ts64(&tm);
|
||||
tm = timespec64_sub(tm, tmr->last_update);
|
||||
cur_time.tv_nsec = tm.tv_nsec;
|
||||
cur_time.tv_sec = tm.tv_sec;
|
||||
snd_seq_sanity_real_time(&cur_time);
|
||||
}
|
||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
||||
|
@ -52,7 +52,7 @@ struct snd_seq_timer {
|
||||
unsigned int skew;
|
||||
unsigned int skew_base;
|
||||
|
||||
struct timeval last_update; /* time of last clock update, used for interpolation */
|
||||
struct timespec64 last_update; /* time of last clock update, used for interpolation */
|
||||
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
@ -353,7 +353,8 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap,
|
||||
int hdmi_slot = 0;
|
||||
/* fill actual channel mappings in ALSA channel (i) order */
|
||||
for (i = 0; i < ch_alloc->channels; i++) {
|
||||
while (!ch_alloc->speakers[7 - hdmi_slot] && !WARN_ON(hdmi_slot >= 8))
|
||||
while (!WARN_ON(hdmi_slot >= 8) &&
|
||||
!ch_alloc->speakers[7 - hdmi_slot])
|
||||
hdmi_slot++; /* skip zero slots */
|
||||
|
||||
hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++;
|
||||
@ -430,6 +431,12 @@ static int to_cea_slot(int ordered_ca, unsigned char pos)
|
||||
int mask = snd_hdac_chmap_to_spk_mask(pos);
|
||||
int i;
|
||||
|
||||
/* Add sanity check to pass klockwork check.
|
||||
* This should never happen.
|
||||
*/
|
||||
if (ordered_ca >= ARRAY_SIZE(channel_allocations))
|
||||
return -1;
|
||||
|
||||
if (mask) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (channel_allocations[ordered_ca].speakers[7 - i] == mask)
|
||||
@ -456,7 +463,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_spk_to_chmap);
|
||||
/* from CEA slot to ALSA API channel position */
|
||||
static int from_cea_slot(int ordered_ca, unsigned char slot)
|
||||
{
|
||||
int mask = channel_allocations[ordered_ca].speakers[7 - slot];
|
||||
int mask;
|
||||
|
||||
/* Add sanity check to pass klockwork check.
|
||||
* This should never happen.
|
||||
*/
|
||||
if (slot >= 8)
|
||||
return 0;
|
||||
|
||||
mask = channel_allocations[ordered_ca].speakers[7 - slot];
|
||||
|
||||
return snd_hdac_spk_to_chmap(mask);
|
||||
}
|
||||
@ -523,7 +538,8 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
|
||||
int ordered_ca = get_channel_allocation_order(ca);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i < channel_allocations[ordered_ca].channels)
|
||||
if (ordered_ca < ARRAY_SIZE(channel_allocations) &&
|
||||
i < channel_allocations[ordered_ca].channels)
|
||||
map[i] = from_cea_slot(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f);
|
||||
else
|
||||
map[i] = 0;
|
||||
@ -551,6 +567,12 @@ int snd_hdac_get_active_channels(int ca)
|
||||
{
|
||||
int ordered_ca = get_channel_allocation_order(ca);
|
||||
|
||||
/* Add sanity check to pass klockwork check.
|
||||
* This should never happen.
|
||||
*/
|
||||
if (ordered_ca >= ARRAY_SIZE(channel_allocations))
|
||||
ordered_ca = 0;
|
||||
|
||||
return channel_allocations[ordered_ca].channels;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_get_active_channels);
|
||||
|
@ -121,7 +121,7 @@ int snd_ak4114_create(struct snd_card *card,
|
||||
|
||||
__fail:
|
||||
snd_ak4114_free(chip);
|
||||
return err < 0 ? err : -EIO;
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ak4114_create);
|
||||
|
||||
|
@ -110,7 +110,7 @@ int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t
|
||||
|
||||
__fail:
|
||||
snd_ak4117_free(chip);
|
||||
return err < 0 ? err : -EIO;
|
||||
return err;
|
||||
}
|
||||
|
||||
void snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val)
|
||||
|
@ -170,15 +170,4 @@ static struct isa_driver snd_ad1848_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_ad1848_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_ad1848_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_ad1848_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_ad1848_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_ad1848_init);
|
||||
module_exit(alsa_card_ad1848_exit);
|
||||
module_isa_driver(snd_ad1848_driver, SNDRV_CARDS);
|
||||
|
@ -112,15 +112,4 @@ static struct isa_driver snd_adlib_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_adlib_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_adlib_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_adlib_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_adlib_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_adlib_init);
|
||||
module_exit(alsa_card_adlib_exit);
|
||||
module_isa_driver(snd_adlib_driver, SNDRV_CARDS);
|
||||
|
@ -469,15 +469,4 @@ static struct isa_driver snd_cmi8328_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init alsa_card_cmi8328_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_cmi8328_driver, CMI8328_MAX);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_cmi8328_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_cmi8328_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_cmi8328_init)
|
||||
module_exit(alsa_card_cmi8328_exit)
|
||||
module_isa_driver(snd_cmi8328_driver, CMI8328_MAX);
|
||||
|
@ -186,15 +186,4 @@ static struct isa_driver snd_cs4231_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_cs4231_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_cs4231_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_cs4231_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_cs4231_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_cs4231_init);
|
||||
module_exit(alsa_card_cs4231_exit);
|
||||
module_isa_driver(snd_cs4231_driver, SNDRV_CARDS);
|
||||
|
@ -634,15 +634,4 @@ static struct isa_driver snd_galaxy_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_galaxy_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_galaxy_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_galaxy_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_galaxy_init);
|
||||
module_exit(alsa_card_galaxy_exit);
|
||||
module_isa_driver(snd_galaxy_driver, SNDRV_CARDS);
|
||||
|
@ -229,15 +229,4 @@ static struct isa_driver snd_gusclassic_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_gusclassic_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_gusclassic_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_gusclassic_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_gusclassic_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_gusclassic_init);
|
||||
module_exit(alsa_card_gusclassic_exit);
|
||||
module_isa_driver(snd_gusclassic_driver, SNDRV_CARDS);
|
||||
|
@ -358,15 +358,4 @@ static struct isa_driver snd_gusextreme_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_gusextreme_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_gusextreme_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_gusextreme_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_gusextreme_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_gusextreme_init);
|
||||
module_exit(alsa_card_gusextreme_exit);
|
||||
module_isa_driver(snd_gusextreme_driver, SNDRV_CARDS);
|
||||
|
@ -370,15 +370,4 @@ static struct isa_driver snd_gusmax_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init alsa_card_gusmax_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_gusmax_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_gusmax_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_gusmax_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_gusmax_init)
|
||||
module_exit(alsa_card_gusmax_exit)
|
||||
module_isa_driver(snd_gusmax_driver, SNDRV_CARDS);
|
||||
|
@ -387,15 +387,4 @@ static struct isa_driver snd_jazz16_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init alsa_card_jazz16_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_jazz16_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_jazz16_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_jazz16_init)
|
||||
module_exit(alsa_card_jazz16_exit)
|
||||
module_isa_driver(snd_jazz16_driver, SNDRV_CARDS);
|
||||
|
@ -251,15 +251,4 @@ static struct isa_driver snd_sb8_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init alsa_card_sb8_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_sb8_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_sb8_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_sb8_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_sb8_init)
|
||||
module_exit(alsa_card_sb8_exit)
|
||||
module_isa_driver(snd_sb8_driver, SNDRV_CARDS);
|
||||
|
@ -711,15 +711,4 @@ static struct isa_driver snd_sc6000_driver = {
|
||||
};
|
||||
|
||||
|
||||
static int __init alsa_card_sc6000_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_sc6000_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_sc6000_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_sc6000_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_sc6000_init)
|
||||
module_exit(alsa_card_sc6000_exit)
|
||||
module_isa_driver(snd_sc6000_driver, SNDRV_CARDS);
|
||||
|
@ -254,7 +254,7 @@ static void ad_write(ad1848_info * devc, int reg, int data)
|
||||
|
||||
static void wait_for_calibration(ad1848_info * devc)
|
||||
{
|
||||
int timeout = 0;
|
||||
int timeout;
|
||||
|
||||
/*
|
||||
* Wait until the auto calibration process has finished.
|
||||
|
@ -482,13 +482,13 @@ static struct orVals orDMA[] __initdata = {
|
||||
};
|
||||
|
||||
static struct aedsp16_info ae_config = {
|
||||
DEF_AEDSP16_IOB,
|
||||
DEF_AEDSP16_IRQ,
|
||||
DEF_AEDSP16_MRQ,
|
||||
DEF_AEDSP16_DMA,
|
||||
-1,
|
||||
-1,
|
||||
INIT_NONE
|
||||
.base_io = DEF_AEDSP16_IOB,
|
||||
.irq = DEF_AEDSP16_IRQ,
|
||||
.mpu_irq = DEF_AEDSP16_MRQ,
|
||||
.dma = DEF_AEDSP16_DMA,
|
||||
.mss_base = -1,
|
||||
.mpu_base = -1,
|
||||
.init = INIT_NONE
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1,2 +1,29 @@
|
||||
extern int mod_firmware_load(const char *fn, char **fp);
|
||||
#include <linux/fs.h>
|
||||
|
||||
/**
|
||||
* mod_firmware_load - load sound driver firmware
|
||||
* @fn: filename
|
||||
* @fp: return for the buffer.
|
||||
*
|
||||
* Load the firmware for a sound module (up to 128K) into a buffer.
|
||||
* The buffer is returned in *fp. It is allocated with vmalloc so is
|
||||
* virtually linear and not DMAable. The caller should free it with
|
||||
* vfree when finished.
|
||||
*
|
||||
* The length of the buffer is returned on a successful load, the
|
||||
* value zero on a failure.
|
||||
*
|
||||
* Caution: This API is not recommended. Firmware should be loaded via
|
||||
* request_firmware.
|
||||
*/
|
||||
static inline int mod_firmware_load(const char *fn, char **fp)
|
||||
{
|
||||
loff_t size;
|
||||
int err;
|
||||
|
||||
err = kernel_read_file_from_path((char *)fn, (void **)fp, &size,
|
||||
131072, READING_FIRMWARE);
|
||||
if (err < 0)
|
||||
return 0;
|
||||
return size;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "sound_config.h"
|
||||
|
||||
static volatile int initialized, opened, tmr_running;
|
||||
static volatile time_t tmr_offs, tmr_ctr;
|
||||
static volatile unsigned int tmr_offs, tmr_ctr;
|
||||
static volatile unsigned long ticks_offs;
|
||||
static volatile int curr_tempo, curr_timebase;
|
||||
static volatile unsigned long curr_ticks;
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "sound_config.h"
|
||||
|
||||
static volatile int opened, tmr_running;
|
||||
static volatile time_t tmr_offs, tmr_ctr;
|
||||
static volatile unsigned int tmr_offs, tmr_ctr;
|
||||
static volatile unsigned long ticks_offs;
|
||||
static volatile int curr_tempo, curr_timebase;
|
||||
static volatile unsigned long curr_ticks;
|
||||
|
@ -1615,23 +1615,23 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
|
||||
int i;
|
||||
struct regs_cs4382 cs_read = {0};
|
||||
struct regs_cs4382 cs_def = {
|
||||
0x00000001, /* Mode Control 1 */
|
||||
0x00000000, /* Mode Control 2 */
|
||||
0x00000084, /* Mode Control 3 */
|
||||
0x00000000, /* Filter Control */
|
||||
0x00000000, /* Invert Control */
|
||||
0x00000024, /* Mixing Control Pair 1 */
|
||||
0x00000000, /* Vol Control A1 */
|
||||
0x00000000, /* Vol Control B1 */
|
||||
0x00000024, /* Mixing Control Pair 2 */
|
||||
0x00000000, /* Vol Control A2 */
|
||||
0x00000000, /* Vol Control B2 */
|
||||
0x00000024, /* Mixing Control Pair 3 */
|
||||
0x00000000, /* Vol Control A3 */
|
||||
0x00000000, /* Vol Control B3 */
|
||||
0x00000024, /* Mixing Control Pair 4 */
|
||||
0x00000000, /* Vol Control A4 */
|
||||
0x00000000 /* Vol Control B4 */
|
||||
.mode_control_1 = 0x00000001, /* Mode Control 1 */
|
||||
.mode_control_2 = 0x00000000, /* Mode Control 2 */
|
||||
.mode_control_3 = 0x00000084, /* Mode Control 3 */
|
||||
.filter_control = 0x00000000, /* Filter Control */
|
||||
.invert_control = 0x00000000, /* Invert Control */
|
||||
.mix_control_P1 = 0x00000024, /* Mixing Control Pair 1 */
|
||||
.vol_control_A1 = 0x00000000, /* Vol Control A1 */
|
||||
.vol_control_B1 = 0x00000000, /* Vol Control B1 */
|
||||
.mix_control_P2 = 0x00000024, /* Mixing Control Pair 2 */
|
||||
.vol_control_A2 = 0x00000000, /* Vol Control A2 */
|
||||
.vol_control_B2 = 0x00000000, /* Vol Control B2 */
|
||||
.mix_control_P3 = 0x00000024, /* Mixing Control Pair 3 */
|
||||
.vol_control_A3 = 0x00000000, /* Vol Control A3 */
|
||||
.vol_control_B3 = 0x00000000, /* Vol Control B3 */
|
||||
.mix_control_P4 = 0x00000024, /* Mixing Control Pair 4 */
|
||||
.vol_control_A4 = 0x00000000, /* Vol Control A4 */
|
||||
.vol_control_B4 = 0x00000000 /* Vol Control B4 */
|
||||
};
|
||||
|
||||
if (hw->model == CTSB1270) {
|
||||
|
@ -1272,11 +1272,11 @@ static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol,
|
||||
|
||||
chip = snd_kcontrol_chip(kcontrol);
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = ECHOGAIN_MINOUT;
|
||||
uinfo->value.integer.max = ECHOGAIN_MAXOUT;
|
||||
uinfo->dimen.d[0] = num_busses_out(chip);
|
||||
uinfo->dimen.d[1] = num_busses_in(chip);
|
||||
uinfo->count = uinfo->dimen.d[0] * uinfo->dimen.d[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1344,11 +1344,11 @@ static int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol,
|
||||
|
||||
chip = snd_kcontrol_chip(kcontrol);
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = ECHOGAIN_MINOUT;
|
||||
uinfo->value.integer.max = ECHOGAIN_MAXOUT;
|
||||
uinfo->dimen.d[0] = num_busses_out(chip);
|
||||
uinfo->dimen.d[1] = num_pipes_out(chip);
|
||||
uinfo->count = uinfo->dimen.d[0] * uinfo->dimen.d[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1728,7 +1728,6 @@ static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 96;
|
||||
uinfo->value.integer.min = ECHOGAIN_MINOUT;
|
||||
uinfo->value.integer.max = 0;
|
||||
#ifdef ECHOCARD_HAS_VMIXER
|
||||
@ -1738,6 +1737,7 @@ static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol,
|
||||
#endif
|
||||
uinfo->dimen.d[1] = 16; /* 16 channels */
|
||||
uinfo->dimen.d[2] = 2; /* 0=level, 1=peak */
|
||||
uinfo->count = uinfo->dimen.d[0] * uinfo->dimen.d[1] * uinfo->dimen.d[2];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3584,6 +3584,12 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
|
||||
bool reset;
|
||||
|
||||
spdif = snd_hda_spdif_out_of_nid(codec, nid);
|
||||
/* Add sanity check to pass klockwork check.
|
||||
* This should never happen.
|
||||
*/
|
||||
if (WARN_ON(spdif == NULL))
|
||||
return;
|
||||
|
||||
curr_fmt = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_STREAM_FORMAT, 0);
|
||||
reset = codec->spdif_status_reset &&
|
||||
@ -3768,7 +3774,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
|
||||
spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
|
||||
if (mout->dig_out_nid && mout->share_spdif &&
|
||||
mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
|
||||
if (chs == 2 &&
|
||||
if (chs == 2 && spdif != NULL &&
|
||||
snd_hda_is_supported_format(codec, mout->dig_out_nid,
|
||||
format) &&
|
||||
!(spdif->status & IEC958_AES0_NONAUDIO)) {
|
||||
|
@ -2492,10 +2492,6 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec)
|
||||
if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
|
||||
return -ENOMEM;
|
||||
spec->have_aamix_ctl = 1;
|
||||
/* if no explicit aamix path is present (e.g. for Realtek codecs),
|
||||
* enable aamix as default -- just for compatibility
|
||||
*/
|
||||
spec->aamix_mode = !has_aamix_out_paths(spec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1680,6 +1680,11 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
|
||||
/* Add sanity check to pass klockwork check.
|
||||
* This should never happen.
|
||||
*/
|
||||
if (WARN_ON(spdif == NULL))
|
||||
return true;
|
||||
non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
|
||||
mutex_unlock(&codec->spdif_mutex);
|
||||
return non_pcm;
|
||||
|
@ -3718,6 +3718,9 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
|
||||
case 0x10ec0295:
|
||||
alc_process_coef_fw(codec, coef0225);
|
||||
break;
|
||||
case 0x10ec0867:
|
||||
alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
|
||||
break;
|
||||
}
|
||||
codec_dbg(codec, "Headset jack set to unplugged mode.\n");
|
||||
}
|
||||
@ -3805,6 +3808,9 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
|
||||
alc_process_coef_fw(codec, coef0293);
|
||||
snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
|
||||
break;
|
||||
case 0x10ec0867:
|
||||
alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
|
||||
/* fallthru */
|
||||
case 0x10ec0662:
|
||||
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
|
||||
snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
|
||||
@ -3899,6 +3905,9 @@ static void alc_headset_mode_default(struct hda_codec *codec)
|
||||
case 0x10ec0668:
|
||||
alc_process_coef_fw(codec, coef0688);
|
||||
break;
|
||||
case 0x10ec0867:
|
||||
alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
|
||||
break;
|
||||
}
|
||||
codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
|
||||
}
|
||||
@ -3989,6 +3998,9 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
|
||||
case 0x10ec0295:
|
||||
alc_process_coef_fw(codec, coef0225);
|
||||
break;
|
||||
case 0x10ec0867:
|
||||
alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
|
||||
break;
|
||||
}
|
||||
codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
|
||||
}
|
||||
@ -4166,6 +4178,9 @@ static void alc_determine_headset_type(struct hda_codec *codec)
|
||||
val = alc_read_coef_idx(codec, 0x46);
|
||||
is_ctia = (val & 0x00f0) == 0x00f0;
|
||||
break;
|
||||
case 0x10ec0867:
|
||||
is_ctia = true;
|
||||
break;
|
||||
}
|
||||
|
||||
codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
|
||||
@ -6532,6 +6547,8 @@ enum {
|
||||
ALC668_FIXUP_DELL_XPS13,
|
||||
ALC662_FIXUP_ASUS_Nx50,
|
||||
ALC668_FIXUP_ASUS_Nx51,
|
||||
ALC891_FIXUP_HEADSET_MODE,
|
||||
ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
|
||||
};
|
||||
|
||||
static const struct hda_fixup alc662_fixups[] = {
|
||||
@ -6787,6 +6804,20 @@ static const struct hda_fixup alc662_fixups[] = {
|
||||
.chained = true,
|
||||
.chain_id = ALC662_FIXUP_BASS_CHMAP,
|
||||
},
|
||||
[ALC891_FIXUP_HEADSET_MODE] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_headset_mode,
|
||||
},
|
||||
[ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
|
||||
{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
|
||||
{ }
|
||||
},
|
||||
.chained = true,
|
||||
.chain_id = ALC891_FIXUP_HEADSET_MODE
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc662_fixup_tbl[] = {
|
||||
@ -6903,6 +6934,11 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
|
||||
};
|
||||
|
||||
static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
|
||||
SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
|
||||
{0x17, 0x02211010},
|
||||
{0x18, 0x01a19030},
|
||||
{0x1a, 0x01813040},
|
||||
{0x21, 0x01014020}),
|
||||
SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
|
||||
{0x14, 0x01014010},
|
||||
{0x18, 0x01a19020},
|
||||
@ -7091,7 +7127,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
|
||||
HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc882),
|
||||
HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
|
||||
HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
|
||||
HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
|
||||
HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
|
||||
|
@ -965,7 +965,7 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel)
|
||||
int err;
|
||||
struct mixart_msg request;
|
||||
struct mixart_set_out_audio_level audio_level;
|
||||
u32 resp;
|
||||
u32 resp = 0;
|
||||
|
||||
if(chip->pipe_out_ana.status == PIPE_UNDEFINED)
|
||||
return -EINVAL; /* no pipe defined */
|
||||
|
@ -1496,7 +1496,7 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
|
||||
f = PAGE_SIZE;
|
||||
while ((size + (f >> 1) - 1) <= (f << 7) && (f << 1) > period)
|
||||
f = f >> 1;
|
||||
pages = (size + f - 1) / f;
|
||||
pages = DIV_ROUND_UP(size, f);
|
||||
data->size = size;
|
||||
data->pages = pages;
|
||||
snd_printdd
|
||||
|
@ -991,6 +991,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
master_vol = NULL;
|
||||
if (pm7500)
|
||||
err = build_mixers(chip,
|
||||
ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500),
|
||||
|
@ -63,9 +63,6 @@ MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
|
||||
module_param(enable, bool, 0644);
|
||||
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
|
||||
|
||||
/* Use workqueue */
|
||||
static struct workqueue_struct *aica_queue;
|
||||
|
||||
/* Simple platform device */
|
||||
static struct platform_device *pd;
|
||||
static struct resource aica_memory_space[2] = {
|
||||
@ -327,7 +324,7 @@ static void aica_period_elapsed(unsigned long timer_var)
|
||||
dreamcastcard->current_period = play_period;
|
||||
if (unlikely(dreamcastcard->dma_check == 0))
|
||||
dreamcastcard->dma_check = 1;
|
||||
queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
|
||||
schedule_work(&(dreamcastcard->spu_dma_work));
|
||||
}
|
||||
|
||||
static void spu_begin_dma(struct snd_pcm_substream *substream)
|
||||
@ -337,7 +334,7 @@ static void spu_begin_dma(struct snd_pcm_substream *substream)
|
||||
runtime = substream->runtime;
|
||||
dreamcastcard = substream->pcm->private_data;
|
||||
/*get the queue to do the work */
|
||||
queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
|
||||
schedule_work(&(dreamcastcard->spu_dma_work));
|
||||
/* Timer may already be running */
|
||||
if (unlikely(dreamcastcard->timer.data)) {
|
||||
mod_timer(&dreamcastcard->timer, jiffies + 4);
|
||||
@ -381,7 +378,7 @@ static int snd_aicapcm_pcm_close(struct snd_pcm_substream
|
||||
*substream)
|
||||
{
|
||||
struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
|
||||
flush_workqueue(aica_queue);
|
||||
flush_work(&(dreamcastcard->spu_dma_work));
|
||||
if (dreamcastcard->timer.data)
|
||||
del_timer(&dreamcastcard->timer);
|
||||
kfree(dreamcastcard->channel);
|
||||
@ -633,9 +630,6 @@ static int snd_aica_probe(struct platform_device *devptr)
|
||||
if (unlikely(err < 0))
|
||||
goto freedreamcast;
|
||||
platform_set_drvdata(devptr, dreamcastcard);
|
||||
aica_queue = create_workqueue(CARD_NAME);
|
||||
if (unlikely(!aica_queue))
|
||||
goto freedreamcast;
|
||||
snd_printk
|
||||
("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
|
||||
return 0;
|
||||
@ -671,10 +665,6 @@ static int __init aica_init(void)
|
||||
|
||||
static void __exit aica_exit(void)
|
||||
{
|
||||
/* Destroy the aica kernel thread *
|
||||
* being extra cautious to check if it exists*/
|
||||
if (likely(aica_queue))
|
||||
destroy_workqueue(aica_queue);
|
||||
platform_device_unregister(pd);
|
||||
platform_driver_unregister(&snd_aica_driver);
|
||||
/* Kill any sound still playing and reset ARM7 to safe state */
|
||||
|
@ -10,6 +10,7 @@ if SND_ATMEL_SOC
|
||||
|
||||
config SND_ATMEL_SOC_PDC
|
||||
tristate
|
||||
depends on HAS_DMA
|
||||
default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m
|
||||
default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y)
|
||||
|
||||
|
@ -593,11 +593,6 @@ static int atmel_classd_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "no memory resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
io_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(io_base)) {
|
||||
ret = PTR_ERR(io_base);
|
||||
|
@ -624,11 +624,6 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "no memory resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
io_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(io_base)) {
|
||||
ret = PTR_ERR(io_base);
|
||||
|
@ -321,7 +321,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
dma_params = &ssc_dma_params[dai->id][dir];
|
||||
dma_params = &ssc_dma_params[pdev->id][dir];
|
||||
dma_params->ssc = ssc_p->ssc;
|
||||
dma_params->substream = substream;
|
||||
|
||||
|
@ -7,3 +7,12 @@ config SND_BCM2835_SOC_I2S
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the BCM2835 I2S interface. You will also need
|
||||
to select the audio interfaces to support below.
|
||||
|
||||
config SND_SOC_CYGNUS
|
||||
tristate "SoC platform audio for Broadcom Cygnus chips"
|
||||
depends on ARCH_BCM_CYGNUS || COMPILE_TEST
|
||||
help
|
||||
Say Y if you want to add support for ASoC audio on Broadcom
|
||||
Cygnus chips (bcm958300, bcm958305, bcm911360)
|
||||
|
||||
If you don't know what to do here, say N.
|
@ -3,3 +3,8 @@ snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o
|
||||
|
||||
obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
|
||||
|
||||
# CYGNUS Platform Support
|
||||
snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o
|
||||
|
||||
|
861
sound/soc/bcm/cygnus-pcm.c
Normal file
861
sound/soc/bcm/cygnus-pcm.c
Normal file
@ -0,0 +1,861 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
#include "cygnus-ssp.h"
|
||||
|
||||
/* Register offset needed for ASoC PCM module */
|
||||
|
||||
#define INTH_R5F_STATUS_OFFSET 0x040
|
||||
#define INTH_R5F_CLEAR_OFFSET 0x048
|
||||
#define INTH_R5F_MASK_SET_OFFSET 0x050
|
||||
#define INTH_R5F_MASK_CLEAR_OFFSET 0x054
|
||||
|
||||
#define BF_REARM_FREE_MARK_OFFSET 0x344
|
||||
#define BF_REARM_FULL_MARK_OFFSET 0x348
|
||||
|
||||
/* Ring Buffer Ctrl Regs --- Start */
|
||||
/* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_RDADDR_REG_BASE */
|
||||
#define SRC_RBUF_0_RDADDR_OFFSET 0x500
|
||||
#define SRC_RBUF_1_RDADDR_OFFSET 0x518
|
||||
#define SRC_RBUF_2_RDADDR_OFFSET 0x530
|
||||
#define SRC_RBUF_3_RDADDR_OFFSET 0x548
|
||||
#define SRC_RBUF_4_RDADDR_OFFSET 0x560
|
||||
#define SRC_RBUF_5_RDADDR_OFFSET 0x578
|
||||
#define SRC_RBUF_6_RDADDR_OFFSET 0x590
|
||||
|
||||
/* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_WRADDR_REG_BASE */
|
||||
#define SRC_RBUF_0_WRADDR_OFFSET 0x504
|
||||
#define SRC_RBUF_1_WRADDR_OFFSET 0x51c
|
||||
#define SRC_RBUF_2_WRADDR_OFFSET 0x534
|
||||
#define SRC_RBUF_3_WRADDR_OFFSET 0x54c
|
||||
#define SRC_RBUF_4_WRADDR_OFFSET 0x564
|
||||
#define SRC_RBUF_5_WRADDR_OFFSET 0x57c
|
||||
#define SRC_RBUF_6_WRADDR_OFFSET 0x594
|
||||
|
||||
/* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_BASEADDR_REG_BASE */
|
||||
#define SRC_RBUF_0_BASEADDR_OFFSET 0x508
|
||||
#define SRC_RBUF_1_BASEADDR_OFFSET 0x520
|
||||
#define SRC_RBUF_2_BASEADDR_OFFSET 0x538
|
||||
#define SRC_RBUF_3_BASEADDR_OFFSET 0x550
|
||||
#define SRC_RBUF_4_BASEADDR_OFFSET 0x568
|
||||
#define SRC_RBUF_5_BASEADDR_OFFSET 0x580
|
||||
#define SRC_RBUF_6_BASEADDR_OFFSET 0x598
|
||||
|
||||
/* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_ENDADDR_REG_BASE */
|
||||
#define SRC_RBUF_0_ENDADDR_OFFSET 0x50c
|
||||
#define SRC_RBUF_1_ENDADDR_OFFSET 0x524
|
||||
#define SRC_RBUF_2_ENDADDR_OFFSET 0x53c
|
||||
#define SRC_RBUF_3_ENDADDR_OFFSET 0x554
|
||||
#define SRC_RBUF_4_ENDADDR_OFFSET 0x56c
|
||||
#define SRC_RBUF_5_ENDADDR_OFFSET 0x584
|
||||
#define SRC_RBUF_6_ENDADDR_OFFSET 0x59c
|
||||
|
||||
/* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_FREE_MARK_REG_BASE */
|
||||
#define SRC_RBUF_0_FREE_MARK_OFFSET 0x510
|
||||
#define SRC_RBUF_1_FREE_MARK_OFFSET 0x528
|
||||
#define SRC_RBUF_2_FREE_MARK_OFFSET 0x540
|
||||
#define SRC_RBUF_3_FREE_MARK_OFFSET 0x558
|
||||
#define SRC_RBUF_4_FREE_MARK_OFFSET 0x570
|
||||
#define SRC_RBUF_5_FREE_MARK_OFFSET 0x588
|
||||
#define SRC_RBUF_6_FREE_MARK_OFFSET 0x5a0
|
||||
|
||||
/* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_RDADDR_REG_BASE */
|
||||
#define DST_RBUF_0_RDADDR_OFFSET 0x5c0
|
||||
#define DST_RBUF_1_RDADDR_OFFSET 0x5d8
|
||||
#define DST_RBUF_2_RDADDR_OFFSET 0x5f0
|
||||
#define DST_RBUF_3_RDADDR_OFFSET 0x608
|
||||
#define DST_RBUF_4_RDADDR_OFFSET 0x620
|
||||
#define DST_RBUF_5_RDADDR_OFFSET 0x638
|
||||
|
||||
/* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_WRADDR_REG_BASE */
|
||||
#define DST_RBUF_0_WRADDR_OFFSET 0x5c4
|
||||
#define DST_RBUF_1_WRADDR_OFFSET 0x5dc
|
||||
#define DST_RBUF_2_WRADDR_OFFSET 0x5f4
|
||||
#define DST_RBUF_3_WRADDR_OFFSET 0x60c
|
||||
#define DST_RBUF_4_WRADDR_OFFSET 0x624
|
||||
#define DST_RBUF_5_WRADDR_OFFSET 0x63c
|
||||
|
||||
/* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_BASEADDR_REG_BASE */
|
||||
#define DST_RBUF_0_BASEADDR_OFFSET 0x5c8
|
||||
#define DST_RBUF_1_BASEADDR_OFFSET 0x5e0
|
||||
#define DST_RBUF_2_BASEADDR_OFFSET 0x5f8
|
||||
#define DST_RBUF_3_BASEADDR_OFFSET 0x610
|
||||
#define DST_RBUF_4_BASEADDR_OFFSET 0x628
|
||||
#define DST_RBUF_5_BASEADDR_OFFSET 0x640
|
||||
|
||||
/* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_ENDADDR_REG_BASE */
|
||||
#define DST_RBUF_0_ENDADDR_OFFSET 0x5cc
|
||||
#define DST_RBUF_1_ENDADDR_OFFSET 0x5e4
|
||||
#define DST_RBUF_2_ENDADDR_OFFSET 0x5fc
|
||||
#define DST_RBUF_3_ENDADDR_OFFSET 0x614
|
||||
#define DST_RBUF_4_ENDADDR_OFFSET 0x62c
|
||||
#define DST_RBUF_5_ENDADDR_OFFSET 0x644
|
||||
|
||||
/* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_FULL_MARK_REG_BASE */
|
||||
#define DST_RBUF_0_FULL_MARK_OFFSET 0x5d0
|
||||
#define DST_RBUF_1_FULL_MARK_OFFSET 0x5e8
|
||||
#define DST_RBUF_2_FULL_MARK_OFFSET 0x600
|
||||
#define DST_RBUF_3_FULL_MARK_OFFSET 0x618
|
||||
#define DST_RBUF_4_FULL_MARK_OFFSET 0x630
|
||||
#define DST_RBUF_5_FULL_MARK_OFFSET 0x648
|
||||
/* Ring Buffer Ctrl Regs --- End */
|
||||
|
||||
/* Error Status Regs --- Start */
|
||||
/* AUD_FMM_BF_ESR_ESRX_STATUS_REG_BASE */
|
||||
#define ESR0_STATUS_OFFSET 0x900
|
||||
#define ESR1_STATUS_OFFSET 0x918
|
||||
#define ESR2_STATUS_OFFSET 0x930
|
||||
#define ESR3_STATUS_OFFSET 0x948
|
||||
#define ESR4_STATUS_OFFSET 0x960
|
||||
|
||||
/* AUD_FMM_BF_ESR_ESRX_STATUS_CLEAR_REG_BASE */
|
||||
#define ESR0_STATUS_CLR_OFFSET 0x908
|
||||
#define ESR1_STATUS_CLR_OFFSET 0x920
|
||||
#define ESR2_STATUS_CLR_OFFSET 0x938
|
||||
#define ESR3_STATUS_CLR_OFFSET 0x950
|
||||
#define ESR4_STATUS_CLR_OFFSET 0x968
|
||||
|
||||
/* AUD_FMM_BF_ESR_ESRX_MASK_REG_BASE */
|
||||
#define ESR0_MASK_STATUS_OFFSET 0x90c
|
||||
#define ESR1_MASK_STATUS_OFFSET 0x924
|
||||
#define ESR2_MASK_STATUS_OFFSET 0x93c
|
||||
#define ESR3_MASK_STATUS_OFFSET 0x954
|
||||
#define ESR4_MASK_STATUS_OFFSET 0x96c
|
||||
|
||||
/* AUD_FMM_BF_ESR_ESRX_MASK_SET_REG_BASE */
|
||||
#define ESR0_MASK_SET_OFFSET 0x910
|
||||
#define ESR1_MASK_SET_OFFSET 0x928
|
||||
#define ESR2_MASK_SET_OFFSET 0x940
|
||||
#define ESR3_MASK_SET_OFFSET 0x958
|
||||
#define ESR4_MASK_SET_OFFSET 0x970
|
||||
|
||||
/* AUD_FMM_BF_ESR_ESRX_MASK_CLEAR_REG_BASE */
|
||||
#define ESR0_MASK_CLR_OFFSET 0x914
|
||||
#define ESR1_MASK_CLR_OFFSET 0x92c
|
||||
#define ESR2_MASK_CLR_OFFSET 0x944
|
||||
#define ESR3_MASK_CLR_OFFSET 0x95c
|
||||
#define ESR4_MASK_CLR_OFFSET 0x974
|
||||
/* Error Status Regs --- End */
|
||||
|
||||
#define R5F_ESR0_SHIFT 0 /* esr0 = fifo underflow */
|
||||
#define R5F_ESR1_SHIFT 1 /* esr1 = ringbuf underflow */
|
||||
#define R5F_ESR2_SHIFT 2 /* esr2 = ringbuf overflow */
|
||||
#define R5F_ESR3_SHIFT 3 /* esr3 = freemark */
|
||||
#define R5F_ESR4_SHIFT 4 /* esr4 = fullmark */
|
||||
|
||||
|
||||
/* Mask for R5F register. Set all relevant interrupt for playback handler */
|
||||
#define ANY_PLAYBACK_IRQ (BIT(R5F_ESR0_SHIFT) | \
|
||||
BIT(R5F_ESR1_SHIFT) | \
|
||||
BIT(R5F_ESR3_SHIFT))
|
||||
|
||||
/* Mask for R5F register. Set all relevant interrupt for capture handler */
|
||||
#define ANY_CAPTURE_IRQ (BIT(R5F_ESR2_SHIFT) | BIT(R5F_ESR4_SHIFT))
|
||||
|
||||
/*
|
||||
* PERIOD_BYTES_MIN is the number of bytes to at which the interrupt will tick.
|
||||
* This number should be a multiple of 256. Minimum value is 256
|
||||
*/
|
||||
#define PERIOD_BYTES_MIN 0x100
|
||||
|
||||
static const struct snd_pcm_hardware cygnus_pcm_hw = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
|
||||
/* A period is basically an interrupt */
|
||||
.period_bytes_min = PERIOD_BYTES_MIN,
|
||||
.period_bytes_max = 0x10000,
|
||||
|
||||
/* period_min/max gives range of approx interrupts per buffer */
|
||||
.periods_min = 2,
|
||||
.periods_max = 8,
|
||||
|
||||
/*
|
||||
* maximum buffer size in bytes = period_bytes_max * periods_max
|
||||
* We allocate this amount of data for each enabled channel
|
||||
*/
|
||||
.buffer_bytes_max = 4 * 0x8000,
|
||||
};
|
||||
|
||||
static u64 cygnus_dma_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct cygnus_aio_port *cygnus_dai_get_dma_data(
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
|
||||
return snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
|
||||
}
|
||||
|
||||
static void ringbuf_set_initial(void __iomem *audio_io,
|
||||
struct ringbuf_regs *p_rbuf,
|
||||
bool is_playback,
|
||||
u32 start,
|
||||
u32 periodsize,
|
||||
u32 bufsize)
|
||||
{
|
||||
u32 initial_rd;
|
||||
u32 initial_wr;
|
||||
u32 end;
|
||||
u32 fmark_val; /* free or full mark */
|
||||
|
||||
p_rbuf->period_bytes = periodsize;
|
||||
p_rbuf->buf_size = bufsize;
|
||||
|
||||
if (is_playback) {
|
||||
/* Set the pointers to indicate full (flip uppermost bit) */
|
||||
initial_rd = start;
|
||||
initial_wr = initial_rd ^ BIT(31);
|
||||
} else {
|
||||
/* Set the pointers to indicate empty */
|
||||
initial_wr = start;
|
||||
initial_rd = initial_wr;
|
||||
}
|
||||
|
||||
end = start + bufsize - 1;
|
||||
|
||||
/*
|
||||
* The interrupt will fire when free/full mark is *exceeded*
|
||||
* The fmark value must be multiple of PERIOD_BYTES_MIN so set fmark
|
||||
* to be PERIOD_BYTES_MIN less than the period size.
|
||||
*/
|
||||
fmark_val = periodsize - PERIOD_BYTES_MIN;
|
||||
|
||||
writel(start, audio_io + p_rbuf->baseaddr);
|
||||
writel(end, audio_io + p_rbuf->endaddr);
|
||||
writel(fmark_val, audio_io + p_rbuf->fmark);
|
||||
writel(initial_rd, audio_io + p_rbuf->rdaddr);
|
||||
writel(initial_wr, audio_io + p_rbuf->wraddr);
|
||||
}
|
||||
|
||||
static int configure_ringbuf_regs(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct cygnus_aio_port *aio;
|
||||
struct ringbuf_regs *p_rbuf;
|
||||
int status = 0;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
|
||||
/* Map the ssp portnum to a set of ring buffers. */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
p_rbuf = &aio->play_rb_regs;
|
||||
|
||||
switch (aio->portnum) {
|
||||
case 0:
|
||||
*p_rbuf = RINGBUF_REG_PLAYBACK(0);
|
||||
break;
|
||||
case 1:
|
||||
*p_rbuf = RINGBUF_REG_PLAYBACK(2);
|
||||
break;
|
||||
case 2:
|
||||
*p_rbuf = RINGBUF_REG_PLAYBACK(4);
|
||||
break;
|
||||
case 3: /* SPDIF */
|
||||
*p_rbuf = RINGBUF_REG_PLAYBACK(6);
|
||||
break;
|
||||
default:
|
||||
status = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
p_rbuf = &aio->capture_rb_regs;
|
||||
|
||||
switch (aio->portnum) {
|
||||
case 0:
|
||||
*p_rbuf = RINGBUF_REG_CAPTURE(0);
|
||||
break;
|
||||
case 1:
|
||||
*p_rbuf = RINGBUF_REG_CAPTURE(2);
|
||||
break;
|
||||
case 2:
|
||||
*p_rbuf = RINGBUF_REG_CAPTURE(4);
|
||||
break;
|
||||
default:
|
||||
status = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct ringbuf_regs *get_ringbuf(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct cygnus_aio_port *aio;
|
||||
struct ringbuf_regs *p_rbuf = NULL;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
p_rbuf = &aio->play_rb_regs;
|
||||
else
|
||||
p_rbuf = &aio->capture_rb_regs;
|
||||
|
||||
return p_rbuf;
|
||||
}
|
||||
|
||||
static void enable_intr(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct cygnus_aio_port *aio;
|
||||
u32 clear_mask;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
|
||||
/* The port number maps to the bit position to be cleared */
|
||||
clear_mask = BIT(aio->portnum);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
/* Clear interrupt status before enabling them */
|
||||
writel(clear_mask, aio->cygaud->audio + ESR0_STATUS_CLR_OFFSET);
|
||||
writel(clear_mask, aio->cygaud->audio + ESR1_STATUS_CLR_OFFSET);
|
||||
writel(clear_mask, aio->cygaud->audio + ESR3_STATUS_CLR_OFFSET);
|
||||
/* Unmask the interrupts of the given port*/
|
||||
writel(clear_mask, aio->cygaud->audio + ESR0_MASK_CLR_OFFSET);
|
||||
writel(clear_mask, aio->cygaud->audio + ESR1_MASK_CLR_OFFSET);
|
||||
writel(clear_mask, aio->cygaud->audio + ESR3_MASK_CLR_OFFSET);
|
||||
|
||||
writel(ANY_PLAYBACK_IRQ,
|
||||
aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
|
||||
} else {
|
||||
writel(clear_mask, aio->cygaud->audio + ESR2_STATUS_CLR_OFFSET);
|
||||
writel(clear_mask, aio->cygaud->audio + ESR4_STATUS_CLR_OFFSET);
|
||||
writel(clear_mask, aio->cygaud->audio + ESR2_MASK_CLR_OFFSET);
|
||||
writel(clear_mask, aio->cygaud->audio + ESR4_MASK_CLR_OFFSET);
|
||||
|
||||
writel(ANY_CAPTURE_IRQ,
|
||||
aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void disable_intr(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct cygnus_aio_port *aio;
|
||||
u32 set_mask;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s on port %d\n", __func__, aio->portnum);
|
||||
|
||||
/* The port number maps to the bit position to be set */
|
||||
set_mask = BIT(aio->portnum);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
/* Mask the interrupts of the given port*/
|
||||
writel(set_mask, aio->cygaud->audio + ESR0_MASK_SET_OFFSET);
|
||||
writel(set_mask, aio->cygaud->audio + ESR1_MASK_SET_OFFSET);
|
||||
writel(set_mask, aio->cygaud->audio + ESR3_MASK_SET_OFFSET);
|
||||
} else {
|
||||
writel(set_mask, aio->cygaud->audio + ESR2_MASK_SET_OFFSET);
|
||||
writel(set_mask, aio->cygaud->audio + ESR4_MASK_SET_OFFSET);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int cygnus_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
enable_intr(substream);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
disable_intr(substream);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cygnus_pcm_period_elapsed(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct cygnus_aio_port *aio;
|
||||
struct ringbuf_regs *p_rbuf = NULL;
|
||||
u32 regval;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
|
||||
p_rbuf = get_ringbuf(substream);
|
||||
|
||||
/*
|
||||
* If free/full mark interrupt occurs, provide timestamp
|
||||
* to ALSA and update appropriate idx by period_bytes
|
||||
*/
|
||||
snd_pcm_period_elapsed(substream);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
/* Set the ring buffer to full */
|
||||
regval = readl(aio->cygaud->audio + p_rbuf->rdaddr);
|
||||
regval = regval ^ BIT(31);
|
||||
writel(regval, aio->cygaud->audio + p_rbuf->wraddr);
|
||||
} else {
|
||||
/* Set the ring buffer to empty */
|
||||
regval = readl(aio->cygaud->audio + p_rbuf->wraddr);
|
||||
writel(regval, aio->cygaud->audio + p_rbuf->rdaddr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ESR0/1/3 status Description
|
||||
* 0x1 I2S0_out port caused interrupt
|
||||
* 0x2 I2S1_out port caused interrupt
|
||||
* 0x4 I2S2_out port caused interrupt
|
||||
* 0x8 SPDIF_out port caused interrupt
|
||||
*/
|
||||
static void handle_playback_irq(struct cygnus_audio *cygaud)
|
||||
{
|
||||
void __iomem *audio_io;
|
||||
u32 port;
|
||||
u32 esr_status0, esr_status1, esr_status3;
|
||||
|
||||
audio_io = cygaud->audio;
|
||||
|
||||
/*
|
||||
* ESR status gets updates with/without interrupts enabled.
|
||||
* So, check the ESR mask, which provides interrupt enable/
|
||||
* disable status and use it to determine which ESR status
|
||||
* should be serviced.
|
||||
*/
|
||||
esr_status0 = readl(audio_io + ESR0_STATUS_OFFSET);
|
||||
esr_status0 &= ~readl(audio_io + ESR0_MASK_STATUS_OFFSET);
|
||||
esr_status1 = readl(audio_io + ESR1_STATUS_OFFSET);
|
||||
esr_status1 &= ~readl(audio_io + ESR1_MASK_STATUS_OFFSET);
|
||||
esr_status3 = readl(audio_io + ESR3_STATUS_OFFSET);
|
||||
esr_status3 &= ~readl(audio_io + ESR3_MASK_STATUS_OFFSET);
|
||||
|
||||
for (port = 0; port < CYGNUS_MAX_PLAYBACK_PORTS; port++) {
|
||||
u32 esrmask = BIT(port);
|
||||
|
||||
/*
|
||||
* Ringbuffer or FIFO underflow
|
||||
* If we get this interrupt then, it is also true that we have
|
||||
* not yet responded to the freemark interrupt.
|
||||
* Log a debug message. The freemark handler below will
|
||||
* handle getting everything going again.
|
||||
*/
|
||||
if ((esrmask & esr_status1) || (esrmask & esr_status0)) {
|
||||
dev_dbg(cygaud->dev,
|
||||
"Underrun: esr0=0x%x, esr1=0x%x esr3=0x%x\n",
|
||||
esr_status0, esr_status1, esr_status3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Freemark is hit. This is the normal interrupt.
|
||||
* In typical operation the read and write regs will be equal
|
||||
*/
|
||||
if (esrmask & esr_status3) {
|
||||
struct snd_pcm_substream *playstr;
|
||||
|
||||
playstr = cygaud->portinfo[port].play_stream;
|
||||
cygnus_pcm_period_elapsed(playstr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear ESR interrupt */
|
||||
writel(esr_status0, audio_io + ESR0_STATUS_CLR_OFFSET);
|
||||
writel(esr_status1, audio_io + ESR1_STATUS_CLR_OFFSET);
|
||||
writel(esr_status3, audio_io + ESR3_STATUS_CLR_OFFSET);
|
||||
/* Rearm freemark logic by writing 1 to the correct bit */
|
||||
writel(esr_status3, audio_io + BF_REARM_FREE_MARK_OFFSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* ESR2/4 status Description
|
||||
* 0x1 I2S0_in port caused interrupt
|
||||
* 0x2 I2S1_in port caused interrupt
|
||||
* 0x4 I2S2_in port caused interrupt
|
||||
*/
|
||||
static void handle_capture_irq(struct cygnus_audio *cygaud)
|
||||
{
|
||||
void __iomem *audio_io;
|
||||
u32 port;
|
||||
u32 esr_status2, esr_status4;
|
||||
|
||||
audio_io = cygaud->audio;
|
||||
|
||||
/*
|
||||
* ESR status gets updates with/without interrupts enabled.
|
||||
* So, check the ESR mask, which provides interrupt enable/
|
||||
* disable status and use it to determine which ESR status
|
||||
* should be serviced.
|
||||
*/
|
||||
esr_status2 = readl(audio_io + ESR2_STATUS_OFFSET);
|
||||
esr_status2 &= ~readl(audio_io + ESR2_MASK_STATUS_OFFSET);
|
||||
esr_status4 = readl(audio_io + ESR4_STATUS_OFFSET);
|
||||
esr_status4 &= ~readl(audio_io + ESR4_MASK_STATUS_OFFSET);
|
||||
|
||||
for (port = 0; port < CYGNUS_MAX_CAPTURE_PORTS; port++) {
|
||||
u32 esrmask = BIT(port);
|
||||
|
||||
/*
|
||||
* Ringbuffer or FIFO overflow
|
||||
* If we get this interrupt then, it is also true that we have
|
||||
* not yet responded to the fullmark interrupt.
|
||||
* Log a debug message. The fullmark handler below will
|
||||
* handle getting everything going again.
|
||||
*/
|
||||
if (esrmask & esr_status2)
|
||||
dev_dbg(cygaud->dev,
|
||||
"Overflow: esr2=0x%x\n", esr_status2);
|
||||
|
||||
if (esrmask & esr_status4) {
|
||||
struct snd_pcm_substream *capstr;
|
||||
|
||||
capstr = cygaud->portinfo[port].capture_stream;
|
||||
cygnus_pcm_period_elapsed(capstr);
|
||||
}
|
||||
}
|
||||
|
||||
writel(esr_status2, audio_io + ESR2_STATUS_CLR_OFFSET);
|
||||
writel(esr_status4, audio_io + ESR4_STATUS_CLR_OFFSET);
|
||||
/* Rearm fullmark logic by writing 1 to the correct bit */
|
||||
writel(esr_status4, audio_io + BF_REARM_FULL_MARK_OFFSET);
|
||||
}
|
||||
|
||||
static irqreturn_t cygnus_dma_irq(int irq, void *data)
|
||||
{
|
||||
u32 r5_status;
|
||||
struct cygnus_audio *cygaud = data;
|
||||
|
||||
/*
|
||||
* R5 status bits Description
|
||||
* 0 ESR0 (playback FIFO interrupt)
|
||||
* 1 ESR1 (playback rbuf interrupt)
|
||||
* 2 ESR2 (capture rbuf interrupt)
|
||||
* 3 ESR3 (Freemark play. interrupt)
|
||||
* 4 ESR4 (Fullmark capt. interrupt)
|
||||
*/
|
||||
r5_status = readl(cygaud->audio + INTH_R5F_STATUS_OFFSET);
|
||||
|
||||
if (!(r5_status & (ANY_PLAYBACK_IRQ | ANY_CAPTURE_IRQ)))
|
||||
return IRQ_NONE;
|
||||
|
||||
/* If playback interrupt happened */
|
||||
if (ANY_PLAYBACK_IRQ & r5_status) {
|
||||
handle_playback_irq(cygaud);
|
||||
writel(ANY_PLAYBACK_IRQ & r5_status,
|
||||
cygaud->audio + INTH_R5F_CLEAR_OFFSET);
|
||||
}
|
||||
|
||||
/* If capture interrupt happened */
|
||||
if (ANY_CAPTURE_IRQ & r5_status) {
|
||||
handle_capture_irq(cygaud);
|
||||
writel(ANY_CAPTURE_IRQ & r5_status,
|
||||
cygaud->audio + INTH_R5F_CLEAR_OFFSET);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct cygnus_aio_port *aio;
|
||||
int ret;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
if (!aio)
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &cygnus_pcm_hw);
|
||||
|
||||
ret = snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, PERIOD_BYTES_MIN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, PERIOD_BYTES_MIN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* Keep track of which substream belongs to which port.
|
||||
* This info is needed by snd_pcm_period_elapsed() in irq_handler
|
||||
*/
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
aio->play_stream = substream;
|
||||
else
|
||||
aio->capture_stream = substream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct cygnus_aio_port *aio;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
aio->play_stream = NULL;
|
||||
else
|
||||
aio->capture_stream = NULL;
|
||||
|
||||
if (!aio->play_stream && !aio->capture_stream)
|
||||
dev_dbg(rtd->cpu_dai->dev, "freed port %d\n", aio->portnum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct cygnus_aio_port *aio;
|
||||
int ret = 0;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
|
||||
|
||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
runtime->dma_bytes = params_buffer_bytes(params);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct cygnus_aio_port *aio;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
|
||||
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct cygnus_aio_port *aio;
|
||||
unsigned long bufsize, periodsize;
|
||||
int ret = 0;
|
||||
bool is_play;
|
||||
u32 start;
|
||||
struct ringbuf_regs *p_rbuf = NULL;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
|
||||
|
||||
bufsize = snd_pcm_lib_buffer_bytes(substream);
|
||||
periodsize = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s (buf_size %lu) (period_size %lu)\n",
|
||||
__func__, bufsize, periodsize);
|
||||
|
||||
configure_ringbuf_regs(substream);
|
||||
|
||||
p_rbuf = get_ringbuf(substream);
|
||||
|
||||
start = runtime->dma_addr;
|
||||
|
||||
is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0;
|
||||
|
||||
ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start,
|
||||
periodsize, bufsize);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct cygnus_aio_port *aio;
|
||||
unsigned int res = 0, cur = 0, base = 0;
|
||||
struct ringbuf_regs *p_rbuf = NULL;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
|
||||
/*
|
||||
* Get the offset of the current read (for playack) or write
|
||||
* index (for capture). Report this value back to the asoc framework.
|
||||
*/
|
||||
p_rbuf = get_ringbuf(substream);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
cur = readl(aio->cygaud->audio + p_rbuf->rdaddr);
|
||||
else
|
||||
cur = readl(aio->cygaud->audio + p_rbuf->wraddr);
|
||||
|
||||
base = readl(aio->cygaud->audio + p_rbuf->baseaddr);
|
||||
|
||||
/*
|
||||
* Mask off the MSB of the rdaddr,wraddr and baseaddr
|
||||
* since MSB is not part of the address
|
||||
*/
|
||||
res = (cur & 0x7fffffff) - (base & 0x7fffffff);
|
||||
|
||||
return bytes_to_frames(substream->runtime, res);
|
||||
}
|
||||
|
||||
static int cygnus_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
|
||||
{
|
||||
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
size_t size;
|
||||
|
||||
size = cygnus_pcm_hw.buffer_bytes_max;
|
||||
|
||||
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);
|
||||
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s: size 0x%zx @ %pK\n",
|
||||
__func__, size, buf->area);
|
||||
|
||||
if (!buf->area) {
|
||||
dev_err(rtd->cpu_dai->dev, "%s: dma_alloc failed\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
buf->bytes = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct snd_pcm_ops cygnus_pcm_ops = {
|
||||
.open = cygnus_pcm_open,
|
||||
.close = cygnus_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = cygnus_pcm_hw_params,
|
||||
.hw_free = cygnus_pcm_hw_free,
|
||||
.prepare = cygnus_pcm_prepare,
|
||||
.trigger = cygnus_pcm_trigger,
|
||||
.pointer = cygnus_pcm_pointer,
|
||||
};
|
||||
|
||||
static void cygnus_dma_free_dma_buffers(struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
|
||||
substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
||||
if (substream) {
|
||||
buf = &substream->dma_buffer;
|
||||
if (buf->area) {
|
||||
dma_free_coherent(pcm->card->dev, buf->bytes,
|
||||
buf->area, buf->addr);
|
||||
buf->area = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
|
||||
if (substream) {
|
||||
buf = &substream->dma_buffer;
|
||||
if (buf->area) {
|
||||
dma_free_coherent(pcm->card->dev, buf->bytes,
|
||||
buf->area, buf->addr);
|
||||
buf->area = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
int ret;
|
||||
|
||||
if (!card->dev->dma_mask)
|
||||
card->dev->dma_mask = &cygnus_dma_dmamask;
|
||||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
|
||||
ret = cygnus_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
||||
ret = cygnus_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret) {
|
||||
cygnus_dma_free_dma_buffers(pcm);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_platform_driver cygnus_soc_platform = {
|
||||
.ops = &cygnus_pcm_ops,
|
||||
.pcm_new = cygnus_dma_new,
|
||||
.pcm_free = cygnus_dma_free_dma_buffers,
|
||||
};
|
||||
|
||||
int cygnus_soc_platform_register(struct device *dev,
|
||||
struct cygnus_audio *cygaud)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
dev_dbg(dev, "%s Enter\n", __func__);
|
||||
|
||||
rc = devm_request_irq(dev, cygaud->irq_num, cygnus_dma_irq,
|
||||
IRQF_SHARED, "cygnus-audio", cygaud);
|
||||
if (rc) {
|
||||
dev_err(dev, "%s request_irq error %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = snd_soc_register_platform(dev, &cygnus_soc_platform);
|
||||
if (rc) {
|
||||
dev_err(dev, "%s failed\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cygnus_soc_platform_unregister(struct device *dev)
|
||||
{
|
||||
snd_soc_unregister_platform(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Broadcom");
|
||||
MODULE_DESCRIPTION("Cygnus ASoC PCM module");
|
1529
sound/soc/bcm/cygnus-ssp.c
Normal file
1529
sound/soc/bcm/cygnus-ssp.c
Normal file
File diff suppressed because it is too large
Load Diff
139
sound/soc/bcm/cygnus-ssp.h
Normal file
139
sound/soc/bcm/cygnus-ssp.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef __CYGNUS_SSP_H__
|
||||
#define __CYGNUS_SSP_H__
|
||||
|
||||
#define CYGNUS_TDM_DAI_MAX_SLOTS 16
|
||||
|
||||
#define CYGNUS_MAX_PLAYBACK_PORTS 4
|
||||
#define CYGNUS_MAX_CAPTURE_PORTS 3
|
||||
#define CYGNUS_MAX_I2S_PORTS 3
|
||||
#define CYGNUS_MAX_PORTS CYGNUS_MAX_PLAYBACK_PORTS
|
||||
#define CYGNUS_AUIDO_MAX_NUM_CLKS 3
|
||||
|
||||
#define CYGNUS_SSP_FRAMEBITS_DIV 1
|
||||
|
||||
#define CYGNUS_SSPMODE_I2S 0
|
||||
#define CYGNUS_SSPMODE_TDM 1
|
||||
#define CYGNUS_SSPMODE_UNKNOWN -1
|
||||
|
||||
#define CYGNUS_SSP_CLKSRC_PLL 0
|
||||
|
||||
/* Max string length of our dt property names */
|
||||
#define PROP_LEN_MAX 40
|
||||
|
||||
struct ringbuf_regs {
|
||||
unsigned rdaddr;
|
||||
unsigned wraddr;
|
||||
unsigned baseaddr;
|
||||
unsigned endaddr;
|
||||
unsigned fmark; /* freemark for play, fullmark for caputure */
|
||||
unsigned period_bytes;
|
||||
unsigned buf_size;
|
||||
};
|
||||
|
||||
#define RINGBUF_REG_PLAYBACK(num) ((struct ringbuf_regs) { \
|
||||
.rdaddr = SRC_RBUF_ ##num## _RDADDR_OFFSET, \
|
||||
.wraddr = SRC_RBUF_ ##num## _WRADDR_OFFSET, \
|
||||
.baseaddr = SRC_RBUF_ ##num## _BASEADDR_OFFSET, \
|
||||
.endaddr = SRC_RBUF_ ##num## _ENDADDR_OFFSET, \
|
||||
.fmark = SRC_RBUF_ ##num## _FREE_MARK_OFFSET, \
|
||||
.period_bytes = 0, \
|
||||
.buf_size = 0, \
|
||||
})
|
||||
|
||||
#define RINGBUF_REG_CAPTURE(num) ((struct ringbuf_regs) { \
|
||||
.rdaddr = DST_RBUF_ ##num## _RDADDR_OFFSET, \
|
||||
.wraddr = DST_RBUF_ ##num## _WRADDR_OFFSET, \
|
||||
.baseaddr = DST_RBUF_ ##num## _BASEADDR_OFFSET, \
|
||||
.endaddr = DST_RBUF_ ##num## _ENDADDR_OFFSET, \
|
||||
.fmark = DST_RBUF_ ##num## _FULL_MARK_OFFSET, \
|
||||
.period_bytes = 0, \
|
||||
.buf_size = 0, \
|
||||
})
|
||||
|
||||
enum cygnus_audio_port_type {
|
||||
PORT_TDM,
|
||||
PORT_SPDIF,
|
||||
};
|
||||
|
||||
struct cygnus_ssp_regs {
|
||||
u32 i2s_stream_cfg;
|
||||
u32 i2s_cfg;
|
||||
u32 i2s_cap_stream_cfg;
|
||||
u32 i2s_cap_cfg;
|
||||
u32 i2s_mclk_cfg;
|
||||
|
||||
u32 bf_destch_ctrl;
|
||||
u32 bf_destch_cfg;
|
||||
u32 bf_sourcech_ctrl;
|
||||
u32 bf_sourcech_cfg;
|
||||
u32 bf_sourcech_grp;
|
||||
};
|
||||
|
||||
struct cygnus_track_clk {
|
||||
bool cap_en;
|
||||
bool play_en;
|
||||
bool cap_clk_en;
|
||||
bool play_clk_en;
|
||||
};
|
||||
|
||||
struct cygnus_aio_port {
|
||||
int portnum;
|
||||
int mode;
|
||||
bool is_slave;
|
||||
int streams_on; /* will be 0 if both capture and play are off */
|
||||
int fsync_width;
|
||||
int port_type;
|
||||
|
||||
u32 mclk;
|
||||
u32 lrclk;
|
||||
u32 bit_per_frame;
|
||||
u32 pll_clk_num;
|
||||
|
||||
struct cygnus_audio *cygaud;
|
||||
struct cygnus_ssp_regs regs;
|
||||
|
||||
struct ringbuf_regs play_rb_regs;
|
||||
struct ringbuf_regs capture_rb_regs;
|
||||
|
||||
struct snd_pcm_substream *play_stream;
|
||||
struct snd_pcm_substream *capture_stream;
|
||||
|
||||
struct cygnus_track_clk clk_trace;
|
||||
};
|
||||
|
||||
|
||||
struct cygnus_audio {
|
||||
struct cygnus_aio_port portinfo[CYGNUS_MAX_PORTS];
|
||||
|
||||
int irq_num;
|
||||
void __iomem *audio;
|
||||
struct device *dev;
|
||||
void __iomem *i2s_in;
|
||||
|
||||
struct clk *audio_clk[CYGNUS_AUIDO_MAX_NUM_CLKS];
|
||||
int active_ports;
|
||||
unsigned long vco_rate;
|
||||
};
|
||||
|
||||
extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
|
||||
extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd);
|
||||
extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
|
||||
int len);
|
||||
extern int cygnus_soc_platform_register(struct device *dev,
|
||||
struct cygnus_audio *cygaud);
|
||||
extern int cygnus_soc_platform_unregister(struct device *dev);
|
||||
extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
|
||||
int len);
|
||||
#endif
|
@ -32,6 +32,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_ADAU1977_SPI if SPI_MASTER
|
||||
select SND_SOC_ADAU1977_I2C if I2C
|
||||
select SND_SOC_ADAU1701 if I2C
|
||||
select SND_SOC_ADAU7002
|
||||
select SND_SOC_ADS117X
|
||||
select SND_SOC_AK4104 if SPI_MASTER
|
||||
select SND_SOC_AK4535 if I2C
|
||||
@ -46,6 +47,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_BT_SCO
|
||||
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
|
||||
select SND_SOC_CS35L32 if I2C
|
||||
select SND_SOC_CS35L33 if I2C
|
||||
select SND_SOC_CS42L51_I2C if I2C
|
||||
select SND_SOC_CS42L52 if I2C && INPUT
|
||||
select SND_SOC_CS42L56 if I2C && INPUT
|
||||
@ -57,6 +59,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_CS42XX8_I2C if I2C
|
||||
select SND_SOC_CS4349 if I2C
|
||||
select SND_SOC_CS47L24 if MFD_CS47L24
|
||||
select SND_SOC_CS53L30 if I2C
|
||||
select SND_SOC_CX20442 if TTY
|
||||
select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_DA7213 if I2C
|
||||
@ -84,6 +87,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_MAX98925 if I2C
|
||||
select SND_SOC_MAX98926 if I2C
|
||||
select SND_SOC_MAX9850 if I2C
|
||||
select SND_SOC_MAX9860 if I2C
|
||||
select SND_SOC_MAX9768 if I2C
|
||||
select SND_SOC_MAX9877 if I2C
|
||||
select SND_SOC_MC13783 if MFD_MC13XXX
|
||||
@ -269,8 +273,12 @@ config SND_SOC_AD1980
|
||||
config SND_SOC_AD73311
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU_UTILS
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1373
|
||||
tristate
|
||||
select SND_SOC_ADAU_UTILS
|
||||
|
||||
config SND_SOC_ADAU1701
|
||||
tristate "Analog Devices ADAU1701 CODEC"
|
||||
@ -280,6 +288,7 @@ config SND_SOC_ADAU1701
|
||||
config SND_SOC_ADAU17X1
|
||||
tristate
|
||||
select SND_SOC_SIGMADSP_REGMAP
|
||||
select SND_SOC_ADAU_UTILS
|
||||
|
||||
config SND_SOC_ADAU1761
|
||||
tristate
|
||||
@ -322,6 +331,9 @@ config SND_SOC_ADAU1977_I2C
|
||||
select SND_SOC_ADAU1977
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_ADAU7002
|
||||
tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter"
|
||||
|
||||
config SND_SOC_ADAV80X
|
||||
tristate
|
||||
|
||||
@ -371,7 +383,7 @@ config SND_SOC_ALC5632
|
||||
tristate
|
||||
|
||||
config SND_SOC_BT_SCO
|
||||
tristate
|
||||
tristate "Dummy BT SCO codec driver"
|
||||
|
||||
config SND_SOC_CQ0093VC
|
||||
tristate
|
||||
@ -380,6 +392,10 @@ config SND_SOC_CS35L32
|
||||
tristate "Cirrus Logic CS35L32 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_CS35L33
|
||||
tristate "Cirrus Logic CS35L33 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_CS42L51
|
||||
tristate
|
||||
|
||||
@ -450,6 +466,11 @@ config SND_SOC_CS4349
|
||||
config SND_SOC_CS47L24
|
||||
tristate
|
||||
|
||||
# Cirrus Logic Quad-Channel ADC
|
||||
config SND_SOC_CS53L30
|
||||
tristate "Cirrus Logic CS53L30 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_CX20442
|
||||
tristate
|
||||
depends on TTY
|
||||
@ -536,6 +557,10 @@ config SND_SOC_MAX98357A
|
||||
config SND_SOC_MAX98371
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX98504
|
||||
tristate "Maxim MAX98504 speaker amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_MAX9867
|
||||
tristate
|
||||
|
||||
@ -548,6 +573,11 @@ config SND_SOC_MAX98926
|
||||
config SND_SOC_MAX9850
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX9860
|
||||
tristate "Maxim MAX9860 Mono Audio Voice Codec"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_PCM1681
|
||||
tristate "Texas Instruments PCM1681 CODEC"
|
||||
depends on I2C
|
||||
@ -644,6 +674,9 @@ config SND_SOC_RT298
|
||||
config SND_SOC_RT5514
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5514_SPI
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5616
|
||||
tristate "Realtek RT5616 CODEC"
|
||||
depends on I2C
|
||||
@ -969,7 +1002,8 @@ config SND_SOC_WM8983
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8985
|
||||
tristate
|
||||
tristate "Wolfson Microelectronics WM8985 and WM8758 codec driver"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8988
|
||||
tristate
|
||||
|
@ -7,6 +7,7 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o
|
||||
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
|
||||
snd-soc-ad1980-objs := ad1980.o
|
||||
snd-soc-ad73311-objs := ad73311.o
|
||||
snd-soc-adau-utils-objs := adau-utils.o
|
||||
snd-soc-adau1373-objs := adau1373.o
|
||||
snd-soc-adau1701-objs := adau1701.o
|
||||
snd-soc-adau17x1-objs := adau17x1.o
|
||||
@ -19,6 +20,7 @@ snd-soc-adau1781-spi-objs := adau1781-spi.o
|
||||
snd-soc-adau1977-objs := adau1977.o
|
||||
snd-soc-adau1977-spi-objs := adau1977-spi.o
|
||||
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
|
||||
snd-soc-adau7002-objs := adau7002.o
|
||||
snd-soc-adav80x-objs := adav80x.o
|
||||
snd-soc-adav801-objs := adav801.o
|
||||
snd-soc-adav803-objs := adav803.o
|
||||
@ -35,6 +37,7 @@ snd-soc-arizona-objs := arizona.o
|
||||
snd-soc-bt-sco-objs := bt-sco.o
|
||||
snd-soc-cq93vc-objs := cq93vc.o
|
||||
snd-soc-cs35l32-objs := cs35l32.o
|
||||
snd-soc-cs35l33-objs := cs35l33.o
|
||||
snd-soc-cs42l51-objs := cs42l51.o
|
||||
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
|
||||
snd-soc-cs42l52-objs := cs42l52.o
|
||||
@ -49,6 +52,7 @@ snd-soc-cs42xx8-objs := cs42xx8.o
|
||||
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
|
||||
snd-soc-cs4349-objs := cs4349.o
|
||||
snd-soc-cs47l24-objs := cs47l24.o
|
||||
snd-soc-cs53l30-objs := cs53l30.o
|
||||
snd-soc-cx20442-objs := cx20442.o
|
||||
snd-soc-da7210-objs := da7210.o
|
||||
snd-soc-da7213-objs := da7213.o
|
||||
@ -79,6 +83,7 @@ snd-soc-max9867-objs := max9867.o
|
||||
snd-soc-max98925-objs := max98925.o
|
||||
snd-soc-max98926-objs := max98926.o
|
||||
snd-soc-max9850-objs := max9850.o
|
||||
snd-soc-max9860-objs := max9860.o
|
||||
snd-soc-mc13783-objs := mc13783.o
|
||||
snd-soc-ml26124-objs := ml26124.o
|
||||
snd-soc-nau8825-objs := nau8825.o
|
||||
@ -100,6 +105,7 @@ snd-soc-rl6347a-objs := rl6347a.o
|
||||
snd-soc-rt286-objs := rt286.o
|
||||
snd-soc-rt298-objs := rt298.o
|
||||
snd-soc-rt5514-objs := rt5514.o
|
||||
snd-soc-rt5514-spi-objs := rt5514-spi.o
|
||||
snd-soc-rt5616-objs := rt5616.o
|
||||
snd-soc-rt5631-objs := rt5631.o
|
||||
snd-soc-rt5640-objs := rt5640.o
|
||||
@ -208,6 +214,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
|
||||
|
||||
# Amp
|
||||
snd-soc-max9877-objs := max9877.o
|
||||
snd-soc-max98504-objs := max98504.o
|
||||
snd-soc-tpa6130a2-objs := tpa6130a2.o
|
||||
snd-soc-tas2552-objs := tas2552.o
|
||||
|
||||
@ -220,6 +227,7 @@ obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
||||
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU_UTILS) += snd-soc-adau-utils.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o
|
||||
@ -232,6 +240,7 @@ obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
|
||||
@ -250,6 +259,7 @@ obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
|
||||
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
|
||||
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
|
||||
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
|
||||
obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
|
||||
@ -264,6 +274,7 @@ obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o
|
||||
obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o
|
||||
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
|
||||
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
|
||||
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
|
||||
@ -293,6 +304,7 @@ obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
|
||||
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
|
||||
obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o
|
||||
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
|
||||
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
|
||||
@ -314,6 +326,7 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
|
||||
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
|
||||
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
|
||||
obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o
|
||||
obj-$(CONFIG_SND_SOC_RT5514_SPI) += snd-soc-rt5514-spi.o
|
||||
obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o
|
||||
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
|
||||
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
|
||||
@ -419,4 +432,5 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
|
||||
|
||||
# Amp
|
||||
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
|
||||
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
|
||||
|
61
sound/soc/codecs/adau-utils.c
Normal file
61
sound/soc/codecs/adau-utils.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Shared helper functions for devices from the ADAU family
|
||||
*
|
||||
* Copyright 2011-2016 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "adau-utils.h"
|
||||
|
||||
int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
|
||||
uint8_t regs[5])
|
||||
{
|
||||
unsigned int r, n, m, i, j;
|
||||
unsigned int div;
|
||||
|
||||
if (!freq_out) {
|
||||
r = 0;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
} else {
|
||||
if (freq_out % freq_in != 0) {
|
||||
div = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= div;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
div--;
|
||||
} else {
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
}
|
||||
if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regs[0] = m >> 8;
|
||||
regs[1] = m & 0xff;
|
||||
regs[2] = n >> 8;
|
||||
regs[3] = n & 0xff;
|
||||
regs[4] = (r << 3) | (div << 1);
|
||||
if (m != 0)
|
||||
regs[4] |= 1; /* Fractional mode */
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau_calc_pll_cfg);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL v2");
|
7
sound/soc/codecs/adau-utils.h
Normal file
7
sound/soc/codecs/adau-utils.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef SOUND_SOC_CODECS_ADAU_PLL_H
|
||||
#define SOUND_SOC_CODECS_ADAU_PLL_H
|
||||
|
||||
int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
|
||||
uint8_t regs[5]);
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include <sound/adau1373.h>
|
||||
|
||||
#include "adau1373.h"
|
||||
#include "adau-utils.h"
|
||||
|
||||
struct adau1373_dai {
|
||||
unsigned int clk_src;
|
||||
@ -1254,7 +1255,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
||||
{
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int dpll_div = 0;
|
||||
unsigned int x, r, n, m, i, j, mode;
|
||||
uint8_t pll_regs[5];
|
||||
int ret;
|
||||
|
||||
switch (pll_id) {
|
||||
case ADAU1373_PLL1:
|
||||
@ -1295,27 +1297,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
||||
dpll_div++;
|
||||
}
|
||||
|
||||
if (freq_out % freq_in != 0) {
|
||||
/* fout = fin * (r + (n/m)) / x */
|
||||
x = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= x;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
x--;
|
||||
mode = 1;
|
||||
} else {
|
||||
/* fout = fin / r */
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
x = 0;
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
if (r < 2 || r > 8 || x > 3 || m > 0xffff || n > 0xffff)
|
||||
ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (dpll_div) {
|
||||
@ -1330,12 +1313,11 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
||||
|
||||
regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
|
||||
(source << 4) | dpll_div);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),
|
||||
(r << 3) | (x << 1) | mode);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]);
|
||||
|
||||
/* Set sysclk to pll_rate / 4 */
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
|
||||
|
@ -31,7 +31,7 @@ static int adau1761_i2c_probe(struct i2c_client *client,
|
||||
|
||||
static int adau1761_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
adau17x1_remove(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ static int adau1761_spi_probe(struct spi_device *spi)
|
||||
|
||||
static int adau1761_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
adau17x1_remove(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ static int adau1781_i2c_probe(struct i2c_client *client,
|
||||
|
||||
static int adau1781_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
adau17x1_remove(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ static int adau1781_spi_probe(struct spi_device *spi)
|
||||
|
||||
static int adau1781_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
adau17x1_remove(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
@ -23,6 +24,7 @@
|
||||
|
||||
#include "sigmadsp.h"
|
||||
#include "adau17x1.h"
|
||||
#include "adau-utils.h"
|
||||
|
||||
static const char * const adau17x1_capture_mixer_boost_text[] = {
|
||||
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
|
||||
@ -302,6 +304,116 @@ bool adau17x1_has_dsp(struct adau *adau)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
|
||||
|
||||
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
if (freq_in < 8000000 || freq_in > 27000000)
|
||||
return -EINVAL;
|
||||
|
||||
ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adau->pll_freq = freq_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
bool is_pll;
|
||||
bool was_pll;
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
is_pll = false;
|
||||
break;
|
||||
case ADAU17X1_CLK_SRC_PLL_AUTO:
|
||||
if (!adau->mclk)
|
||||
return -EINVAL;
|
||||
/* Fall-through */
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
is_pll = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (adau->clk_src) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
was_pll = false;
|
||||
break;
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
case ADAU17X1_CLK_SRC_PLL_AUTO:
|
||||
was_pll = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->sysclk = freq;
|
||||
|
||||
if (is_pll != was_pll) {
|
||||
if (is_pll) {
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
} else {
|
||||
snd_soc_dapm_del_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
}
|
||||
}
|
||||
|
||||
adau->clk_src = clk_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_auto_pll(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct adau *adau = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned int pll_rate;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return adau17x1_set_dai_pll(dai, ADAU17X1_PLL, ADAU17X1_PLL_SRC_MCLK,
|
||||
clk_get_rate(adau->mclk), pll_rate);
|
||||
}
|
||||
|
||||
static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -311,10 +423,19 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
||||
unsigned int freq;
|
||||
int ret;
|
||||
|
||||
if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
|
||||
switch (adau->clk_src) {
|
||||
case ADAU17X1_CLK_SRC_PLL_AUTO:
|
||||
ret = adau17x1_auto_pll(dai, params);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Fall-through */
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
freq = adau->pll_freq;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
freq = adau->sysclk;
|
||||
break;
|
||||
}
|
||||
|
||||
if (freq % params_rate(params) != 0)
|
||||
return -EINVAL;
|
||||
@ -386,93 +507,6 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
||||
ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int r, n, m, i, j;
|
||||
unsigned int div;
|
||||
int ret;
|
||||
|
||||
if (freq_in < 8000000 || freq_in > 27000000)
|
||||
return -EINVAL;
|
||||
|
||||
if (!freq_out) {
|
||||
r = 0;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
} else {
|
||||
if (freq_out % freq_in != 0) {
|
||||
div = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= div;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
div--;
|
||||
} else {
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
}
|
||||
if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->pll_regs[0] = m >> 8;
|
||||
adau->pll_regs[1] = m & 0xff;
|
||||
adau->pll_regs[2] = n >> 8;
|
||||
adau->pll_regs[3] = n & 0xff;
|
||||
adau->pll_regs[4] = (r << 3) | (div << 1);
|
||||
if (m != 0)
|
||||
adau->pll_regs[4] |= 1; /* Fractional mode */
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adau->pll_freq = freq_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->sysclk = freq;
|
||||
|
||||
if (adau->clk_src != clk_id) {
|
||||
if (clk_id == ADAU17X1_CLK_SRC_PLL) {
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
} else {
|
||||
snd_soc_dapm_del_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
}
|
||||
}
|
||||
|
||||
adau->clk_src = clk_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
@ -857,6 +891,10 @@ int adau17x1_add_routes(struct snd_soc_codec *codec)
|
||||
ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
|
||||
}
|
||||
|
||||
if (adau->clk_src != ADAU17X1_CLK_SRC_MCLK)
|
||||
snd_soc_dapm_add_routes(dapm, &adau17x1_dapm_pll_route, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
|
||||
@ -879,6 +917,7 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *firmware_name)
|
||||
{
|
||||
struct adau *adau;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
@ -887,6 +926,30 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
if (!adau)
|
||||
return -ENOMEM;
|
||||
|
||||
adau->mclk = devm_clk_get(dev, "mclk");
|
||||
if (IS_ERR(adau->mclk)) {
|
||||
if (PTR_ERR(adau->mclk) != -ENOENT)
|
||||
return PTR_ERR(adau->mclk);
|
||||
/* Clock is optional (for the driver) */
|
||||
adau->mclk = NULL;
|
||||
} else if (adau->mclk) {
|
||||
adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO;
|
||||
|
||||
/*
|
||||
* Any valid PLL output rate will work at this point, use one
|
||||
* that is likely to be chosen later as well. The register will
|
||||
* be written when the PLL is powered up for the first time.
|
||||
*/
|
||||
ret = adau_calc_pll_cfg(clk_get_rate(adau->mclk), 48000 * 1024,
|
||||
adau->pll_regs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(adau->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
adau->regmap = regmap;
|
||||
adau->switch_mode = switch_mode;
|
||||
adau->type = type;
|
||||
@ -910,6 +973,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_probe);
|
||||
|
||||
void adau17x1_remove(struct device *dev)
|
||||
{
|
||||
struct adau *adau = dev_get_drvdata(dev);
|
||||
|
||||
snd_soc_unregister_codec(dev);
|
||||
if (adau->mclk)
|
||||
clk_disable_unprepare(adau->mclk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_remove);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -22,13 +22,18 @@ enum adau17x1_pll_src {
|
||||
};
|
||||
|
||||
enum adau17x1_clk_src {
|
||||
/* Automatically configure PLL based on the sample rate */
|
||||
ADAU17X1_CLK_SRC_PLL_AUTO,
|
||||
ADAU17X1_CLK_SRC_MCLK,
|
||||
ADAU17X1_CLK_SRC_PLL,
|
||||
};
|
||||
|
||||
struct clk;
|
||||
|
||||
struct adau {
|
||||
unsigned int sysclk;
|
||||
unsigned int pll_freq;
|
||||
struct clk *mclk;
|
||||
|
||||
enum adau17x1_clk_src clk_src;
|
||||
enum adau17x1_type type;
|
||||
@ -52,6 +57,7 @@ int adau17x1_add_routes(struct snd_soc_codec *codec);
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
|
||||
const char *firmware_name);
|
||||
void adau17x1_remove(struct device *dev);
|
||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||
enum adau17x1_micbias_voltage micbias);
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
|
||||
|
80
sound/soc/codecs/adau7002.c
Normal file
80
sound/soc/codecs/adau7002.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* ADAU7002 Stereo PDM-to-I2S/TDM converter driver
|
||||
*
|
||||
* Copyright 2014-2016 Analog Devices
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
static const struct snd_soc_dapm_widget adau7002_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("PDM_DAT"),
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau7002_routes[] = {
|
||||
{ "Capture", NULL, "PDM_DAT" },
|
||||
{ "Capture", NULL, "IOVDD" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver adau7002_dai = {
|
||||
.name = "adau7002-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 20,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_codec_driver adau7002_codec_driver = {
|
||||
.dapm_widgets = adau7002_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau7002_widgets),
|
||||
.dapm_routes = adau7002_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adau7002_routes),
|
||||
};
|
||||
|
||||
static int adau7002_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &adau7002_codec_driver,
|
||||
&adau7002_dai, 1);
|
||||
}
|
||||
|
||||
static int adau7002_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id adau7002_dt_ids[] = {
|
||||
{ .compatible = "adi,adau7002", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adau7002_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver adau7002_driver = {
|
||||
.driver = {
|
||||
.name = "adau7002",
|
||||
.of_match_table = of_match_ptr(adau7002_dt_ids),
|
||||
},
|
||||
.probe = adau7002_probe,
|
||||
.remove = adau7002_remove,
|
||||
};
|
||||
module_platform_driver(adau7002_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ADAU7002 Stereo PDM-to-I2S/TDM Converter driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -437,15 +437,25 @@ static struct snd_soc_dai_driver ak4613_dai = {
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static int ak4613_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_cache_only(regmap, true);
|
||||
regcache_mark_dirty(regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4613_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_mark_dirty(regmap);
|
||||
regcache_cache_only(regmap, false);
|
||||
return regcache_sync(regmap);
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
|
||||
.suspend = ak4613_suspend,
|
||||
.resume = ak4613_resume,
|
||||
.set_bias_level = ak4613_set_bias_level,
|
||||
.controls = ak4613_snd_controls,
|
||||
|
@ -523,15 +523,23 @@ static struct snd_soc_dai_driver ak4642_dai = {
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static int ak4642_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_cache_only(regmap, true);
|
||||
regcache_mark_dirty(regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_mark_dirty(regmap);
|
||||
regcache_cache_only(regmap, false);
|
||||
regcache_sync(regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
@ -544,6 +552,7 @@ static int ak4642_probe(struct snd_soc_codec *codec)
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
|
||||
.probe = ak4642_probe,
|
||||
.suspend = ak4642_suspend,
|
||||
.resume = ak4642_resume,
|
||||
.set_bias_level = ak4642_set_bias_level,
|
||||
.controls = ak4642_snd_controls,
|
||||
|
@ -85,30 +85,9 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
bool manual_ena = false;
|
||||
int val;
|
||||
|
||||
switch (arizona->type) {
|
||||
case WM5102:
|
||||
switch (arizona->rev) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
manual_ena = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
if (!priv->spk_ena && manual_ena) {
|
||||
regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
|
||||
priv->spk_ena_pending = true;
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
|
||||
if (val & ARIZONA_SPK_OVERHEAT_STS) {
|
||||
@ -120,33 +99,12 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
|
||||
regmap_update_bits_async(arizona->regmap,
|
||||
ARIZONA_OUTPUT_ENABLES_1,
|
||||
1 << w->shift, 1 << w->shift);
|
||||
|
||||
if (priv->spk_ena_pending) {
|
||||
msleep(75);
|
||||
regmap_write_async(arizona->regmap, 0x4f5, 0xda);
|
||||
priv->spk_ena_pending = false;
|
||||
priv->spk_ena++;
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
if (manual_ena) {
|
||||
priv->spk_ena--;
|
||||
if (!priv->spk_ena)
|
||||
regmap_write_async(arizona->regmap,
|
||||
0x4f5, 0x25a);
|
||||
}
|
||||
|
||||
regmap_update_bits_async(arizona->regmap,
|
||||
ARIZONA_OUTPUT_ENABLES_1,
|
||||
1 << w->shift, 0);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
if (manual_ena) {
|
||||
if (!priv->spk_ena)
|
||||
regmap_write_async(arizona->regmap,
|
||||
0x4f5, 0x0da);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -324,6 +282,17 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_gpio);
|
||||
|
||||
int arizona_init_notifiers(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_notifiers);
|
||||
|
||||
const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
|
||||
"None",
|
||||
"Tone Generator 1",
|
||||
@ -619,7 +588,7 @@ const struct soc_enum arizona_asrc_rate1 =
|
||||
arizona_rate_text, arizona_rate_val);
|
||||
EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
|
||||
|
||||
static const char *arizona_vol_ramp_text[] = {
|
||||
static const char * const arizona_vol_ramp_text[] = {
|
||||
"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
|
||||
"15ms/6dB", "30ms/6dB",
|
||||
};
|
||||
@ -648,7 +617,7 @@ SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
|
||||
arizona_vol_ramp_text);
|
||||
EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
|
||||
|
||||
static const char *arizona_lhpf_mode_text[] = {
|
||||
static const char * const arizona_lhpf_mode_text[] = {
|
||||
"Low-pass", "High-pass"
|
||||
};
|
||||
|
||||
@ -676,7 +645,7 @@ SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
|
||||
arizona_lhpf_mode_text);
|
||||
EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
|
||||
|
||||
static const char *arizona_ng_hold_text[] = {
|
||||
static const char * const arizona_ng_hold_text[] = {
|
||||
"30ms", "120ms", "250ms", "500ms",
|
||||
};
|
||||
|
||||
@ -810,6 +779,14 @@ const struct soc_enum arizona_output_anc_src[] = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_output_anc_src);
|
||||
|
||||
const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
|
||||
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 3, 1, 0),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
|
||||
|
||||
static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
@ -2573,6 +2550,30 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
|
||||
|
||||
int arizona_register_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb,
|
||||
int (*notify)(struct notifier_block *nb,
|
||||
unsigned long action, void *data))
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
nb->notifier_call = notify;
|
||||
|
||||
return blocking_notifier_chain_register(&arizona->notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_register_notifier);
|
||||
|
||||
int arizona_unregister_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
|
||||
return blocking_notifier_chain_unregister(&arizona->notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_unregister_notifier);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -63,6 +63,9 @@
|
||||
#define ARIZONA_DVFS_SR1_RQ 0x001
|
||||
#define ARIZONA_DVFS_ADSP1_RQ 0x100
|
||||
|
||||
/* Notifier events */
|
||||
#define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1
|
||||
|
||||
struct arizona;
|
||||
struct wm_adsp;
|
||||
|
||||
@ -87,14 +90,15 @@ struct arizona_priv {
|
||||
unsigned int out_down_pending;
|
||||
unsigned int out_down_delay;
|
||||
|
||||
unsigned int spk_ena:2;
|
||||
unsigned int spk_ena_pending:1;
|
||||
|
||||
unsigned int dvfs_reqs;
|
||||
struct mutex dvfs_lock;
|
||||
bool dvfs_cached;
|
||||
};
|
||||
|
||||
struct arizona_voice_trigger_info {
|
||||
int core;
|
||||
};
|
||||
|
||||
#define ARIZONA_NUM_MIXER_INPUTS 104
|
||||
|
||||
extern const unsigned int arizona_mixer_tlv[];
|
||||
@ -248,6 +252,8 @@ extern const struct soc_enum arizona_anc_input_src[];
|
||||
extern const struct soc_enum arizona_anc_ng_enum;
|
||||
extern const struct soc_enum arizona_output_anc_src[];
|
||||
|
||||
extern const struct snd_kcontrol_new arizona_voice_trigger_switch[];
|
||||
|
||||
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
@ -306,6 +312,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
extern int arizona_init_spk(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_gpio(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_mono(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_notifiers(struct snd_soc_codec *codec);
|
||||
|
||||
extern int arizona_free_spk(struct snd_soc_codec *codec);
|
||||
|
||||
@ -317,4 +324,13 @@ int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
|
||||
extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
|
||||
|
||||
extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
|
||||
|
||||
extern int arizona_register_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb,
|
||||
int (*notify)(struct notifier_block *nb,
|
||||
unsigned long action,
|
||||
void *data));
|
||||
extern int arizona_unregister_notifier(struct snd_soc_codec *codec,
|
||||
struct notifier_block *nb);
|
||||
|
||||
#endif
|
||||
|
@ -25,22 +25,41 @@ static const struct snd_soc_dapm_route bt_sco_routes[] = {
|
||||
{ "TX", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver bt_sco_dai = {
|
||||
.name = "bt-sco-pcm",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
static struct snd_soc_dai_driver bt_sco_dai[] = {
|
||||
{
|
||||
.name = "bt-sco-pcm",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "bt-sco-pcm-wb",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
|
||||
@ -53,7 +72,7 @@ static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
|
||||
static int bt_sco_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
|
||||
&bt_sco_dai, 1);
|
||||
bt_sco_dai, ARRAY_SIZE(bt_sco_dai));
|
||||
}
|
||||
|
||||
static int bt_sco_remove(struct platform_device *pdev)
|
||||
@ -77,6 +96,7 @@ MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id bt_sco_codec_of_match[] = {
|
||||
{ .compatible = "delta,dfbmcs320", },
|
||||
{ .compatible = "linux,bt-sco", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
|
||||
|
1303
sound/soc/codecs/cs35l33.c
Normal file
1303
sound/soc/codecs/cs35l33.c
Normal file
File diff suppressed because it is too large
Load Diff
221
sound/soc/codecs/cs35l33.h
Normal file
221
sound/soc/codecs/cs35l33.h
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* cs35l33.h -- CS35L33 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2016 Cirrus Logic, Inc.
|
||||
*
|
||||
* Author: Paul Handrigan <paul.handrigan@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CS35L33_H__
|
||||
#define __CS35L33_H__
|
||||
|
||||
#define CS35L33_CHIP_ID 0x00035A33
|
||||
#define CS35L33_DEVID_AB 0x01 /* Device ID A & B [RO] */
|
||||
#define CS35L33_DEVID_CD 0x02 /* Device ID C & D [RO] */
|
||||
#define CS35L33_DEVID_E 0x03 /* Device ID E [RO] */
|
||||
#define CS35L33_FAB_ID 0x04 /* Fab ID [RO] */
|
||||
#define CS35L33_REV_ID 0x05 /* Revision ID [RO] */
|
||||
#define CS35L33_PWRCTL1 0x06 /* Power Ctl 1 */
|
||||
#define CS35L33_PWRCTL2 0x07 /* Power Ctl 2 */
|
||||
#define CS35L33_CLK_CTL 0x08 /* Clock Ctl */
|
||||
#define CS35L33_BST_PEAK_CTL 0x09 /* Max Current for Boost */
|
||||
#define CS35L33_PROTECT_CTL 0x0A /* Amp Protection Parameters */
|
||||
#define CS35L33_BST_CTL1 0x0B /* Boost Converter CTL1 */
|
||||
#define CS35L33_BST_CTL2 0x0C /* Boost Converter CTL2 */
|
||||
#define CS35L33_ADSP_CTL 0x0D /* Serial Port Control */
|
||||
#define CS35L33_ADC_CTL 0x0E /* ADC Control */
|
||||
#define CS35L33_DAC_CTL 0x0F /* DAC Control */
|
||||
#define CS35L33_DIG_VOL_CTL 0x10 /* Digital Volume CTL */
|
||||
#define CS35L33_CLASSD_CTL 0x11 /* Class D Amp CTL */
|
||||
#define CS35L33_AMP_CTL 0x12 /* Amp Gain/Protecton Release CTL */
|
||||
#define CS35L33_INT_MASK_1 0x13 /* Interrupt Mask 1 */
|
||||
#define CS35L33_INT_MASK_2 0x14 /* Interrupt Mask 2 */
|
||||
#define CS35L33_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */
|
||||
#define CS35L33_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */
|
||||
#define CS35L33_DIAG_LOCK 0x17 /* Diagnostic Mode Register Lock */
|
||||
#define CS35L33_DIAG_CTRL_1 0x18 /* Diagnostic Mode Register Control */
|
||||
#define CS35L33_DIAG_CTRL_2 0x19 /* Diagnostic Mode Register Control 2 */
|
||||
#define CS35L33_HG_MEMLDO_CTL 0x23 /* H/G Memory/LDO CTL */
|
||||
#define CS35L33_HG_REL_RATE 0x24 /* H/G Release Rate */
|
||||
#define CS35L33_LDO_DEL 0x25 /* LDO Entry Delay/VPhg Control 1 */
|
||||
#define CS35L33_HG_HEAD 0x29 /* H/G Headroom */
|
||||
#define CS35L33_HG_EN 0x2A /* H/G Enable/VPhg CNT2 */
|
||||
#define CS35L33_TX_VMON 0x2D /* TDM TX Control 1 (VMON) */
|
||||
#define CS35L33_TX_IMON 0x2E /* TDM TX Control 2 (IMON) */
|
||||
#define CS35L33_TX_VPMON 0x2F /* TDM TX Control 3 (VPMON) */
|
||||
#define CS35L33_TX_VBSTMON 0x30 /* TDM TX Control 4 (VBSTMON) */
|
||||
#define CS35L33_TX_FLAG 0x31 /* TDM TX Control 5 (FLAG) */
|
||||
#define CS35L33_TX_EN1 0x32 /* TDM TX Enable 1 */
|
||||
#define CS35L33_TX_EN2 0x33 /* TDM TX Enable 2 */
|
||||
#define CS35L33_TX_EN3 0x34 /* TDM TX Enable 3 */
|
||||
#define CS35L33_TX_EN4 0x35 /* TDM TX Enable 4 */
|
||||
#define CS35L33_RX_AUD 0x36 /* TDM RX Control 1 */
|
||||
#define CS35L33_RX_SPLY 0x37 /* TDM RX Control 2 */
|
||||
#define CS35L33_RX_ALIVE 0x38 /* TDM RX Control 3 */
|
||||
#define CS35L33_BST_CTL4 0x39 /* Boost Converter Control 4 */
|
||||
#define CS35L33_HG_STATUS 0x3F /* H/G Status */
|
||||
#define CS35L33_MAX_REGISTER 0x59
|
||||
|
||||
#define CS35L33_MCLK_5644 5644800
|
||||
#define CS35L33_MCLK_6144 6144000
|
||||
#define CS35L33_MCLK_6 6000000
|
||||
#define CS35L33_MCLK_11289 11289600
|
||||
#define CS35L33_MCLK_12 12000000
|
||||
#define CS35L33_MCLK_12288 12288000
|
||||
|
||||
/* CS35L33_PWRCTL1 */
|
||||
#define CS35L33_PDN_AMP (1 << 7)
|
||||
#define CS35L33_PDN_BST (1 << 2)
|
||||
#define CS35L33_PDN_ALL 1
|
||||
|
||||
/* CS35L33_PWRCTL2 */
|
||||
#define CS35L33_PDN_VMON_SHIFT 7
|
||||
#define CS35L33_PDN_VMON (1 << CS35L33_PDN_VMON_SHIFT)
|
||||
#define CS35L33_PDN_IMON_SHIFT 6
|
||||
#define CS35L33_PDN_IMON (1 << CS35L33_PDN_IMON_SHIFT)
|
||||
#define CS35L33_PDN_VPMON_SHIFT 5
|
||||
#define CS35L33_PDN_VPMON (1 << CS35L33_PDN_VPMON_SHIFT)
|
||||
#define CS35L33_PDN_VBSTMON_SHIFT 4
|
||||
#define CS35L33_PDN_VBSTMON (1 << CS35L33_PDN_VBSTMON_SHIFT)
|
||||
#define CS35L33_SDOUT_3ST_I2S_SHIFT 3
|
||||
#define CS35L33_SDOUT_3ST_I2S (1 << CS35L33_SDOUT_3ST_I2S_SHIFT)
|
||||
#define CS35L33_PDN_SDIN_SHIFT 2
|
||||
#define CS35L33_PDN_SDIN (1 << CS35L33_PDN_SDIN_SHIFT)
|
||||
#define CS35L33_PDN_TDM_SHIFT 1
|
||||
#define CS35L33_PDN_TDM (1 << CS35L33_PDN_TDM_SHIFT)
|
||||
|
||||
/* CS35L33_CLK_CTL */
|
||||
#define CS35L33_MCLKDIS (1 << 7)
|
||||
#define CS35L33_MCLKDIV2 (1 << 6)
|
||||
#define CS35L33_SDOUT_3ST_TDM (1 << 5)
|
||||
#define CS35L33_INT_FS_RATE (1 << 4)
|
||||
#define CS35L33_ADSP_FS 0xF
|
||||
|
||||
/* CS35L33_PROTECT_CTL */
|
||||
#define CS35L33_ALIVE_WD_DIS (3 << 2)
|
||||
|
||||
/* CS35L33_BST_CTL1 */
|
||||
#define CS35L33_BST_CTL_SRC (1 << 6)
|
||||
#define CS35L33_BST_CTL_SHIFT (1 << 5)
|
||||
#define CS35L33_BST_CTL_MASK 0x3F
|
||||
|
||||
/* CS35L33_BST_CTL2 */
|
||||
#define CS35L33_TDM_WD_SEL (1 << 4)
|
||||
#define CS35L33_ALIVE_WD_DIS2 (1 << 3)
|
||||
#define CS35L33_VBST_SR_STEP 0x3
|
||||
|
||||
/* CS35L33_ADSP_CTL */
|
||||
#define CS35L33_ADSP_DRIVE (1 << 7)
|
||||
#define CS35L33_MS_MASK (1 << 6)
|
||||
#define CS35L33_SDIN_LOC (3 << 4)
|
||||
#define CS35L33_ALIVE_RATE 0x3
|
||||
|
||||
/* CS35L33_ADC_CTL */
|
||||
#define CS35L33_INV_VMON (1 << 7)
|
||||
#define CS35L33_INV_IMON (1 << 6)
|
||||
#define CS35L33_ADC_NOTCH_DIS (1 << 5)
|
||||
#define CS35L33_IMON_SCALE 0xF
|
||||
|
||||
/* CS35L33_DAC_CTL */
|
||||
#define CS35L33_INV_DAC (1 << 7)
|
||||
#define CS35L33_DAC_NOTCH_DIS (1 << 5)
|
||||
#define CS35L33_DIGSFT (1 << 4)
|
||||
#define CS35L33_DSR_RATE 0xF
|
||||
|
||||
/* CS35L33_CLASSD_CTL */
|
||||
#define CS35L33_AMP_SD (1 << 6)
|
||||
#define CS35L33_AMP_DRV_SEL_SRC (1 << 5)
|
||||
#define CS35L33_AMP_DRV_SEL_MASK 0x10
|
||||
#define CS35L33_AMP_DRV_SEL_SHIFT 4
|
||||
#define CS35L33_AMP_CAL (1 << 3)
|
||||
#define CS35L33_GAIN_CHG_ZC_MASK 0x04
|
||||
#define CS35L33_GAIN_CHG_ZC_SHIFT 2
|
||||
#define CS35L33_CLASS_D_CTL_MASK 0x3F
|
||||
|
||||
/* CS35L33_AMP_CTL */
|
||||
#define CS35L33_AMP_GAIN 0xF0
|
||||
#define CS35L33_CAL_ERR_RLS (1 << 3)
|
||||
#define CS35L33_AMP_SHORT_RLS (1 << 2)
|
||||
#define CS35L33_OTW_RLS (1 << 1)
|
||||
#define CS35L33_OTE_RLS 1
|
||||
|
||||
/* CS35L33_INT_MASK_1 */
|
||||
#define CS35L33_M_CAL_ERR_SHIFT 6
|
||||
#define CS35L33_M_CAL_ERR (1 << CS35L33_M_CAL_ERR_SHIFT)
|
||||
#define CS35L33_M_ALIVE_ERR_SHIFT 5
|
||||
#define CS35L33_M_ALIVE_ERR (1 << CS35L33_M_ALIVE_ERR_SHIFT)
|
||||
#define CS35L33_M_AMP_SHORT_SHIFT 2
|
||||
#define CS35L33_M_AMP_SHORT (1 << CS35L33_M_AMP_SHORT_SHIFT)
|
||||
#define CS35L33_M_OTW_SHIFT 1
|
||||
#define CS35L33_M_OTW (1 << CS35L33_M_OTW_SHIFT)
|
||||
#define CS35L33_M_OTE_SHIFT 0
|
||||
#define CS35L33_M_OTE (1 << CS35L33_M_OTE_SHIFT)
|
||||
|
||||
/* CS35L33_INT_STATUS_1 */
|
||||
#define CS35L33_CAL_ERR (1 << 6)
|
||||
#define CS35L33_ALIVE_ERR (1 << 5)
|
||||
#define CS35L33_ADSPCLK_ERR (1 << 4)
|
||||
#define CS35L33_MCLK_ERR (1 << 3)
|
||||
#define CS35L33_AMP_SHORT (1 << 2)
|
||||
#define CS35L33_OTW (1 << 1)
|
||||
#define CS35L33_OTE (1 << 0)
|
||||
|
||||
/* CS35L33_INT_STATUS_2 */
|
||||
#define CS35L33_VMON_OVFL (1 << 7)
|
||||
#define CS35L33_IMON_OVFL (1 << 6)
|
||||
#define CS35L33_VPMON_OVFL (1 << 5)
|
||||
#define CS35L33_VBSTMON_OVFL (1 << 4)
|
||||
#define CS35L33_PDN_DONE 1
|
||||
|
||||
/* CS35L33_BST_CTL4 */
|
||||
#define CS35L33_BST_RGS 0x70
|
||||
#define CS35L33_BST_COEFF3 0xF
|
||||
|
||||
/* CS35L33_HG_MEMLDO_CTL */
|
||||
#define CS35L33_MEM_DEPTH_SHIFT 5
|
||||
#define CS35L33_MEM_DEPTH_MASK (0x3 << CS35L33_MEM_DEPTH_SHIFT)
|
||||
#define CS35L33_LDO_THLD_SHIFT 1
|
||||
#define CS35L33_LDO_THLD_MASK (0xF << CS35L33_LDO_THLD_SHIFT)
|
||||
#define CS35L33_LDO_DISABLE_SHIFT 0
|
||||
#define CS35L33_LDO_DISABLE_MASK (0x1 << CS35L33_LDO_DISABLE_SHIFT)
|
||||
|
||||
/* CS35L33_LDO_DEL */
|
||||
#define CS35L33_VP_HG_VA_SHIFT 5
|
||||
#define CS35L33_VP_HG_VA_MASK (0x7 << CS35L33_VP_HG_VA_SHIFT)
|
||||
#define CS35L33_LDO_ENTRY_DELAY_SHIFT 2
|
||||
#define CS35L33_LDO_ENTRY_DELAY_MASK (0x7 << CS35L33_LDO_ENTRY_DELAY_SHIFT)
|
||||
#define CS35L33_VP_HG_RATE_SHIFT 0
|
||||
#define CS35L33_VP_HG_RATE_MASK (0x3 << CS35L33_VP_HG_RATE_SHIFT)
|
||||
|
||||
/* CS35L33_HG_HEAD */
|
||||
#define CS35L33_HD_RM_SHIFT 0
|
||||
#define CS35L33_HD_RM_MASK (0x7F << CS35L33_HD_RM_SHIFT)
|
||||
|
||||
/* CS35L33_HG_EN */
|
||||
#define CS35L33_CLASS_HG_ENA_SHIFT 7
|
||||
#define CS35L33_CLASS_HG_EN_MASK (0x1 << CS35L33_CLASS_HG_ENA_SHIFT)
|
||||
#define CS35L33_VP_HG_AUTO_SHIFT 6
|
||||
#define CS35L33_VP_HG_AUTO_MASK (0x1 << 6)
|
||||
#define CS35L33_VP_HG_SHIFT 0
|
||||
#define CS35L33_VP_HG_MASK (0x1F << CS35L33_VP_HG_SHIFT)
|
||||
|
||||
#define CS35L33_RATES (SNDRV_PCM_RATE_8000_48000)
|
||||
#define CS35L33_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
/* CS35L33_{RX,TX}_X */
|
||||
#define CS35L33_X_STATE_SHIFT 7
|
||||
#define CS35L33_X_STATE (1 << CS35L33_X_STATE_SHIFT)
|
||||
#define CS35L33_X_LOC_SHIFT 0
|
||||
#define CS35L33_X_LOC (0x1F << CS35L33_X_LOC_SHIFT)
|
||||
|
||||
/* CS35L33_RX_AUD */
|
||||
#define CS35L33_AUDIN_RX_DEPTH_SHIFT 5
|
||||
#define CS35L33_AUDIN_RX_DEPTH (0x7 << CS35L33_AUDIN_RX_DEPTH_SHIFT)
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user