mirror of
https://github.com/suyu-emu/horinux.git
synced 2026-09-21 14:15:21 -07:00
Merge tag 'sound-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"There have been major modernization with the standard bus: in ALSA
sequencer core and HD-audio. Also, HD-audio receives the regmap
support replacing the in-house cache register cache code. These
changes shouldn't impact the existing behavior, but rather
refactoring.
In addition, HD-audio got the code split to a core library part and
the "legacy" driver parts. This is a preliminary work for adapting
the upcoming ASoC HD-audio driver, and the whole transition is still
work in progress, likely finished in 4.1.
Along with them, there are many updates in ASoC area as usual, too:
lots of cleanups, Intel code shuffling, etc.
Here are some highlights:
ALSA core:
- PCM: the audio timestamp / wallclock enhancement
- PCM: fixes in DPCM management
- Fixes / cleanups of user-space control element management
- Sequencer: modernization using the standard bus
HD-audio:
- Modernization using the standard bus
- Regmap support
- Use standard runtime PM for codec power saving
- Widget-path based power-saving for IDT, VIA and Realtek codecs
- Reorganized sysfs entries for each codec object
- More Dell headset support
ASoC:
- Move of jack registration to the card level
- Lots of ASoC cleanups, mainly moving things from the CODEC level to
the card level
- Support for DAPM routes specified by both the machine driver and DT
- Continuing improvements to rcar
- pcm512x enhacements
- Intel platforms updates
- rt5670 updates / fixes
- New platforms / devices: some non-DSP Qualcomm platforms, Google's
Storm platform, Maxmim MAX98925 CODECs and the Ingenic JZ4780 SoC
Misc:
- ice1724: Improved ESI W192M support
- emu10k1: Emu 1010 fixes/enhancement"
* tag 'sound-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (411 commits)
ALSA: hda - set GET bit when adding a vendor verb to the codec regmap
ALSA: hda/realtek - Enable the ALC292 dock fixup on the Thinkpad T450
ALSA: hda - Fix another race in runtime PM refcounting
ALSA: hda - Expose codec type sysfs
ALSA: ctl: fix to handle several elements added by one operation for userspace element
ASoC: Intel: fix array_size.cocci warnings
ASoC: n810: Automatically disconnect non-connected pins
ASoC: n810: Consistently pass the card DAPM context to n810_ext_control()
ASoC: davinci-evm: Use card DAPM context to access widgets
ASoC: mop500_ab8500: Use card DAPM context to access widgets
ASoC: wm1133-ev1: Use card DAPM context to access widgets
ASoC: atmel: Improve machine driver compile test coverage
ASoC: atmel: Add dependency to SND_SOC_I2C_AND_SPI where necessary
ALSA: control: Fix a typo of SNDRV_CTL_ELEM_ACCESS_TLV_* with SNDRV_CTL_TLV_OP_*
ALSA: usb-audio: Don't attempt to get Microsoft Lifecam Cinema sample rate
ASoC: rnsd: fix build regression without CONFIG_OF
ALSA: emu10k1: add toggles for E-mu 1010 optical ports
ALSA: ctl: fill identical information to return value when adding userspace elements
ALSA: ctl: fix a bug to return no identical information in info operation for userspace controls
ALSA: ctl: confirm to return all identical information in 'activate' event
...
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
Ingenic JZ4740 I2S controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "ingenic,jz4740-i2s"
|
||||
- compatible : "ingenic,jz4740-i2s" or "ingenic,jz4780-i2s"
|
||||
- reg : I2S registers location and length
|
||||
- clocks : AIC and I2S PLL clock specifiers.
|
||||
- clock-names: "aic" and "i2s"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
max98925 audio CODEC
|
||||
|
||||
This device supports I2C.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "maxim,max98925"
|
||||
|
||||
- vmon-slot-no : slot number used to send voltage information
|
||||
|
||||
- imon-slot-no : slot number used to send current information
|
||||
|
||||
- reg : the I2C address of the device for I2C
|
||||
|
||||
Example:
|
||||
|
||||
codec: max98925@1a {
|
||||
compatible = "maxim,max98925";
|
||||
vmon-slot-no = <0>;
|
||||
imon-slot-no = <2>;
|
||||
reg = <0x1a>;
|
||||
};
|
||||
@@ -18,6 +18,7 @@ Required properties:
|
||||
* Headphones
|
||||
* Speakers
|
||||
* Mic Jack
|
||||
* Int Mic
|
||||
|
||||
- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
|
||||
connected to the CODEC.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
* Qualcomm Technologies LPASS CPU DAI
|
||||
|
||||
This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "qcom,lpass-cpu"
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
- clock-names : A list which must include the following entries:
|
||||
* "ahbix-clk"
|
||||
* "mi2s-osr-clk"
|
||||
* "mi2s-bit-clk"
|
||||
- interrupts : Must contain an entry for each entry in
|
||||
interrupt-names.
|
||||
- interrupt-names : A list which must include the following entries:
|
||||
* "lpass-irq-lpaif"
|
||||
- pinctrl-N : One property must exist for each entry in
|
||||
pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
|
||||
for details of the property values.
|
||||
- pinctrl-names : Must contain a "default" entry.
|
||||
- reg : Must contain an address for each entry in reg-names.
|
||||
- reg-names : A list which must include the following entries:
|
||||
* "lpass-lpaif"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- qcom,adsp : Phandle for the audio DSP node
|
||||
|
||||
Example:
|
||||
|
||||
lpass@28100000 {
|
||||
compatible = "qcom,lpass-cpu";
|
||||
clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>;
|
||||
clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk";
|
||||
interrupts = <0 85 1>;
|
||||
interrupt-names = "lpass-irq-lpaif";
|
||||
pinctrl-names = "default", "idle";
|
||||
pinctrl-0 = <&mi2s_default>;
|
||||
pinctrl-1 = <&mi2s_idle>;
|
||||
reg = <0x28100000 0x10000>;
|
||||
reg-names = "lpass-lpaif";
|
||||
qcom,adsp = <&adsp>;
|
||||
};
|
||||
@@ -29,9 +29,17 @@ SSI subnode properties:
|
||||
- shared-pin : if shared clock pin
|
||||
- pio-transfer : use PIO transfer mode
|
||||
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : SSI case "rx" (=playback), "tx" (=capture)
|
||||
SSIU case "rxu" (=playback), "txu" (=capture)
|
||||
|
||||
SRC subnode properties:
|
||||
no properties at this point
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : "rx" (=playback), "tx" (=capture)
|
||||
|
||||
DVC subnode properties:
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : "tx" (=playback/capture)
|
||||
|
||||
DAI subnode properties:
|
||||
- playback : list of playback modules
|
||||
@@ -45,56 +53,145 @@ rcar_sound: rcar_sound@ec500000 {
|
||||
reg = <0 0xec500000 0 0x1000>, /* SCU */
|
||||
<0 0xec5a0000 0 0x100>, /* ADG */
|
||||
<0 0xec540000 0 0x1000>, /* SSIU */
|
||||
<0 0xec541000 0 0x1280>; /* SSI */
|
||||
<0 0xec541000 0 0x1280>, /* SSI */
|
||||
<0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/
|
||||
reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
|
||||
|
||||
clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>,
|
||||
<&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>,
|
||||
<&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>,
|
||||
<&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>,
|
||||
<&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>,
|
||||
<&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>,
|
||||
<&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>,
|
||||
<&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>,
|
||||
<&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>,
|
||||
<&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>,
|
||||
<&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>,
|
||||
<&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>,
|
||||
<&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>;
|
||||
clock-names = "ssi-all",
|
||||
"ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
|
||||
"ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
|
||||
"src.9", "src.8", "src.7", "src.6", "src.5",
|
||||
"src.4", "src.3", "src.2", "src.1", "src.0",
|
||||
"dvc.0", "dvc.1",
|
||||
"clk_a", "clk_b", "clk_c", "clk_i";
|
||||
|
||||
rcar_sound,dvc {
|
||||
dvc0: dvc@0 { };
|
||||
dvc1: dvc@1 { };
|
||||
dvc0: dvc@0 {
|
||||
dmas = <&audma0 0xbc>;
|
||||
dma-names = "tx";
|
||||
};
|
||||
dvc1: dvc@1 {
|
||||
dmas = <&audma0 0xbe>;
|
||||
dma-names = "tx";
|
||||
};
|
||||
};
|
||||
|
||||
rcar_sound,src {
|
||||
src0: src@0 { };
|
||||
src1: src@1 { };
|
||||
src2: src@2 { };
|
||||
src3: src@3 { };
|
||||
src4: src@4 { };
|
||||
src5: src@5 { };
|
||||
src6: src@6 { };
|
||||
src7: src@7 { };
|
||||
src8: src@8 { };
|
||||
src9: src@9 { };
|
||||
src0: src@0 {
|
||||
interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x85>, <&audma1 0x9a>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src1: src@1 {
|
||||
interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x87>, <&audma1 0x9c>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src2: src@2 {
|
||||
interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x89>, <&audma1 0x9e>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src3: src@3 {
|
||||
interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x8b>, <&audma1 0xa0>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src4: src@4 {
|
||||
interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x8d>, <&audma1 0xb0>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src5: src@5 {
|
||||
interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x8f>, <&audma1 0xb2>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src6: src@6 {
|
||||
interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x91>, <&audma1 0xb4>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src7: src@7 {
|
||||
interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x93>, <&audma1 0xb6>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src8: src@8 {
|
||||
interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x95>, <&audma1 0xb8>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
src9: src@9 {
|
||||
interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x97>, <&audma1 0xba>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
};
|
||||
|
||||
rcar_sound,ssi {
|
||||
ssi0: ssi@0 {
|
||||
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi1: ssi@1 {
|
||||
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi2: ssi@2 {
|
||||
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi3: ssi@3 {
|
||||
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi4: ssi@4 {
|
||||
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi5: ssi@5 {
|
||||
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi6: ssi@6 {
|
||||
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi7: ssi@7 {
|
||||
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi8: ssi@8 {
|
||||
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi9: ssi@9 {
|
||||
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
Renesas Sampling Rate Convert Sound Card:
|
||||
|
||||
Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC <-> codec.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "renesas,rsrc-card,<board>"
|
||||
Examples with soctypes are:
|
||||
- "renesas,rsrc-card,lager"
|
||||
- "renesas,rsrc-card,koelsch"
|
||||
Optional properties:
|
||||
|
||||
- card_name : User specified audio sound card name, one string
|
||||
property.
|
||||
- cpu : CPU sub-node
|
||||
- codec : CODEC sub-node
|
||||
|
||||
Optional subnode properties:
|
||||
|
||||
- format : CPU/CODEC common audio format.
|
||||
"i2s", "right_j", "left_j" , "dsp_a"
|
||||
"dsp_b", "ac97", "pdm", "msb", "lsb"
|
||||
- frame-master : Indicates dai-link frame master.
|
||||
phandle to a cpu or codec subnode.
|
||||
- bitclock-master : Indicates dai-link bit clock master.
|
||||
phandle to a cpu or codec subnode.
|
||||
- bitclock-inversion : bool property. Add this if the
|
||||
dai-link uses bit clock inversion.
|
||||
- frame-inversion : bool property. Add this if the
|
||||
dai-link uses frame clock inversion.
|
||||
- convert-rate : platform specified sampling rate convert
|
||||
|
||||
Required CPU/CODEC subnodes properties:
|
||||
|
||||
- sound-dai : phandle and port of CPU/CODEC
|
||||
|
||||
Optional CPU/CODEC subnodes properties:
|
||||
|
||||
- clocks / system-clock-frequency : specify subnode's clock if needed.
|
||||
it can be specified via "clocks" if system has
|
||||
clock node (= common clock), or "system-clock-frequency"
|
||||
(if system doens't support common clock)
|
||||
If a clock is specified, it is
|
||||
enabled with clk_prepare_enable()
|
||||
in dai startup() and disabled with
|
||||
clk_disable_unprepare() in dai
|
||||
shutdown().
|
||||
|
||||
Example
|
||||
|
||||
sound {
|
||||
compatible = "renesas,rsrc-card,lager";
|
||||
|
||||
card-name = "rsnd-ak4643";
|
||||
format = "left_j";
|
||||
bitclock-master = <&sndcodec>;
|
||||
frame-master = <&sndcodec>;
|
||||
|
||||
sndcpu: cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
|
||||
sndcodec: codec {
|
||||
sound-dai = <&ak4643>;
|
||||
system-clock-frequency = <11289600>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
* Sound complex for Storm boards
|
||||
|
||||
Models a soundcard for Storm boards with the Qualcomm Technologies IPQ806x SOC
|
||||
connected to a MAX98357A DAC via I2S.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "google,storm-audio"
|
||||
- cpu : Phandle of the CPU DAI
|
||||
- codec : Phandle of the codec DAI
|
||||
|
||||
Optional properties:
|
||||
|
||||
- qcom,model : The user-visible name of this sound card.
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "google,storm-audio";
|
||||
qcom,model = "ipq806x-storm";
|
||||
cpu = <&lpass_cpu>;
|
||||
codec = <&max98357a>;
|
||||
};
|
||||
@@ -10,6 +10,13 @@ Required properties:
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
- PVDD-supply, DVDD-supply : Power supplies for the device, as covered
|
||||
in Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
Optional properties:
|
||||
|
||||
- wlf,reset-gpio: A GPIO specifier for the GPIO controlling the reset pin
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8804@1a {
|
||||
|
||||
@@ -71,11 +71,11 @@ SOURCE:
|
||||
HDMI/DP (either HDMI or DisplayPort)
|
||||
|
||||
Exceptions (deprecated):
|
||||
[Digital] Capture Source
|
||||
[Digital] Capture Switch (aka input gain switch)
|
||||
[Digital] Capture Volume (aka input gain volume)
|
||||
[Digital] Playback Switch (aka output gain switch)
|
||||
[Digital] Playback Volume (aka output gain volume)
|
||||
[Analogue|Digital] Capture Source
|
||||
[Analogue|Digital] Capture Switch (aka input gain switch)
|
||||
[Analogue|Digital] Capture Volume (aka input gain volume)
|
||||
[Analogue|Digital] Playback Switch (aka output gain switch)
|
||||
[Analogue|Digital] Playback Volume (aka output gain volume)
|
||||
Tone Control - Switch
|
||||
Tone Control - Bass
|
||||
Tone Control - Treble
|
||||
|
||||
@@ -466,7 +466,11 @@ The generic parser supports the following hints:
|
||||
- add_jack_modes (bool): add "xxx Jack Mode" enum controls to each
|
||||
I/O jack for allowing to change the headphone amp and mic bias VREF
|
||||
capabilities
|
||||
- power_down_unused (bool): power down the unused widgets
|
||||
- power_save_node (bool): advanced power management for each widget,
|
||||
controlling the power sate (D0/D3) of each widget node depending on
|
||||
the actual pin and stream states
|
||||
- power_down_unused (bool): power down the unused widgets, a subset of
|
||||
power_save_node, and will be dropped in future
|
||||
- add_hp_mic (bool): add the headphone to capture source if possible
|
||||
- hp_mic_detect (bool): enable/disable the hp/mic shared input for a
|
||||
single built-in mic case; default true
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
The ALSA API can provide two different system timestamps:
|
||||
|
||||
- Trigger_tstamp is the system time snapshot taken when the .trigger
|
||||
callback is invoked. This snapshot is taken by the ALSA core in the
|
||||
general case, but specific hardware may have synchronization
|
||||
capabilities or conversely may only be able to provide a correct
|
||||
estimate with a delay. In the latter two cases, the low-level driver
|
||||
is responsible for updating the trigger_tstamp at the most appropriate
|
||||
and precise moment. Applications should not rely solely on the first
|
||||
trigger_tstamp but update their internal calculations if the driver
|
||||
provides a refined estimate with a delay.
|
||||
|
||||
- tstamp is the current system timestamp updated during the last
|
||||
event or application query.
|
||||
The difference (tstamp - trigger_tstamp) defines the elapsed time.
|
||||
|
||||
The ALSA API provides reports 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.
|
||||
|
||||
The use of these different pointers and time information depends on
|
||||
the application needs:
|
||||
|
||||
- 'avail' reports how much can be written in the ring buffer
|
||||
- 'delay' reports the time it will take to hear a new sample after all
|
||||
queued samples have been played out.
|
||||
|
||||
When timestamps are enabled, the avail/delay information is reported
|
||||
along with a snapshot of system time. Applications can select from
|
||||
CLOCK_REALTIME (NTP corrections including going backwards),
|
||||
CLOCK_MONOTONIC (NTP corrections but never going backwards),
|
||||
CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode
|
||||
dynamically with sw_params
|
||||
|
||||
|
||||
The ALSA API also provide an audio_tstamp which reflects the passage
|
||||
of time as measured by different components of audio hardware. In
|
||||
ascii-art, this could be represented as follows (for the playback
|
||||
case):
|
||||
|
||||
|
||||
--------------------------------------------------------------> time
|
||||
^ ^ ^ ^ ^
|
||||
| | | | |
|
||||
analog link dma app FullBuffer
|
||||
time time time time time
|
||||
| | | | |
|
||||
|< codec delay >|<--hw delay-->|<queued samples>|<---avail->|
|
||||
|<----------------- delay---------------------->| |
|
||||
|<----ring buffer length---->|
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
audio time it wants reported by selecting the relevant settings in
|
||||
audio_tstamp_config fields, 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
|
||||
time with dedicated hardware, possibly synchronized with system time,
|
||||
removes the need to keep track of internal DSP processing times and
|
||||
latency.
|
||||
|
||||
In case the application requests an audio tstamp that is not supported
|
||||
in hardware/low-level driver, the type is overridden as DEFAULT and the
|
||||
timestamp will report the DMA time based on the hw_pointer value.
|
||||
|
||||
For backwards compatibility with previous implementations that did not
|
||||
provide timestamp selection, with a zero-valued COMPAT timestamp type
|
||||
the results will default to the HDAudio wall clock for playback
|
||||
streams and to the DMA time (hw_ptr) in all other cases.
|
||||
|
||||
The audio timestamp accuracy can be returned to user-space, so that
|
||||
appropriate decisions are made:
|
||||
|
||||
- for dma time (default), the granularity of the transfers can be
|
||||
inferred from the steps between updates and in turn provide
|
||||
information on how much the application pointer can be rewound
|
||||
safely.
|
||||
|
||||
- the link time can be used to track long-term drifts between audio
|
||||
and system time using the (tstamp-trigger_tstamp)/audio_tstamp
|
||||
ratio, the precision helps define how much smoothing/low-pass
|
||||
filtering is required. The link time can be either reset on startup
|
||||
or reported as is (the latter being useful to compare progress of
|
||||
different streams - but may require the wallclock to be always
|
||||
running and not wrap-around during idle periods). If supported in
|
||||
hardware, the absolute link time could also be used to define a
|
||||
precise start time (patches WIP)
|
||||
|
||||
- including the delay in the audio timestamp may
|
||||
counter-intuitively not increase the precision of timestamps, e.g. if a
|
||||
codec includes variable-latency DSP processing or a chain of
|
||||
hardware components the delay is typically not known with precision.
|
||||
|
||||
The accuracy is reported in nanosecond units (using an unsigned 32-bit
|
||||
word), which gives a max precision of 4.29s, more than enough for
|
||||
audio applications...
|
||||
|
||||
Due to the varied nature of timestamping needs, even for a single
|
||||
application, the audio_tstamp_config can be changed dynamically. In
|
||||
the STATUS ioctl, the parameters are read-only and do not allow for
|
||||
any application selection. To work around this limitation without
|
||||
impacting legacy applications, a new STATUS_EXT ioctl is introduced
|
||||
with read/write parameters. ALSA-lib will be modified to make use of
|
||||
STATUS_EXT and effectively deprecate STATUS.
|
||||
|
||||
The ALSA API only allows for a single audio timestamp to be reported
|
||||
at a time. This is a conscious design decision, reading the audio
|
||||
timestamps from hardware registers or from IPC takes time, the more
|
||||
timestamps are read the more imprecise the combined measurements
|
||||
are. To avoid any interpretation issues, a single (system, audio)
|
||||
timestamp is reported. Applications that need different timestamps
|
||||
will be required to issue multiple queries and perform an
|
||||
interpolation of the results
|
||||
|
||||
In some hardware-specific configuration, the system timestamp is
|
||||
latched by a low-level audio subsytem, and the information provided
|
||||
back to the driver. Due to potential delays in the communication with
|
||||
the hardware, there is a risk of misalignment with the avail and delay
|
||||
information. To make sure applications are not confused, a
|
||||
driver_timestamp field is added in the snd_pcm_status structure; this
|
||||
timestamp shows when the information is put together by the driver
|
||||
before returning from the STATUS and STATUS_EXT ioctl. in most cases
|
||||
this driver_timestamp will be identical to the regular system tstamp.
|
||||
|
||||
Examples of typestamping with HDaudio:
|
||||
|
||||
1. DMA timestamp, no compensation for DMA+analog delay
|
||||
$ ./audio_time -p --ts_type=1
|
||||
playback: systime: 341121338 nsec, audio time 342000000 nsec, systime delta -878662
|
||||
playback: systime: 426236663 nsec, audio time 427187500 nsec, systime delta -950837
|
||||
playback: systime: 597080580 nsec, audio time 598000000 nsec, systime delta -919420
|
||||
playback: systime: 682059782 nsec, audio time 683020833 nsec, systime delta -961051
|
||||
playback: systime: 852896415 nsec, audio time 853854166 nsec, systime delta -957751
|
||||
playback: systime: 937903344 nsec, audio time 938854166 nsec, systime delta -950822
|
||||
|
||||
2. DMA timestamp, compensation for DMA+analog delay
|
||||
$ ./audio_time -p --ts_type=1 -d
|
||||
playback: systime: 341053347 nsec, audio time 341062500 nsec, systime delta -9153
|
||||
playback: systime: 426072447 nsec, audio time 426062500 nsec, systime delta 9947
|
||||
playback: systime: 596899518 nsec, audio time 596895833 nsec, systime delta 3685
|
||||
playback: systime: 681915317 nsec, audio time 681916666 nsec, systime delta -1349
|
||||
playback: systime: 852741306 nsec, audio time 852750000 nsec, systime delta -8694
|
||||
|
||||
3. link timestamp, compensation for DMA+analog delay
|
||||
$ ./audio_time -p --ts_type=2 -d
|
||||
playback: systime: 341060004 nsec, audio time 341062791 nsec, systime delta -2787
|
||||
playback: systime: 426242074 nsec, audio time 426244875 nsec, systime delta -2801
|
||||
playback: systime: 597080992 nsec, audio time 597084583 nsec, systime delta -3591
|
||||
playback: systime: 682084512 nsec, audio time 682088291 nsec, systime delta -3779
|
||||
playback: systime: 852936229 nsec, audio time 852940916 nsec, systime delta -4687
|
||||
playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -5146
|
||||
|
||||
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
|
||||
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
|
||||
dispersion.
|
||||
|
||||
Example 3 and 4 are with USB audio class. Example 3 shows a high
|
||||
offset between audio time and system time due to buffering. Example 4
|
||||
shows how compensating for the delay exposes a 1ms accuracy (due to
|
||||
the use of the frame counter by the driver)
|
||||
|
||||
Example 3: DMA timestamp, no compensation for delay, delta of ~5ms
|
||||
$ ./audio_time -p -Dhw:1 -t1
|
||||
playback: systime: 120174019 nsec, audio time 125000000 nsec, systime delta -4825981
|
||||
playback: systime: 245041136 nsec, audio time 250000000 nsec, systime delta -4958864
|
||||
playback: systime: 370106088 nsec, audio time 375000000 nsec, systime delta -4893912
|
||||
playback: systime: 495040065 nsec, audio time 500000000 nsec, systime delta -4959935
|
||||
playback: systime: 620038179 nsec, audio time 625000000 nsec, systime delta -4961821
|
||||
playback: systime: 745087741 nsec, audio time 750000000 nsec, systime delta -4912259
|
||||
playback: systime: 870037336 nsec, audio time 875000000 nsec, systime delta -4962664
|
||||
|
||||
Example 4: DMA timestamp, compensation for delay, delay of ~1ms
|
||||
$ ./audio_time -p -Dhw:1 -t1 -d
|
||||
playback: systime: 120190520 nsec, audio time 120000000 nsec, systime delta 190520
|
||||
playback: systime: 245036740 nsec, audio time 244000000 nsec, systime delta 1036740
|
||||
playback: systime: 370034081 nsec, audio time 369000000 nsec, systime delta 1034081
|
||||
playback: systime: 495159907 nsec, audio time 494000000 nsec, systime delta 1159907
|
||||
playback: systime: 620098824 nsec, audio time 619000000 nsec, systime delta 1098824
|
||||
playback: systime: 745031847 nsec, audio time 744000000 nsec, systime delta 1031847
|
||||
+8
-1
@@ -1764,7 +1764,7 @@ S: Supported
|
||||
F: drivers/tty/serial/atmel_serial.c
|
||||
|
||||
ATMEL Audio ALSA driver
|
||||
M: Bo Shen <voice.shen@atmel.com>
|
||||
M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: sound/soc/atmel
|
||||
@@ -5301,6 +5301,13 @@ F: drivers/char/ipmi/
|
||||
F: include/linux/ipmi*
|
||||
F: include/uapi/linux/ipmi*
|
||||
|
||||
QCOM AUDIO (ASoC) DRIVERS
|
||||
M: Patrick Lai <plai@codeaurora.org>
|
||||
M: Banajit Goswami <bgoswami@codeaurora.org>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: sound/soc/qcom/
|
||||
|
||||
IPS SCSI RAID DRIVER
|
||||
M: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
|
||||
@@ -1015,7 +1015,6 @@ static struct asoc_simple_card_info fsi_wm8978_info = {
|
||||
.platform = "sh_fsi2",
|
||||
.daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||
.cpu_dai = {
|
||||
.fmt = SND_SOC_DAIFMT_IB_NF,
|
||||
.name = "fsia-dai",
|
||||
},
|
||||
.codec_dai = {
|
||||
@@ -1040,9 +1039,9 @@ static struct asoc_simple_card_info fsi2_hdmi_info = {
|
||||
.card = "FSI2B-HDMI",
|
||||
.codec = "sh-mobile-hdmi",
|
||||
.platform = "sh_fsi2",
|
||||
.daifmt = SND_SOC_DAIFMT_CBS_CFS,
|
||||
.cpu_dai = {
|
||||
.name = "fsib-dai",
|
||||
.fmt = SND_SOC_DAIFMT_CBS_CFS,
|
||||
},
|
||||
.codec_dai = {
|
||||
.name = "sh_mobile_hdmi-hifi",
|
||||
|
||||
@@ -194,6 +194,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
|
||||
|
||||
return ERR_PTR(ret_no_channel);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_dma_request_slave_channel);
|
||||
|
||||
/**
|
||||
* of_dma_simple_xlate - Simple DMA engine translation function
|
||||
|
||||
@@ -608,7 +608,9 @@ struct ac97_quirk {
|
||||
int type; /* quirk type above */
|
||||
};
|
||||
|
||||
int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override);
|
||||
int snd_ac97_tune_hardware(struct snd_ac97 *ac97,
|
||||
const struct ac97_quirk *quirk,
|
||||
const char *override);
|
||||
int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate);
|
||||
|
||||
/*
|
||||
|
||||
@@ -70,7 +70,7 @@ struct snd_compr_runtime {
|
||||
* @device: device pointer
|
||||
* @direction: stream direction, playback/recording
|
||||
* @metadata_set: metadata set flag, true when set
|
||||
* @next_track: has userspace signall next track transistion, true when set
|
||||
* @next_track: has userspace signal next track transition, true when set
|
||||
* @private_data: pointer to DSP private data
|
||||
*/
|
||||
struct snd_compr_stream {
|
||||
@@ -95,7 +95,7 @@ struct snd_compr_stream {
|
||||
* and the stream properties
|
||||
* @get_params: retrieve the codec parameters, mandatory
|
||||
* @set_metadata: Set the metadata values for a stream
|
||||
* @get_metadata: retreives the requested metadata values from stream
|
||||
* @get_metadata: retrieves the requested metadata values from stream
|
||||
* @trigger: Trigger operations like start, pause, resume, drain, stop.
|
||||
* This callback is mandatory
|
||||
* @pointer: Retrieve current h/w pointer information. Mandatory
|
||||
|
||||
@@ -227,7 +227,7 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
|
||||
* Add a virtual slave control to the given master.
|
||||
* Unlike snd_ctl_add_slave(), the element added via this function
|
||||
* is supposed to have volatile values, and get callback is called
|
||||
* at each time quried from the master.
|
||||
* at each time queried from the master.
|
||||
*
|
||||
* When the control peeks the hardware values directly and the value
|
||||
* can be changed by other means than the put callback of the element,
|
||||
|
||||
@@ -278,7 +278,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
|
||||
void *device_data, struct snd_device_ops *ops);
|
||||
int snd_device_register(struct snd_card *card, void *device_data);
|
||||
int snd_device_register_all(struct snd_card *card);
|
||||
int snd_device_disconnect_all(struct snd_card *card);
|
||||
void snd_device_disconnect(struct snd_card *card, void *device_data);
|
||||
void snd_device_disconnect_all(struct snd_card *card);
|
||||
void snd_device_free(struct snd_card *card, void *device_data);
|
||||
void snd_device_free_all(struct snd_card *card);
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* HD-audio regmap helpers
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_HDA_REGMAP_H
|
||||
#define __SOUND_HDA_REGMAP_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/hdaudio.h>
|
||||
|
||||
int snd_hdac_regmap_init(struct hdac_device *codec);
|
||||
void snd_hdac_regmap_exit(struct hdac_device *codec);
|
||||
int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
|
||||
unsigned int verb);
|
||||
int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
|
||||
unsigned int *val);
|
||||
int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
|
||||
unsigned int val);
|
||||
int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
|
||||
unsigned int mask, unsigned int val);
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
|
||||
* @nid: widget NID
|
||||
* @verb: codec verb
|
||||
*
|
||||
* Returns an encoded pseudo register.
|
||||
*/
|
||||
#define snd_hdac_regmap_encode_verb(nid, verb) \
|
||||
(((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
|
||||
* @nid: widget NID
|
||||
* @ch: channel (left = 0, right = 1)
|
||||
* @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
|
||||
* @idx: input index value
|
||||
*
|
||||
* Returns an encoded pseudo register.
|
||||
*/
|
||||
#define snd_hdac_regmap_encode_amp(nid, ch, dir, idx) \
|
||||
(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
|
||||
((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) | \
|
||||
((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
|
||||
(idx))
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
|
||||
* @nid: widget NID
|
||||
* @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
|
||||
* @idx: input index value
|
||||
*
|
||||
* Returns an encoded pseudo register.
|
||||
*/
|
||||
#define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx) \
|
||||
(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
|
||||
AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */ \
|
||||
((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
|
||||
(idx))
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_write - Write a verb with caching
|
||||
* @nid: codec NID
|
||||
* @reg: verb to write
|
||||
* @val: value to write
|
||||
*
|
||||
* For writing an amp value, use snd_hda_regmap_amp_update().
|
||||
*/
|
||||
static inline int
|
||||
snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
|
||||
unsigned int verb, unsigned int val)
|
||||
{
|
||||
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
|
||||
|
||||
return snd_hdac_regmap_write_raw(codec, cmd, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_regmap_update - Update a verb value with caching
|
||||
* @nid: codec NID
|
||||
* @verb: verb to update
|
||||
* @mask: bit mask to update
|
||||
* @val: value to update
|
||||
*
|
||||
* For updating an amp value, use snd_hda_regmap_amp_update().
|
||||
*/
|
||||
static inline int
|
||||
snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
|
||||
unsigned int verb, unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
|
||||
|
||||
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_regmap_read - Read a verb with caching
|
||||
* @nid: codec NID
|
||||
* @verb: verb to read
|
||||
* @val: pointer to store the value
|
||||
*
|
||||
* For reading an amp value, use snd_hda_regmap_get_amp().
|
||||
*/
|
||||
static inline int
|
||||
snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
|
||||
unsigned int verb, unsigned int *val)
|
||||
{
|
||||
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
|
||||
|
||||
return snd_hdac_regmap_read_raw(codec, cmd, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_get_amp - Read AMP value
|
||||
* @codec: HD-audio codec
|
||||
* @nid: NID to read the AMP value
|
||||
* @ch: channel (left=0 or right=1)
|
||||
* @direction: #HDA_INPUT or #HDA_OUTPUT
|
||||
* @index: the index value (only for input direction)
|
||||
* @val: the pointer to store the value
|
||||
*
|
||||
* Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
|
||||
* Returns the value or a negative error.
|
||||
*/
|
||||
static inline int
|
||||
snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
|
||||
int ch, int dir, int idx)
|
||||
{
|
||||
unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
|
||||
int err, val;
|
||||
|
||||
err = snd_hdac_regmap_read_raw(codec, cmd, &val);
|
||||
return err < 0 ? err : val;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_update_amp - update the AMP value
|
||||
* @codec: HD-audio codec
|
||||
* @nid: NID to read the AMP value
|
||||
* @ch: channel (left=0 or right=1)
|
||||
* @direction: #HDA_INPUT or #HDA_OUTPUT
|
||||
* @idx: the index value (only for input direction)
|
||||
* @mask: bit mask to set
|
||||
* @val: the bits value to set
|
||||
*
|
||||
* Update the AMP value with a bit mask.
|
||||
* Returns 0 if the value is unchanged, 1 if changed, or a negative error.
|
||||
*/
|
||||
static inline int
|
||||
snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
|
||||
int ch, int dir, int idx, int mask, int val)
|
||||
{
|
||||
unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
|
||||
|
||||
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
|
||||
* @codec: HD-audio codec
|
||||
* @nid: NID to read the AMP value
|
||||
* @ch: channel (left=0 or right=1)
|
||||
* @direction: #HDA_INPUT or #HDA_OUTPUT
|
||||
* @index: the index value (only for input direction)
|
||||
* @val: the pointer to store the value
|
||||
*
|
||||
* Read stereo AMP values. The lower byte is left, the upper byte is right.
|
||||
* Returns the value or a negative error.
|
||||
*/
|
||||
static inline int
|
||||
snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
|
||||
int dir, int idx)
|
||||
{
|
||||
unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
|
||||
int err, val;
|
||||
|
||||
err = snd_hdac_regmap_read_raw(codec, cmd, &val);
|
||||
return err < 0 ? err : val;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
|
||||
* @codec: HD-audio codec
|
||||
* @nid: NID to read the AMP value
|
||||
* @direction: #HDA_INPUT or #HDA_OUTPUT
|
||||
* @idx: the index value (only for input direction)
|
||||
* @mask: bit mask to set
|
||||
* @val: the bits value to set
|
||||
*
|
||||
* Update the stereo AMP value with a bit mask.
|
||||
* The lower byte is left, the upper byte is right.
|
||||
* Returns 0 if the value is unchanged, 1 if changed, or a negative error.
|
||||
*/
|
||||
static inline int
|
||||
snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
|
||||
int dir, int idx, int mask, int val)
|
||||
{
|
||||
unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
|
||||
|
||||
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_regmap_sync_node - sync the widget node attributes
|
||||
* @codec: HD-audio codec
|
||||
* @nid: NID to sync
|
||||
*/
|
||||
static inline void
|
||||
snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid)
|
||||
{
|
||||
regcache_mark_dirty(codec->regmap);
|
||||
regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1);
|
||||
}
|
||||
|
||||
#endif /* __SOUND_HDA_REGMAP_H */
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* HD-audio core stuff
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_HDAUDIO_H
|
||||
#define __SOUND_HDAUDIO_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <sound/hda_verbs.h>
|
||||
|
||||
/* codec node id */
|
||||
typedef u16 hda_nid_t;
|
||||
|
||||
struct hdac_bus;
|
||||
struct hdac_device;
|
||||
struct hdac_driver;
|
||||
struct hdac_widget_tree;
|
||||
|
||||
/*
|
||||
* exported bus type
|
||||
*/
|
||||
extern struct bus_type snd_hda_bus_type;
|
||||
|
||||
/*
|
||||
* generic arrays
|
||||
*/
|
||||
struct snd_array {
|
||||
unsigned int used;
|
||||
unsigned int alloced;
|
||||
unsigned int elem_size;
|
||||
unsigned int alloc_align;
|
||||
void *list;
|
||||
};
|
||||
|
||||
/*
|
||||
* HD-audio codec base device
|
||||
*/
|
||||
struct hdac_device {
|
||||
struct device dev;
|
||||
int type;
|
||||
struct hdac_bus *bus;
|
||||
unsigned int addr; /* codec address */
|
||||
struct list_head list; /* list point for bus codec_list */
|
||||
|
||||
hda_nid_t afg; /* AFG node id */
|
||||
hda_nid_t mfg; /* MFG node id */
|
||||
|
||||
/* ids */
|
||||
unsigned int vendor_id;
|
||||
unsigned int subsystem_id;
|
||||
unsigned int revision_id;
|
||||
unsigned int afg_function_id;
|
||||
unsigned int mfg_function_id;
|
||||
unsigned int afg_unsol:1;
|
||||
unsigned int mfg_unsol:1;
|
||||
|
||||
unsigned int power_caps; /* FG power caps */
|
||||
|
||||
const char *vendor_name; /* codec vendor name */
|
||||
const char *chip_name; /* codec chip name */
|
||||
|
||||
/* verb exec op override */
|
||||
int (*exec_verb)(struct hdac_device *dev, unsigned int cmd,
|
||||
unsigned int flags, unsigned int *res);
|
||||
|
||||
/* widgets */
|
||||
unsigned int num_nodes;
|
||||
hda_nid_t start_nid, end_nid;
|
||||
|
||||
/* misc flags */
|
||||
atomic_t in_pm; /* suspend/resume being performed */
|
||||
|
||||
/* sysfs */
|
||||
struct hdac_widget_tree *widgets;
|
||||
|
||||
/* regmap */
|
||||
struct regmap *regmap;
|
||||
struct snd_array vendor_verbs;
|
||||
bool lazy_cache:1; /* don't wake up for writes */
|
||||
bool caps_overwriting:1; /* caps overwrite being in process */
|
||||
bool cache_coef:1; /* cache COEF read/write too */
|
||||
};
|
||||
|
||||
/* device/driver type used for matching */
|
||||
enum {
|
||||
HDA_DEV_CORE,
|
||||
HDA_DEV_LEGACY,
|
||||
};
|
||||
|
||||
/* direction */
|
||||
enum {
|
||||
HDA_INPUT, HDA_OUTPUT
|
||||
};
|
||||
|
||||
#define dev_to_hdac_dev(_dev) container_of(_dev, struct hdac_device, dev)
|
||||
|
||||
int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus,
|
||||
const char *name, unsigned int addr);
|
||||
void snd_hdac_device_exit(struct hdac_device *dev);
|
||||
int snd_hdac_device_register(struct hdac_device *codec);
|
||||
void snd_hdac_device_unregister(struct hdac_device *codec);
|
||||
|
||||
int snd_hdac_refresh_widgets(struct hdac_device *codec);
|
||||
|
||||
unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
|
||||
unsigned int verb, unsigned int parm);
|
||||
int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
|
||||
unsigned int flags, unsigned int *res);
|
||||
int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
|
||||
unsigned int verb, unsigned int parm, unsigned int *res);
|
||||
int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
|
||||
unsigned int *res);
|
||||
int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
|
||||
int parm);
|
||||
int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
|
||||
unsigned int parm, unsigned int val);
|
||||
int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
|
||||
hda_nid_t *start_id);
|
||||
|
||||
/**
|
||||
* snd_hdac_read_parm - read a codec parameter
|
||||
* @codec: the codec object
|
||||
* @nid: NID to read a parameter
|
||||
* @parm: parameter to read
|
||||
*
|
||||
* Returns -1 for error. If you need to distinguish the error more
|
||||
* strictly, use _snd_hdac_read_parm() directly.
|
||||
*/
|
||||
static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid,
|
||||
int parm)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
return _snd_hdac_read_parm(codec, nid, parm, &val) < 0 ? -1 : val;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void snd_hdac_power_up(struct hdac_device *codec);
|
||||
void snd_hdac_power_down(struct hdac_device *codec);
|
||||
void snd_hdac_power_up_pm(struct hdac_device *codec);
|
||||
void snd_hdac_power_down_pm(struct hdac_device *codec);
|
||||
#else
|
||||
static inline void snd_hdac_power_up(struct hdac_device *codec) {}
|
||||
static inline void snd_hdac_power_down(struct hdac_device *codec) {}
|
||||
static inline void snd_hdac_power_up_pm(struct hdac_device *codec) {}
|
||||
static inline void snd_hdac_power_down_pm(struct hdac_device *codec) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* HD-audio codec base driver
|
||||
*/
|
||||
struct hdac_driver {
|
||||
struct device_driver driver;
|
||||
int type;
|
||||
int (*match)(struct hdac_device *dev, struct hdac_driver *drv);
|
||||
void (*unsol_event)(struct hdac_device *dev, unsigned int event);
|
||||
};
|
||||
|
||||
#define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver)
|
||||
|
||||
/*
|
||||
* HD-audio bus base driver
|
||||
*/
|
||||
struct hdac_bus_ops {
|
||||
/* send a single command */
|
||||
int (*command)(struct hdac_bus *bus, unsigned int cmd);
|
||||
/* get a response from the last command */
|
||||
int (*get_response)(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int *res);
|
||||
};
|
||||
|
||||
#define HDA_UNSOL_QUEUE_SIZE 64
|
||||
|
||||
struct hdac_bus {
|
||||
struct device *dev;
|
||||
const struct hdac_bus_ops *ops;
|
||||
|
||||
/* codec linked list */
|
||||
struct list_head codec_list;
|
||||
unsigned int num_codecs;
|
||||
|
||||
/* link caddr -> codec */
|
||||
struct hdac_device *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1];
|
||||
|
||||
/* unsolicited event queue */
|
||||
u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */
|
||||
unsigned int unsol_rp, unsol_wp;
|
||||
struct work_struct unsol_work;
|
||||
|
||||
/* bit flags of powered codecs */
|
||||
unsigned long codec_powered;
|
||||
|
||||
/* flags */
|
||||
bool sync_write:1; /* sync after verb write */
|
||||
|
||||
/* locks */
|
||||
struct mutex cmd_mutex;
|
||||
};
|
||||
|
||||
int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops);
|
||||
void snd_hdac_bus_exit(struct hdac_bus *bus);
|
||||
int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int cmd, unsigned int *res);
|
||||
int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int cmd, unsigned int *res);
|
||||
void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
|
||||
|
||||
int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec);
|
||||
void snd_hdac_bus_remove_device(struct hdac_bus *bus,
|
||||
struct hdac_device *codec);
|
||||
|
||||
static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
|
||||
{
|
||||
set_bit(codec->addr, &codec->bus->codec_powered);
|
||||
}
|
||||
|
||||
static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
|
||||
{
|
||||
clear_bit(codec->addr, &codec->bus->codec_powered);
|
||||
}
|
||||
|
||||
/*
|
||||
* generic array helpers
|
||||
*/
|
||||
void *snd_array_new(struct snd_array *array);
|
||||
void snd_array_free(struct snd_array *array);
|
||||
static inline void snd_array_init(struct snd_array *array, unsigned int size,
|
||||
unsigned int align)
|
||||
{
|
||||
array->elem_size = size;
|
||||
array->alloc_align = align;
|
||||
}
|
||||
|
||||
static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
|
||||
{
|
||||
return array->list + idx * array->elem_size;
|
||||
}
|
||||
|
||||
static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
|
||||
{
|
||||
return (unsigned long)(ptr - array->list) / array->elem_size;
|
||||
}
|
||||
|
||||
#endif /* __SOUND_HDAUDIO_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user