Commit 1c521d7e authored by Mark Brown's avatar Mark Brown

Merge branch 'asoc-5.7' into asoc-next

parents 8e3bb8ec 3d2cdb85
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/amlogic,aiu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic AIU audio output controller
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
properties:
$nodename:
pattern: "^audio-controller@.*"
"#sound-dai-cells":
const: 2
compatible:
items:
- enum:
- amlogic,aiu-gxbb
- amlogic,aiu-gxl
- amlogic,aiu-meson8
- amlogic,aiu-meson8b
- const:
amlogic,aiu
clocks:
items:
- description: AIU peripheral clock
- description: I2S peripheral clock
- description: I2S output clock
- description: I2S master clock
- description: I2S mixer clock
- description: SPDIF peripheral clock
- description: SPDIF output clock
- description: SPDIF master clock
- description: SPDIF master clock multiplexer
clock-names:
items:
- const: pclk
- const: i2s_pclk
- const: i2s_aoclk
- const: i2s_mclk
- const: i2s_mixer
- const: spdif_pclk
- const: spdif_aoclk
- const: spdif_mclk
- const: spdif_mclk_sel
interrupts:
items:
- description: I2S interrupt line
- description: SPDIF interrupt line
interrupt-names:
items:
- const: i2s
- const: spdif
reg:
maxItems: 1
resets:
maxItems: 1
required:
- "#sound-dai-cells"
- compatible
- clocks
- clock-names
- interrupts
- interrupt-names
- reg
- resets
examples:
- |
#include <dt-bindings/clock/gxbb-clkc.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
aiu: audio-controller@5400 {
compatible = "amlogic,aiu-gxl", "amlogic,aiu";
#sound-dai-cells = <2>;
reg = <0x0 0x5400 0x0 0x2ac>;
interrupts = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "i2s", "spdif";
clocks = <&clkc CLKID_AIU_GLUE>,
<&clkc CLKID_I2S_OUT>,
<&clkc CLKID_AOCLK_GATE>,
<&clkc CLKID_CTS_AMCLK>,
<&clkc CLKID_MIXER_IFACE>,
<&clkc CLKID_IEC958>,
<&clkc CLKID_IEC958_GATE>,
<&clkc CLKID_CTS_MCLK_I958>,
<&clkc CLKID_CTS_I958>;
clock-names = "pclk",
"i2s_pclk",
"i2s_aoclk",
"i2s_mclk",
"i2s_mixer",
"spdif_pclk",
"spdif_aoclk",
"spdif_mclk",
"spdif_mclk_sel";
resets = <&reset RESET_AIU>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/amlogic,g12a-toacodec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic G12a Internal DAC Control Glue
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
properties:
$nodename:
pattern: "^audio-controller@.*"
"#sound-dai-cells":
const: 1
compatible:
oneOf:
- items:
- const:
amlogic,g12a-toacodec
- items:
- enum:
- amlogic,sm1-toacodec
- const:
amlogic,g12a-toacodec
reg:
maxItems: 1
resets:
maxItems: 1
required:
- "#sound-dai-cells"
- compatible
- reg
- resets
examples:
- |
#include <dt-bindings/reset/amlogic,meson-g12a-audio-reset.h>
toacodec: audio-controller@740 {
compatible = "amlogic,g12a-toacodec";
reg = <0x0 0x740 0x0 0x4>;
#sound-dai-cells = <1>;
resets = <&clkc_audio AUD_RESET_TOACODEC>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/amlogic,gx-sound-card.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic GX sound card
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
properties:
compatible:
items:
- const: amlogic,gx-sound-card
audio-aux-devs:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: list of auxiliary devices
audio-routing:
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
minItems: 2
description: |-
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.
audio-widgets:
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
minItems: 2
description: |-
A list off component DAPM widget. Each entry is a pair of strings,
the first being the widget type, the second being the widget name
model:
$ref: /schemas/types.yaml#/definitions/string
description: User specified audio sound card name
patternProperties:
"^dai-link-[0-9]+$":
type: object
description: |-
dai-link child nodes:
Container for dai-link level properties and the CODEC sub-nodes.
There should be at least one (and probably more) subnode of this type
properties:
dai-format:
$ref: /schemas/types.yaml#/definitions/string
enum: [ i2s, left-j, dsp_a ]
mclk-fs:
$ref: /schemas/types.yaml#/definitions/uint32
description: |-
Multiplication factor between the frame rate and master clock
rate
sound-dai:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle of the CPU DAI
patternProperties:
"^codec-[0-9]+$":
type: object
description: |-
Codecs:
dai-link representing backend links should have at least one subnode.
One subnode for each codec of the dai-link. dai-link representing
frontend links have no codec, therefore have no subnodes
properties:
sound-dai:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle of the codec DAI
required:
- sound-dai
required:
- sound-dai
required:
- model
- dai-link-0
examples:
- |
sound {
compatible = "amlogic,gx-sound-card";
model = "GXL-ACME-S905X-FOO";
audio-aux-devs = <&amp>;
audio-routing = "I2S ENCODER I2S IN", "I2S FIFO Playback";
dai-link-0 {
sound-dai = <&i2s_fifo>;
};
dai-link-1 {
sound-dai = <&i2s_encoder>;
dai-format = "i2s";
mclk-fs = <256>;
codec-0 {
sound-dai = <&codec0>;
};
codec-1 {
sound-dai = <&codec1>;
};
};
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/amlogic,t9015.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic T9015 Internal Audio DAC
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
properties:
$nodename:
pattern: "^audio-controller@.*"
"#sound-dai-cells":
const: 0
compatible:
items:
- const: amlogic,t9015
clocks:
items:
- description: Peripheral clock
clock-names:
items:
- const: pclk
reg:
maxItems: 1
resets:
maxItems: 1
required:
- "#sound-dai-cells"
- compatible
- reg
- clocks
- clock-names
- resets
examples:
- |
#include <dt-bindings/clock/g12a-clkc.h>
#include <dt-bindings/reset/amlogic,meson-g12a-reset.h>
acodec: audio-controller@32000 {
compatible = "amlogic,t9015";
reg = <0x0 0x32000 0x0 0x14>;
#sound-dai-cells = <0>;
clocks = <&clkc CLKID_AUDIO_CODEC>;
clock-names = "pclk";
resets = <&reset RESET_AUDIO_CODEC>;
};
Broadcom DSL/PON BCM63xx Audio I2S controller
Required properties:
- compatible: Should be "brcm,bcm63xx-i2s".
- #address-cells: 32bit valued, 1 cell.
- #size-cells: 32bit valued, 0 cell.
- reg: Should contain audio registers location and length
- interrupts: Should contain the interrupt for the controller.
- clocks: Must contain an entry for each entry in clock-names.
Please refer to clock-bindings.txt.
- clock-names: One of each entry matching the clocks phandles list:
- "i2sclk" (generated clock) Required.
- "i2sosc" (fixed 200MHz clock) Required.
(1) : The generated clock is required only when any of TX and RX
works on Master Mode.
(2) : The fixed 200MHz clock is from internal chip and always on
Example:
i2s: bcm63xx-i2s {
#address-cells = <1>;
#size-cells = <0>;
compatible = "brcm,bcm63xx-i2s";
reg = <0xFF802080 0xFF>;
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&i2sclk>, <&osc>;
clock-names = "i2sclk","i2sosc";
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/cirrus,cs42l51.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: CS42L51 audio codec DT bindings
maintainers:
- Olivier Moysan <olivier.moysan@st.com>
properties:
compatible:
const: cirrus,cs42l51
reg:
maxItems: 1
"#sound-dai-cells":
const: 0
clocks:
maxItems: 1
clock-names:
items:
- const: MCLK
reset-gpios:
maxItems: 1
VL-supply:
description: phandle to voltage regulator of digital interface section
VD-supply:
description: phandle to voltage regulator of digital internal section
VA-supply:
description: phandle to voltage regulator of analog internal section
VAHP-supply:
description: phandle to voltage regulator of headphone
required:
- compatible
- reg
- "#sound-dai-cells"
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
cs42l51@4a {
compatible = "cirrus,cs42l51";
reg = <0x4a>;
#sound-dai-cells = <0>;
clocks = <&mclk_prov>;
clock-names = "MCLK";
VL-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VA-supply = <&reg_audio>;
VAHP-supply = <&reg_audio>;
reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
};
};
...
CS42L51 audio CODEC
Required properties:
- compatible : "cirrus,cs42l51"
- reg : the I2C address of the device for I2C.
Optional properties:
- VL-supply, VD-supply, VA-supply, VAHP-supply: power supplies for the device,
as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
- reset-gpios : GPIO specification for the reset pin. If specified, it will be
deasserted before starting the communication with the codec.
- clocks : a list of phandles + clock-specifiers, one for each entry in
clock-names
- clock-names : must contain "MCLK"
Example:
cs42l51: cs42l51@4a {
compatible = "cirrus,cs42l51";
reg = <0x4a>;
clocks = <&mclk_prov>;
clock-names = "MCLK";
VL-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VA-supply = <&reg_audio>;
VAHP-supply = <&reg_audio>;
reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
};
Audio codec controlled by ChromeOS EC
Google's ChromeOS EC codec is a digital mic codec provided by the
Embedded Controller (EC) and is controlled via a host-command interface.
An EC codec node should only be found as a sub-node of the EC node (see
Documentation/devicetree/bindings/mfd/cros-ec.txt).
Required properties:
- compatible: Must contain "google,cros-ec-codec"
- #sound-dai-cells: Should be 1. The cell specifies number of DAIs.
Optional properties:
- reg: Pysical base address and length of shared memory region from EC.
It contains 3 unsigned 32-bit integer. The first 2 integers
combine to become an unsigned 64-bit physical address. The last
one integer is length of the shared memory.
- memory-region: Shared memory region to EC. A "shared-dma-pool". See
../reserved-memory/reserved-memory.txt for details.
Example:
{
...
reserved_mem: reserved_mem {
compatible = "shared-dma-pool";
reg = <0 0x52800000 0 0x100000>;
no-map;
};
}
cros-ec@0 {
compatible = "google,cros-ec-spi";
...
cros_ec_codec: ec-codec {
compatible = "google,cros-ec-codec";
#sound-dai-cells = <1>;
reg = <0x0 0x10500000 0x80000>;
memory-region = <&reserved_mem>;
};
};
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/google,cros-ec-codec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Audio codec controlled by ChromeOS EC
maintainers:
- Cheng-Yi Chiang <cychiang@chromium.org>
description: |
Google's ChromeOS EC codec is a digital mic codec provided by the
Embedded Controller (EC) and is controlled via a host-command interface.
An EC codec node should only be found as a sub-node of the EC node (see
Documentation/devicetree/bindings/mfd/cros-ec.txt).
properties:
compatible:
const: google,cros-ec-codec
"#sound-dai-cells":
const: 1
reg:
items:
- description: |
Physical base address and length of shared memory region from EC.
It contains 3 unsigned 32-bit integer. The first 2 integers
combine to become an unsigned 64-bit physical address.
The last one integer is the length of the shared memory.
memory-region:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: |
Shared memory region to EC. A "shared-dma-pool".
See ../reserved-memory/reserved-memory.txt for details.
required:
- compatible
- '#sound-dai-cells'
additionalProperties: false
examples:
- |
reserved_mem: reserved-mem@52800000 {
compatible = "shared-dma-pool";
reg = <0x52800000 0x100000>;
no-map;
};
spi {
#address-cells = <1>;
#size-cells = <0>;
cros-ec@0 {
compatible = "google,cros-ec-spi";
#address-cells = <2>;
#size-cells = <1>;
reg = <0>;
cros_ec_codec: ec-codec@10500000 {
compatible = "google,cros-ec-codec";
#sound-dai-cells = <1>;
reg = <0x0 0x10500000 0x80000>;
memory-region = <&reserved_mem>;
};
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ingenic,aic.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ingenic SoCs AC97 / I2S Controller (AIC) DT bindings
maintainers:
- Paul Cercueil <paul@crapouillou.net>
properties:
$nodename:
pattern: '^audio-controller@'
compatible:
oneOf:
- enum:
- ingenic,jz4740-i2s
- ingenic,jz4760-i2s
- ingenic,jz4770-i2s
- ingenic,jz4780-i2s
- items:
- const: ingenic,jz4725b-i2s
- const: ingenic,jz4740-i2s
'#sound-dai-cells':
const: 0
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: AIC clock
- description: I2S clock
- description: EXT clock
- description: PLL/2 clock
clock-names:
items:
- const: aic
- const: i2s
- const: ext
- const: pll half
dmas:
items:
- description: DMA controller phandle and request line for I2S RX
- description: DMA controller phandle and request line for I2S TX
dma-names:
items:
- const: rx
- const: tx
additionalProperties: false
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- dmas
- dma-names
- '#sound-dai-cells'
examples:
- |
#include <dt-bindings/clock/jz4740-cgu.h>
aic: audio-controller@10020000 {
compatible = "ingenic,jz4740-i2s";
reg = <0x10020000 0x38>;
#sound-dai-cells = <0>;
interrupt-parent = <&intc>;
interrupts = <18>;
clocks = <&cgu JZ4740_CLK_AIC>,
<&cgu JZ4740_CLK_I2S>,
<&cgu JZ4740_CLK_EXT>,
<&cgu JZ4740_CLK_PLL_HALF>;
clock-names = "aic", "i2s", "ext", "pll half";
dmas = <&dmac 25 0xffffffff>, <&dmac 24 0xffffffff>;
dma-names = "rx", "tx";
};
Ingenic JZ4740 I2S controller
Required properties:
- 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"
- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels
- dma-names: Must be "tx" and "rx"
Example:
i2s: i2s@10020000 {
compatible = "ingenic,jz4740-i2s";
reg = <0x10020000 0x94>;
clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>;
clock-names = "aic", "i2s";
dmas = <&dma 2>, <&dma 3>;
dma-names = "tx", "rx";
};
......@@ -18,6 +18,7 @@ Required properties:
* Headphone Jack
* Int Spk
* Mic Jack
* Int Mic
- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
- nvidia,audio-codec : The phandle of the WM8903 audio codec
......
......@@ -10,6 +10,11 @@ Required properties:
- clock-names: should be "pclk".
- spk-depop-time-ms: speak depop time msec.
Optional properties:
- mute-gpios: GPIO specifier for external line driver control (typically the
dedicated GPIO_MUTE pin)
Example for rk3328 internal codec:
codec: codec@ff410000 {
......@@ -18,6 +23,6 @@ codec: codec@ff410000 {
rockchip,grf = <&grf>;
clocks = <&cru PCLK_ACODEC>;
clock-names = "pclk";
mute-gpios = <&grf_gpio 0 GPIO_ACTIVE_LOW>;
spk-depop-time-ms = 100;
status = "disabled";
};
* Rockchip 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 following:
- "rockchip,rk3066-i2s": for rk3066
- "rockchip,px30-i2s", "rockchip,rk3066-i2s": for px30
- "rockchip,rk3036-i2s", "rockchip,rk3066-i2s": for rk3036
- "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188
- "rockchip,rk3228-i2s", "rockchip,rk3066-i2s": for rk3228
- "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288
- "rockchip,rk3328-i2s", "rockchip,rk3066-i2s": for rk3328
- "rockchip,rk3366-i2s", "rockchip,rk3066-i2s": for rk3366
- "rockchip,rk3368-i2s", "rockchip,rk3066-i2s": for rk3368
- "rockchip,rk3399-i2s", "rockchip,rk3066-i2s": for rk3399
- 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 the following:
- "i2s_hclk": clock for I2S BUS
- "i2s_clk" : clock for I2S controller
- 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 {
compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
reg = <0xff890000 0x10000>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&pdma1 0>, <&pdma1 1>;
dma-names = "tx", "rx";
clock-names = "i2s_hclk", "i2s_clk";
clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
rockchip,playback-channels = <8>;
rockchip,capture-channels = <2>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/rockchip-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip I2S controller
description:
The I2S bus (Inter-IC sound bus) is a serial link for digital
audio data transfer between devices in the system.
maintainers:
- Heiko Stuebner <heiko@sntech.de>
properties:
compatible:
oneOf:
- const: rockchip,rk3066-i2s
- items:
- enum:
- rockchip,px30-i2s
- rockchip,rk3036-i2s
- rockchip,rk3188-i2s
- rockchip,rk3228-i2s
- rockchip,rk3288-i2s
- rockchip,rk3328-i2s
- rockchip,rk3366-i2s
- rockchip,rk3368-i2s
- rockchip,rk3399-i2s
- const: rockchip,rk3066-i2s
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: clock for I2S controller
- description: clock for I2S BUS
clock-names:
items:
- const: i2s_clk
- const: i2s_hclk
dmas:
items:
- description: TX DMA Channel
- description: RX DMA Channel
dma-names:
items:
- const: tx
- const: rx
rockchip,capture-channels:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
default: 2
description:
Max capture channels, if not set, 2 channels default.
rockchip,playback-channels:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
default: 8
description:
Max playback channels, if not set, 8 channels default.
rockchip,grf:
$ref: /schemas/types.yaml#/definitions/phandle
description:
The phandle of the syscon node for the GRF register.
Required property for controllers which support multi channel
playback/capture.
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- dmas
- dma-names
- "#sound-dai-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/rk3288-cru.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2s@ff890000 {
compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
reg = <0xff890000 0x10000>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0>;
clock-names = "i2s_clk", "i2s_hclk";
dmas = <&pdma1 0>, <&pdma1 1>;
dma-names = "tx", "rx";
rockchip,capture-channels = <2>;
rockchip,playback-channels = <8>;
#sound-dai-cells = <0>;
};
......@@ -32,6 +32,18 @@ Optional properties:
The delay time is realtek,btndet-delay value multiple of 8.192 ms.
If absent, the default is 16.
- #clock-cells : Should be set to '<1>', wclk and bclk sources provided.
- clock-output-names : Name given for DAI clocks output.
- clocks : phandle and clock specifier for codec MCLK.
- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
- realtek,dmic-clk-rate-hz : Set the clock rate (hz) for the requirement of
the particular DMIC.
- realtek,dmic-delay-ms : Set the delay time (ms) for the requirement of
the particular DMIC.
Pins on the device (for linking into audio routes) for RT5682:
* DMIC L1
......@@ -53,4 +65,10 @@ rt5682 {
realtek,dmic1-clk-pin = <1>;
realtek,jd-src = <1>;
realtek,btndet-delay = <16>;
#clock-cells = <1>;
clock-output-names = "rt5682-dai-wclk", "rt5682-dai-bclk";
clocks = <&osc>;
clock-names = "mclk";
};
STMicroelectronics STM32 SPI/I2S Controller
The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
Only some SPI instances support I2S.
Required properties:
- compatible: Must be "st,stm32h7-i2s"
- reg: Offset and length of the device's register set.
- interrupts: Must contain the interrupt line id.
- clocks: Must contain phandle and clock specifier pairs for each entry
in clock-names.
- clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k".
"i2sclk": clock which feeds the internal clock generator
"pclk": clock which feeds the peripheral bus interface
"x8k": I2S parent clock for sampling rates multiple of 8kHz.
"x11k": I2S parent clock for sampling rates multiple of 11.025kHz.
- dmas: DMA specifiers for tx and rx dma.
See Documentation/devicetree/bindings/dma/stm32-dma.txt.
- dma-names: Identifier for each DMA request line. Must be "tx" and "rx".
- pinctrl-names: should contain only value "default"
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Optional properties:
- resets: Reference to a reset controller asserting the reset controller
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example:
sound_card {
compatible = "audio-graph-card";
dais = <&i2s2_port>;
};
i2s2: audio-controller@40003800 {
compatible = "st,stm32h7-i2s";
reg = <0x40003800 0x400>;
interrupts = <36>;
clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
clock-names = "pclk", "i2sclk", "x8k", "x11k";
dmas = <&dmamux2 2 39 0x400 0x1>,
<&dmamux2 3 40 0x400 0x1>;
dma-names = "rx", "tx";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s2>;
i2s2_port: port@0 {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
format = "i2s";
};
};
};
audio-codec {
codec_port: port@0 {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/st,stm32-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STM32 SPI/I2S Controller
maintainers:
- Olivier Moysan <olivier.moysan@st.com>
description:
The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
Only some SPI instances support I2S.
properties:
compatible:
enum:
- st,stm32h7-i2s
"#sound-dai-cells":
const: 0
reg:
maxItems: 1
clocks:
items:
- description: clock feeding the peripheral bus interface.
- description: clock feeding the internal clock generator.
- description: I2S parent clock for sampling rates multiple of 8kHz.
- description: I2S parent clock for sampling rates multiple of 11.025kHz.
clock-names:
items:
- const: pclk
- const: i2sclk
- const: x8k
- const: x11k
interrupts:
maxItems: 1
dmas:
items:
- description: audio capture DMA.
- description: audio playback DMA.
dma-names:
items:
- const: rx
- const: tx
resets:
maxItems: 1
required:
- compatible
- "#sound-dai-cells"
- reg
- clocks
- clock-names
- interrupts
- dmas
- dma-names
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
i2s2: audio-controller@4000b000 {
compatible = "st,stm32h7-i2s";
#sound-dai-cells = <0>;
reg = <0x4000b000 0x400>;
clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL3_R>;
clock-names = "pclk", "i2sclk", "x8k", "x11k";
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmamux1 39 0x400 0x01>,
<&dmamux1 40 0x400 0x01>;
dma-names = "rx", "tx";
pinctrl-names = "default";
pinctrl-0 = <&i2s2_pins_a>;
};
...
STMicroelectronics STM32 S/PDIF receiver (SPDIFRX).
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
IEC-60958 and IEC-61937.
Required properties:
- compatible: should be "st,stm32h7-spdifrx"
- reg: cpu DAI IP base address and size
- clocks: must contain an entry for kclk (used as S/PDIF signal reference)
- clock-names: must contain "kclk"
- interrupts: cpu DAI interrupt line
- dmas: DMA specifiers for audio data DMA and iec control flow DMA
See STM32 DMA bindings, Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
- dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
Optional properties:
- resets: Reference to a reset controller asserting the SPDIFRX
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example:
spdifrx: spdifrx@40004000 {
compatible = "st,stm32h7-spdifrx";
reg = <0x40004000 0x400>;
clocks = <&rcc SPDIFRX_CK>;
clock-names = "kclk";
interrupts = <97>;
dmas = <&dmamux1 2 93 0x400 0x0>,
<&dmamux1 3 94 0x400 0x0>;
dma-names = "rx", "rx-ctrl";
pinctrl-0 = <&spdifrx_pins>;
pinctrl-names = "default";
spdifrx_port: port {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
};
};
};
spdif_in: spdif-in {
compatible = "linux,spdif-dir";
codec_port: port {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
soundcard {
compatible = "audio-graph-card";
dais = <&spdifrx_port>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/st,stm32-spdifrx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STM32 S/PDIF receiver (SPDIFRX)
maintainers:
- Olivier Moysan <olivier.moysan@st.com>
description: |
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
IEC-60958 and IEC-61937.
properties:
compatible:
enum:
- st,stm32h7-spdifrx
"#sound-dai-cells":
const: 0
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: kclk
interrupts:
maxItems: 1
dmas:
items:
- description: audio data capture DMA
- description: IEC status bits capture DMA
dma-names:
items:
- const: rx
- const: rx-ctrl
resets:
maxItems: 1
required:
- compatible
- "#sound-dai-cells"
- reg
- clocks
- clock-names
- interrupts
- dmas
- dma-names
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
spdifrx: spdifrx@40004000 {
compatible = "st,stm32h7-spdifrx";
#sound-dai-cells = <0>;
reg = <0x40004000 0x400>;
clocks = <&rcc SPDIF_K>;
clock-names = "kclk";
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmamux1 2 93 0x400 0x0>,
<&dmamux1 3 94 0x400 0x0>;
dma-names = "rx", "rx-ctrl";
pinctrl-0 = <&spdifrx_pins>;
pinctrl-names = "default";
};
...
......@@ -8,7 +8,7 @@ real time monitoring of loudspeaker behavior.
Required properties:
- #address-cells - Should be <1>.
- #size-cells - Should be <0>.
- compatible: - Should contain "ti,tas2562".
- compatible: - Should contain "ti,tas2562", "ti,tas2563".
- reg: - The i2c address. Should be 0x4c, 0x4d, 0x4e or 0x4f.
- ti,imon-slot-no:- TDM TX current sense time slot.
......
# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
# Copyright (C) 2019 Texas Instruments Incorporated
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/tlv320adcx140.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TLV320ADCX140 Quad Channel Analog-to-Digital Converter
maintainers:
- Dan Murphy <dmurphy@ti.com>
description: |
The TLV320ADCX140 are multichannel (4-ch analog recording or 8-ch digital
PDM microphones recording), high-performance audio, analog-to-digital
converter (ADC) with analog inputs supporting up to 2V RMS. The TLV320ADCX140
family supports line and microphone Inputs, and offers a programmable
microphone bias or supply voltage generation.
Specifications can be found at:
http://www.ti.com/lit/ds/symlink/tlv320adc3140.pdf
http://www.ti.com/lit/ds/symlink/tlv320adc5140.pdf
http://www.ti.com/lit/ds/symlink/tlv320adc6140.pdf
properties:
compatible:
oneOf:
- const: ti,tlv320adc3140
- const: ti,tlv320adc5140
- const: ti,tlv320adc6140
reg:
maxItems: 1
description: |
I2C addresss of the device can be one of these 0x4c, 0x4d, 0x4e or 0x4f
reset-gpios:
description: |
GPIO used for hardware reset.
areg-supply:
description: |
Regulator with AVDD at 3.3V. If not defined then the internal regulator
is enabled.
ti,mic-bias-source:
description: |
Indicates the source for MIC Bias.
0 - Mic bias is set to VREF
1 - Mic bias is set to VREF × 1.096
6 - Mic bias is set to AVDD
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 6]
ti,vref-source:
description: |
Indicates the source for MIC Bias.
0 - Set VREF to 2.75V
1 - Set VREF to 2.5V
2 - Set VREF to 1.375V
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2]
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
codec: codec@4c {
compatible = "ti,tlv320adc5140";
reg = <0x4c>;
ti,mic-bias-source = <6>;
reset-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
};
};
......@@ -104,5 +104,10 @@ Make sure to name your corresponding cpu and codec playback and capture
dai names ending with "Playback" and "Capture" respectively as dapm core
will link and power those dais based on the name.
Note that in current device tree there is no way to mark a dai_link
as codec to codec. However, it may change in future.
A dai_link in a "simple-audio-card" will automatically be detected as
codec to codec when all DAIs on the link belong to codec components.
The dai_link will be initialized with the subset of stream parameters
(channels, format, sample rate) supported by all DAIs on the link. Since
there is no way to provide these parameters in the device tree, this is
mostly useful for communication with simple fixed-function codecs, such
as a Bluetooth controller or cellular modem.
......@@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/mutex.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
......@@ -169,6 +170,9 @@ struct mtk_hdmi {
bool audio_enable;
bool powered;
bool enabled;
hdmi_codec_plugged_cb plugged_cb;
struct device *codec_dev;
struct mutex update_plugged_status_lock;
};
static inline struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b)
......@@ -1194,13 +1198,26 @@ static void mtk_hdmi_clk_disable_audio(struct mtk_hdmi *hdmi)
clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_AUD_SPDIF]);
}
static enum drm_connector_status
mtk_hdmi_update_plugged_status(struct mtk_hdmi *hdmi)
{
bool connected;
mutex_lock(&hdmi->update_plugged_status_lock);
connected = mtk_cec_hpd_high(hdmi->cec_dev);
if (hdmi->plugged_cb && hdmi->codec_dev)
hdmi->plugged_cb(hdmi->codec_dev, connected);
mutex_unlock(&hdmi->update_plugged_status_lock);
return connected ?
connector_status_connected : connector_status_disconnected;
}
static enum drm_connector_status hdmi_conn_detect(struct drm_connector *conn,
bool force)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
return mtk_cec_hpd_high(hdmi->cec_dev) ?
connector_status_connected : connector_status_disconnected;
return mtk_hdmi_update_plugged_status(hdmi);
}
static void hdmi_conn_destroy(struct drm_connector *conn)
......@@ -1651,20 +1668,39 @@ static int mtk_hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
return 0;
}
static int mtk_hdmi_audio_hook_plugged_cb(struct device *dev, void *data,
hdmi_codec_plugged_cb fn,
struct device *codec_dev)
{
struct mtk_hdmi *hdmi = data;
mutex_lock(&hdmi->update_plugged_status_lock);
hdmi->plugged_cb = fn;
hdmi->codec_dev = codec_dev;
mutex_unlock(&hdmi->update_plugged_status_lock);
mtk_hdmi_update_plugged_status(hdmi);
return 0;
}
static const struct hdmi_codec_ops mtk_hdmi_audio_codec_ops = {
.hw_params = mtk_hdmi_audio_hw_params,
.audio_startup = mtk_hdmi_audio_startup,
.audio_shutdown = mtk_hdmi_audio_shutdown,
.digital_mute = mtk_hdmi_audio_digital_mute,
.get_eld = mtk_hdmi_audio_get_eld,
.hook_plugged_cb = mtk_hdmi_audio_hook_plugged_cb,
};
static void mtk_hdmi_register_audio_driver(struct device *dev)
static int mtk_hdmi_register_audio_driver(struct device *dev)
{
struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
struct hdmi_codec_pdata codec_data = {
.ops = &mtk_hdmi_audio_codec_ops,
.max_i2s_channels = 2,
.i2s = 1,
.data = hdmi,
};
struct platform_device *pdev;
......@@ -1672,9 +1708,10 @@ static void mtk_hdmi_register_audio_driver(struct device *dev)
PLATFORM_DEVID_AUTO, &codec_data,
sizeof(codec_data));
if (IS_ERR(pdev))
return;
return PTR_ERR(pdev);
DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
return 0;
}
static int mtk_drm_hdmi_probe(struct platform_device *pdev)
......@@ -1700,6 +1737,7 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return ret;
}
mutex_init(&hdmi->update_plugged_status_lock);
platform_set_drvdata(pdev, hdmi);
ret = mtk_hdmi_output_init(hdmi);
......@@ -1708,7 +1746,11 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return ret;
}
mtk_hdmi_register_audio_driver(dev);
ret = mtk_hdmi_register_audio_driver(dev);
if (ret) {
dev_err(dev, "Failed to register audio driver: %d\n", ret);
return ret;
}
hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs;
hdmi->bridge.of_node = pdev->dev.of_node;
......
......@@ -594,6 +594,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sdw_stream_runtime *sruntime;
struct snd_soc_dai *codec_dai;
int ret, i;
sruntime = sdw_alloc_stream(dai->name);
......@@ -602,12 +603,12 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
ctrl->sruntime[dai->id] = sruntime;
for (i = 0; i < rtd->num_codecs; i++) {
ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], sruntime,
for_each_rtd_codec_dais(rtd, i, codec_dai) {
ret = snd_soc_dai_set_sdw_stream(codec_dai, sruntime,
substream->stream);
if (ret < 0 && ret != -ENOTSUPP) {
dev_err(dai->dev, "Failed to set sdw stream on %s",
rtd->codec_dais[i]->name);
codec_dai->name);
sdw_release_stream(sruntime);
return ret;
}
......
......@@ -167,6 +167,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
return ret;
}
if (!dpn_prop->read_only_wordlength) {
/* Program DPN_BlockCtrl1 register */
ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1));
if (ret < 0) {
......@@ -175,6 +176,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
t_params->port_num);
return ret;
}
}
/* Program DPN_SampleCtrl1 register */
wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW;
......
......@@ -551,7 +551,7 @@ config SPI_PPC4xx
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on (ARCH_PXA || ARCH_MMP || PCI || ACPI)
depends on ARCH_PXA || ARCH_MMP || PCI || ACPI || COMPILE_TEST
select PXA_SSP if ARCH_PXA || ARCH_MMP
help
This enables using a PXA2xx or Sodaville SSP port as a SPI master
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_MESON_AIU_H
#define __DT_MESON_AIU_H
#define AIU_CPU 0
#define AIU_HDMI 1
#define AIU_ACODEC 2
#define CPU_I2S_FIFO 0
#define CPU_SPDIF_FIFO 1
#define CPU_I2S_ENCODER 2
#define CPU_SPDIF_ENCODER 3
#define CTRL_I2S 0
#define CTRL_PCM 1
#define CTRL_OUT 2
#endif /* __DT_MESON_AIU_H */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_MESON_G12A_TOACODEC_H
#define __DT_MESON_G12A_TOACODEC_H
#define TOACODEC_IN_A 0
#define TOACODEC_IN_B 1
#define TOACODEC_IN_C 2
#define TOACODEC_OUT 3
#endif /* __DT_MESON_G12A_TOACODEC_H */
......@@ -284,6 +284,7 @@ struct sdw_dpn_audio_mode {
* @max_async_buffer: Number of samples that this port can buffer in
* asynchronous modes
* @block_pack_mode: Type of block port mode supported
* @read_only_wordlength: Read Only wordlength field in DPN_BlockCtrl1 register
* @port_encoding: Payload Channel Sample encoding schemes supported
* @audio_modes: Audio modes supported
*/
......@@ -307,6 +308,7 @@ struct sdw_dpn_prop {
u32 modes;
u32 max_async_buffer;
bool block_pack_mode;
bool read_only_wordlength;
u32 port_encoding;
struct sdw_dpn_audio_mode *audio_modes;
};
......
......@@ -23,7 +23,6 @@ struct snd_compr_ops;
* struct snd_compr_runtime: runtime stream description
* @state: stream state
* @ops: pointer to DSP callbacks
* @dma_buffer_p: runtime dma buffer pointer
* @buffer: pointer to kernel buffer, valid only when not in mmap mode or
* DSP doesn't implement copy
* @buffer_size: size of the above buffer
......@@ -34,11 +33,14 @@ struct snd_compr_ops;
* @total_bytes_transferred: cumulative bytes transferred by offload DSP
* @sleep: poll sleep
* @private_data: driver private data pointer
* @dma_area: virtual buffer address
* @dma_addr: physical buffer address (not accessible from main CPU)
* @dma_bytes: size of DMA area
* @dma_buffer_p: runtime dma buffer pointer
*/
struct snd_compr_runtime {
snd_pcm_state_t state;
struct snd_compr_ops *ops;
struct snd_dma_buffer *dma_buffer_p;
void *buffer;
u64 buffer_size;
u32 fragment_size;
......@@ -47,6 +49,11 @@ struct snd_compr_runtime {
u64 total_bytes_transferred;
wait_queue_head_t sleep;
void *private_data;
unsigned char *dma_area;
dma_addr_t dma_addr;
size_t dma_bytes;
struct snd_dma_buffer *dma_buffer_p;
};
/**
......@@ -60,6 +67,7 @@ struct snd_compr_runtime {
* @metadata_set: metadata set flag, true when set
* @next_track: has userspace signal next track transition, true when set
* @private_data: pointer to DSP private data
* @dma_buffer: allocated buffer if any
*/
struct snd_compr_stream {
const char *name;
......@@ -71,6 +79,7 @@ struct snd_compr_stream {
bool metadata_set;
bool next_track;
void *private_data;
struct snd_dma_buffer dma_buffer;
};
/**
......@@ -180,21 +189,34 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
/**
* snd_compr_set_runtime_buffer - Set the Compress runtime buffer
* @substream: compress substream to set
* @stream: compress stream to set
* @bufp: the buffer information, NULL to clear
*
* Copy the buffer information to runtime buffer when @bufp is non-NULL.
* Otherwise it clears the current buffer information.
*/
static inline void snd_compr_set_runtime_buffer(
struct snd_compr_stream *substream,
static inline void
snd_compr_set_runtime_buffer(struct snd_compr_stream *stream,
struct snd_dma_buffer *bufp)
{
struct snd_compr_runtime *runtime = substream->runtime;
struct snd_compr_runtime *runtime = stream->runtime;
if (bufp) {
runtime->dma_buffer_p = bufp;
runtime->dma_area = bufp->area;
runtime->dma_addr = bufp->addr;
runtime->dma_bytes = bufp->bytes;
} else {
runtime->dma_buffer_p = NULL;
runtime->dma_area = NULL;
runtime->dma_addr = 0;
runtime->dma_bytes = 0;
}
}
int snd_compr_malloc_pages(struct snd_compr_stream *stream, size_t size);
int snd_compr_free_pages(struct snd_compr_stream *stream);
int snd_compr_stop_error(struct snd_compr_stream *stream,
snd_pcm_state_t state);
......
......@@ -513,6 +513,7 @@ struct hdac_stream {
struct snd_pcm_substream *substream; /* assigned substream,
* set in PCM open
*/
struct snd_compr_stream *cstream;
unsigned int format_val; /* format value to be set in the
* controller and the codec
*/
......@@ -527,6 +528,7 @@ struct hdac_stream {
bool locked:1;
bool stripe:1; /* apply stripe control */
u64 curr_pos;
/* timestamp */
unsigned long start_wallclk; /* start + minimum wallclk */
unsigned long period_wallclk; /* wallclk for period */
......
......@@ -644,6 +644,11 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
#define snd_pcm_group_for_each_entry(s, substream) \
list_for_each_entry(s, &substream->group->substreams, link_list)
#define for_each_pcm_streams(stream) \
for (stream = SNDRV_PCM_STREAM_PLAYBACK; \
stream <= SNDRV_PCM_STREAM_LAST; \
stream++)
/**
* snd_pcm_running - Check whether the substream is in a running state
* @substream: substream to check
......@@ -1122,7 +1127,14 @@ snd_pcm_kernel_readv(struct snd_pcm_substream *substream,
return __snd_pcm_lib_xfer(substream, bufs, false, frames, true);
}
int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime);
int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw);
static inline int
snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
{
return snd_pcm_hw_limit_rates(&runtime->hw);
}
unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate);
unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit);
unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
......
......@@ -24,6 +24,12 @@ enum rt5682_jd_src {
RT5682_JD1,
};
enum rt5682_dai_clks {
RT5682_DAI_WCLK_IDX,
RT5682_DAI_BCLK_IDX,
RT5682_DAI_NUM_CLKS,
};
struct rt5682_platform_data {
int ldo1_en; /* GPIO for LDO1_EN */
......@@ -32,6 +38,10 @@ struct rt5682_platform_data {
enum rt5682_dmic1_clk_pin dmic1_clk_pin;
enum rt5682_jd_src jd_src;
unsigned int btndet_delay;
unsigned int dmic_clk_rate;
unsigned int dmic_delay;
const char *dai_clk_names[RT5682_DAI_NUM_CLKS];
};
#endif
......
......@@ -75,18 +75,45 @@ struct snd_soc_acpi_mach_params {
};
/**
* snd_soc_acpi_link_adr: ACPI-based list of _ADR, with a variable
* number of devices per link
*
* snd_soc_acpi_endpoint - endpoint descriptor
* @num: endpoint number (mandatory, unique per device)
* @aggregated: 0 (independent) or 1 (logically grouped)
* @group_position: zero-based order (only when @aggregated is 1)
* @group_id: platform-unique group identifier (only when @aggregrated is 1)
*/
struct snd_soc_acpi_endpoint {
u8 num;
u8 aggregated;
u8 group_position;
u8 group_id;
};
/**
* snd_soc_acpi_adr_device - descriptor for _ADR-enumerated device
* @adr: 64 bit ACPI _ADR value
* @num_endpoints: number of endpoints for this device
* @endpoints: array of endpoints
*/
struct snd_soc_acpi_adr_device {
const u64 adr;
const u8 num_endpoints;
const struct snd_soc_acpi_endpoint *endpoints;
};
/**
* snd_soc_acpi_link_adr - ACPI-based list of _ADR enumerated devices
* @mask: one bit set indicates the link this list applies to
* @num_adr: ARRAY_SIZE of adr
* @adr: array of _ADR (represented as u64).
* @num_adr: ARRAY_SIZE of devices
* @adr_d: array of devices
*
* The number of devices per link can be more than 1, e.g. in SoundWire
* multi-drop configurations.
*/
struct snd_soc_acpi_link_adr {
const u32 mask;
const u32 num_adr;
const u64 *adr;
const struct snd_soc_acpi_adr_device *adr_d;
};
/**
......
......@@ -202,6 +202,8 @@ struct snd_soc_dai_ops {
int (*set_sdw_stream)(struct snd_soc_dai *dai,
void *stream, int direction);
void *(*get_sdw_stream)(struct snd_soc_dai *dai, int direction);
/*
* DAI digital mute - optional.
* Called by soc-core to minimise any pops.
......@@ -322,9 +324,7 @@ struct snd_soc_dai {
struct snd_soc_dai_driver *driver;
/* DAI runtime info */
unsigned int capture_active; /* stream usage count */
unsigned int playback_active; /* stream usage count */
unsigned int probed:1;
unsigned int stream_active[SNDRV_PCM_STREAM_LAST + 1]; /* usage count */
unsigned int active;
......@@ -348,8 +348,27 @@ struct snd_soc_dai {
unsigned int rx_mask;
struct list_head list;
/* bit field */
unsigned int probed:1;
unsigned int started:1;
};
static inline struct snd_soc_pcm_stream *
snd_soc_dai_get_pcm_stream(const struct snd_soc_dai *dai, int stream)
{
return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
&dai->driver->playback : &dai->driver->capture;
}
static inline
struct snd_soc_dapm_widget *snd_soc_dai_get_widget(
struct snd_soc_dai *dai, int stream)
{
return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
dai->playback_widget : dai->capture_widget;
}
static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
const struct snd_pcm_substream *ss)
{
......@@ -406,4 +425,23 @@ static inline int snd_soc_dai_set_sdw_stream(struct snd_soc_dai *dai,
return -ENOTSUPP;
}
/**
* snd_soc_dai_get_sdw_stream() - Retrieves SDW stream from DAI
* @dai: DAI
* @direction: Stream direction(Playback/Capture)
*
* This routine only retrieves that was previously configured
* with snd_soc_dai_get_sdw_stream()
*
* Returns pointer to stream or -ENOTSUPP if callback is not supported;
*/
static inline void *snd_soc_dai_get_sdw_stream(struct snd_soc_dai *dai,
int direction)
{
if (dai->driver->ops->get_sdw_stream)
return dai->driver->ops->get_sdw_stream(dai, direction);
else
return ERR_PTR(-ENOTSUPP);
}
#endif
......@@ -482,6 +482,7 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
struct snd_soc_dapm_widget_list **list,
bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
enum snd_soc_dapm_direction));
void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list);
struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
struct snd_kcontrol *kcontrol);
......@@ -691,6 +692,11 @@ struct snd_soc_dapm_widget_list {
struct snd_soc_dapm_widget *widgets[0];
};
#define for_each_dapm_widgets(list, i, widget) \
for ((i) = 0; \
(i) < list->num_widgets && (widget = list->widgets[i]); \
(i)++)
struct snd_soc_dapm_stats {
int power_checks;
int path_checks;
......
......@@ -132,17 +132,8 @@ int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
struct snd_pcm_substream *
snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);
/* get the BE runtime state */
enum snd_soc_dpcm_state
snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream);
/* set the BE runtime state */
void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
enum snd_soc_dpcm_state state);
/* internal use only */
int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
int soc_dpcm_runtime_update(struct snd_soc_card *);
/* update audio routing between PCMs and any DAI links */
int snd_soc_dpcm_runtime_update(struct snd_soc_card *card);
#ifdef CONFIG_DEBUG_FS
void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
......@@ -154,6 +145,7 @@ static inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list_);
void dpcm_path_put(struct snd_soc_dapm_widget_list **list);
int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list, int new);
int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);
......@@ -167,10 +159,4 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
int event);
static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
{
kfree(*list);
}
#endif
......@@ -471,6 +471,9 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hardware *hw, int stream);
int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
unsigned int dai_fmt);
......@@ -855,6 +858,11 @@ struct snd_soc_dai_link {
((platform) = &link->platforms[i]); \
(i)++)
#define for_each_link_cpus(link, i, cpu) \
for ((i) = 0; \
((i) < link->num_cpus) && ((cpu) = &link->cpus[i]); \
(i)++)
/*
* Sample 1 : Single CPU/Codec/Platform
*
......@@ -1110,6 +1118,14 @@ struct snd_soc_card {
#define for_each_card_components(card, component) \
list_for_each_entry(component, &(card)->component_dev_list, card_list)
#define for_each_card_dapms(card, dapm) \
list_for_each_entry(dapm, &card->dapm_list, list)
#define for_each_card_widgets(card, w)\
list_for_each_entry(w, &card->widgets, list)
#define for_each_card_widgets_safe(card, w, _w) \
list_for_each_entry_safe(w, _w, &card->widgets, list)
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
struct snd_soc_pcm_runtime {
struct device *dev;
......@@ -1129,10 +1145,14 @@ struct snd_soc_pcm_runtime {
struct snd_compr *compr;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
struct snd_soc_dai **dais;
struct snd_soc_dai **codec_dais;
unsigned int num_codecs;
struct snd_soc_dai **cpu_dais;
unsigned int num_cpus;
struct delayed_work delayed_work;
void (*close_delayed_work_func)(struct snd_soc_pcm_runtime *rtd);
#ifdef CONFIG_DEBUG_FS
......@@ -1149,16 +1169,31 @@ struct snd_soc_pcm_runtime {
int num_components;
struct snd_soc_component *components[0]; /* CPU/Codec/Platform */
};
/* see soc_new_pcm_runtime() */
#define asoc_rtd_to_cpu(rtd, n) (rtd)->dais[n]
#define asoc_rtd_to_codec(rtd, n) (rtd)->dais[n + (rtd)->num_cpus]
#define for_each_rtd_components(rtd, i, component) \
for ((i) = 0; \
((i) < rtd->num_components) && ((component) = rtd->components[i]);\
(i)++)
#define for_each_rtd_codec_dai(rtd, i, dai)\
#define for_each_rtd_cpu_dais(rtd, i, dai) \
for ((i) = 0; \
((i) < rtd->num_cpus) && ((dai) = rtd->cpu_dais[i]); \
(i)++)
#define for_each_rtd_cpu_dais_rollback(rtd, i, dai) \
for (; (--(i) >= 0) && ((dai) = rtd->cpu_dais[i]);)
#define for_each_rtd_codec_dais(rtd, i, dai) \
for ((i) = 0; \
((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
(i)++)
#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \
#define for_each_rtd_codec_dais_rollback(rtd, i, dai) \
for (; (--(i) >= 0) && ((dai) = rtd->codec_dais[i]);)
#define for_each_rtd_dais(rtd, i, dai) \
for ((i) = 0; \
((i) < (rtd)->num_cpus + (rtd)->num_codecs) && \
((dai) = (rtd)->dais[i]); \
(i)++)
void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
......
......@@ -87,6 +87,15 @@ struct sof_ipc_dai_hda_params {
uint32_t link_dma_ch;
} __packed;
/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */
struct sof_ipc_dai_alh_params {
struct sof_ipc_hdr hdr;
uint32_t stream_id;
/* reserved for future use */
uint32_t reserved[15];
} __packed;
/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */
/* This struct is defined per 2ch PDM controller available in the platform.
......@@ -179,13 +188,4 @@ struct sof_ipc_dai_dmic_params {
struct sof_ipc_dai_dmic_pdm_ctrl pdm[0];
} __packed;
/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */
struct sof_ipc_dai_alh_params {
struct sof_ipc_hdr hdr;
uint32_t stream_id;
/* reserved for future use */
uint32_t reserved[15];
} __packed;
#endif
......@@ -51,6 +51,7 @@
#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U)
#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU)
#define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU)
#define SOF_IPC_GLB_PROBE SOF_GLB_TYPE(0xCU)
/*
* DSP Command Message Types
......@@ -102,6 +103,16 @@
#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010)
#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011)
/* probe */
#define SOF_IPC_PROBE_INIT SOF_CMD_TYPE(0x001)
#define SOF_IPC_PROBE_DEINIT SOF_CMD_TYPE(0x002)
#define SOF_IPC_PROBE_DMA_ADD SOF_CMD_TYPE(0x003)
#define SOF_IPC_PROBE_DMA_INFO SOF_CMD_TYPE(0x004)
#define SOF_IPC_PROBE_DMA_REMOVE SOF_CMD_TYPE(0x005)
#define SOF_IPC_PROBE_POINT_ADD SOF_CMD_TYPE(0x006)
#define SOF_IPC_PROBE_POINT_INFO SOF_CMD_TYPE(0x007)
#define SOF_IPC_PROBE_POINT_REMOVE SOF_CMD_TYPE(0x008)
/* trace */
#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001)
#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002)
......
......@@ -28,9 +28,9 @@
/* extended data types that can be appended onto end of sof_ipc_fw_ready */
enum sof_ipc_ext_data {
SOF_IPC_EXT_DMA_BUFFER = 0,
SOF_IPC_EXT_WINDOW,
SOF_IPC_EXT_CC_INFO,
SOF_IPC_EXT_UNUSED = 0,
SOF_IPC_EXT_WINDOW = 1,
SOF_IPC_EXT_CC_INFO = 2,
};
/* FW version - SOF_IPC_GLB_VERSION */
......@@ -83,22 +83,6 @@ struct sof_ipc_ext_data_hdr {
uint32_t type; /**< SOF_IPC_EXT_ */
} __packed;
struct sof_ipc_dma_buffer_elem {
struct sof_ipc_hdr hdr;
uint32_t type; /**< SOF_IPC_REGION_ */
uint32_t id; /**< platform specific - used to map to host memory */
struct sof_ipc_host_buffer buffer;
} __packed;
/* extended data DMA buffers for IPC, trace and debug */
struct sof_ipc_dma_buffer_data {
struct sof_ipc_ext_data_hdr ext_hdr;
uint32_t num_buffers;
/* host files in buffer[n].buffer */
struct sof_ipc_dma_buffer_elem buffer[];
} __packed;
struct sof_ipc_window_elem {
struct sof_ipc_hdr hdr;
uint32_t type; /**< SOF_IPC_REGION_ */
......
......@@ -53,9 +53,10 @@ struct sof_ipc_comp {
uint32_t id;
enum sof_comp_type type;
uint32_t pipeline_id;
uint32_t core;
/* reserved for future use */
uint32_t reserved[2];
uint32_t reserved[1];
} __packed;
/*
......
......@@ -31,7 +31,7 @@
#include <sound/compress_params.h>
#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 2)
#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 2, 0)
/**
* struct snd_compressed_buffer - compressed buffer
* @fragment_size: size of buffer fragment in bytes
......
......@@ -75,7 +75,9 @@
#define SND_AUDIOCODEC_G723_1 ((__u32) 0x0000000C)
#define SND_AUDIOCODEC_G729 ((__u32) 0x0000000D)
#define SND_AUDIOCODEC_BESPOKE ((__u32) 0x0000000E)
#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_BESPOKE
#define SND_AUDIOCODEC_ALAC ((__u32) 0x0000000F)
#define SND_AUDIOCODEC_APE ((__u32) 0x00000010)
#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_APE
/*
* Profile and modes are listed with bit masks. This allows for a
......@@ -142,6 +144,9 @@
#define SND_AUDIOPROFILE_WMA8 ((__u32) 0x00000002)
#define SND_AUDIOPROFILE_WMA9 ((__u32) 0x00000004)
#define SND_AUDIOPROFILE_WMA10 ((__u32) 0x00000008)
#define SND_AUDIOPROFILE_WMA9_PRO ((__u32) 0x00000010)
#define SND_AUDIOPROFILE_WMA9_LOSSLESS ((__u32) 0x00000020)
#define SND_AUDIOPROFILE_WMA10_LOSSLESS ((__u32) 0x00000040)
#define SND_AUDIOMODE_WMA_LEVEL1 ((__u32) 0x00000001)
#define SND_AUDIOMODE_WMA_LEVEL2 ((__u32) 0x00000002)
......@@ -326,6 +331,33 @@ struct snd_dec_flac {
__u16 reserved;
} __attribute__((packed, aligned(4)));
struct snd_dec_wma {
__u32 encoder_option;
__u32 adv_encoder_option;
__u32 adv_encoder_option2;
__u32 reserved;
} __attribute__((packed, aligned(4)));
struct snd_dec_alac {
__u32 frame_length;
__u8 compatible_version;
__u8 pb;
__u8 mb;
__u8 kb;
__u32 max_run;
__u32 max_frame_bytes;
} __attribute__((packed, aligned(4)));
struct snd_dec_ape {
__u16 compatible_version;
__u16 compression_level;
__u32 format_flags;
__u32 blocks_per_frame;
__u32 final_frame_blocks;
__u32 total_frames;
__u32 seek_table_present;
} __attribute__((packed, aligned(4)));
union snd_codec_options {
struct snd_enc_wma wma;
struct snd_enc_vorbis vorbis;
......@@ -333,6 +365,9 @@ union snd_codec_options {
struct snd_enc_flac flac;
struct snd_enc_generic generic;
struct snd_dec_flac flac_d;
struct snd_dec_wma wma_d;
struct snd_dec_alac alac_d;
struct snd_dec_ape ape_d;
} __attribute__((packed, aligned(4)));
/** struct snd_codec_desc - description of codec capabilities
......
......@@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 12
#define SOF_ABI_MINOR 13
#define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
......
......@@ -38,7 +38,7 @@ int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct dma_slave_config config;
int ret;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
if (!dma_params)
return 0;
......@@ -47,7 +47,7 @@ int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
snd_dmaengine_pcm_set_config_from_dai_data(substream,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream),
&config);
ret = dmaengine_slave_config(chan, &config);
......@@ -95,7 +95,7 @@ int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
runtime->hw = pxa2xx_pcm_hardware;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
if (!dma_params)
return 0;
......@@ -120,7 +120,7 @@ int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
return ret;
return snd_dmaengine_pcm_open(
substream, dma_request_slave_channel(rtd->cpu_dai->dev,
substream, dma_request_slave_channel(asoc_rtd_to_cpu(rtd, 0)->dev,
dma_params->chan_name));
}
EXPORT_SYMBOL(pxa2xx_pcm_open);
......
......@@ -488,6 +488,48 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
}
#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
int snd_compr_malloc_pages(struct snd_compr_stream *stream, size_t size)
{
struct snd_dma_buffer *dmab;
int ret;
if (snd_BUG_ON(!(stream) || !(stream)->runtime))
return -EINVAL;
dmab = kzalloc(sizeof(*dmab), GFP_KERNEL);
if (!dmab)
return -ENOMEM;
dmab->dev = stream->dma_buffer.dev;
ret = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, size, dmab);
if (ret < 0) {
kfree(dmab);
return ret;
}
snd_compr_set_runtime_buffer(stream, dmab);
stream->runtime->dma_bytes = size;
return 1;
}
EXPORT_SYMBOL(snd_compr_malloc_pages);
int snd_compr_free_pages(struct snd_compr_stream *stream)
{
struct snd_compr_runtime *runtime = stream->runtime;
if (snd_BUG_ON(!(stream) || !(stream)->runtime))
return -EINVAL;
if (runtime->dma_area == NULL)
return 0;
if (runtime->dma_buffer_p != &stream->dma_buffer) {
/* It's a newly allocated buffer. Release it now. */
snd_dma_free_pages(runtime->dma_buffer_p);
kfree(runtime->dma_buffer_p);
}
snd_compr_set_runtime_buffer(stream, NULL);
return 0;
}
EXPORT_SYMBOL(snd_compr_free_pages);
/* revisit this with snd_pcm_preallocate_xxx */
static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
struct snd_compr_params *params)
......
......@@ -240,6 +240,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue);
snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct dma_tx_state state;
enum dma_status status;
unsigned int buf_size;
......@@ -250,9 +251,12 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
buf_size = snd_pcm_lib_buffer_bytes(substream);
if (state.residue > 0 && state.residue <= buf_size)
pos = buf_size - state.residue;
runtime->delay = bytes_to_frames(runtime,
state.in_flight_bytes);
}
return bytes_to_frames(substream->runtime, pos);
return bytes_to_frames(runtime, pos);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
......
......@@ -474,32 +474,32 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
EXPORT_SYMBOL(snd_pcm_format_set_silence);
/**
* snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
* @runtime: the runtime instance
* snd_pcm_hw_limit_rates - determine rate_min/rate_max fields
* @hw: the pcm hw instance
*
* Determines the rate_min and rate_max fields from the rates bits of
* the given runtime->hw.
* the given hw.
*
* Return: Zero if successful.
*/
int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw)
{
int i;
for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
if (runtime->hw.rates & (1 << i)) {
runtime->hw.rate_min = snd_pcm_known_rates.list[i];
if (hw->rates & (1 << i)) {
hw->rate_min = snd_pcm_known_rates.list[i];
break;
}
}
for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
if (runtime->hw.rates & (1 << i)) {
runtime->hw.rate_max = snd_pcm_known_rates.list[i];
if (hw->rates & (1 << i)) {
hw->rate_max = snd_pcm_known_rates.list[i];
break;
}
}
return 0;
}
EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
EXPORT_SYMBOL(snd_pcm_hw_limit_rates);
/**
* snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
......
......@@ -26,3 +26,13 @@ config SND_SOC_AMD_ACP3x
depends on X86 && PCI
help
This option enables ACP v3.x I2S support on AMD platform
config SND_SOC_AMD_RV_RT5682_MACH
tristate "AMD RV support for RT5682"
select SND_SOC_RT5682
select SND_SOC_MAX98357A
select SND_SOC_CROS_EC_CODEC
select I2C_CROS_EC_TUNNEL
depends on SND_SOC_AMD_ACP3x && I2C && CROS_EC
help
This option enables machine driver for RT5682 and MAX9835.
......@@ -2,8 +2,10 @@
acp_audio_dma-objs := acp-pcm-dma.o
snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/
obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o
......@@ -54,7 +54,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
......
......@@ -48,7 +48,7 @@ static int cz_aif1_hw_params(struct snd_pcm_substream *substream,
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
CZ_PLAT_CLK, params_rate(params) * 512);
......@@ -73,7 +73,7 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_card *card;
struct snd_soc_component *codec;
codec = rtd->codec_dai->component;
codec = asoc_rtd_to_codec(rtd, 0)->component;
card = rtd->card;
ret = snd_soc_card_jack_new(card, "Headset Jack",
......
This diff is collapsed.
......@@ -42,7 +42,7 @@ static int acp3x_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai,
u32 tx_mask, u32 rx_mask, int slots, int slot_width)
{
struct i2s_dev_data *adata;
u32 val, reg_val, frmt_reg, frm_len;
u32 frm_len;
u16 slot_len;
adata = snd_soc_dai_get_drvdata(cpu_dai);
......@@ -64,36 +64,7 @@ static int acp3x_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
/* Enable I2S/BT channels TDM, respective TX/RX frame lengths.*/
frm_len = FRM_LEN | (slots << 15) | (slot_len << 18);
if (adata->substream_type == SNDRV_PCM_STREAM_PLAYBACK) {
switch (adata->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_ITER;
frmt_reg = mmACP_BTTDM_TXFRMT;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_ITER;
frmt_reg = mmACP_I2STDM_TXFRMT;
}
} else {
switch (adata->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_IRER;
frmt_reg = mmACP_BTTDM_RXFRMT;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_IRER;
frmt_reg = mmACP_I2STDM_RXFRMT;
}
}
val = rv_readl(adata->acp3x_base + reg_val);
rv_writel(val | 0x2, adata->acp3x_base + reg_val);
rv_writel(frm_len, adata->acp3x_base + frmt_reg);
adata->tdm_fmt = frm_len;
return 0;
}
......@@ -105,12 +76,14 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *prtd;
struct snd_soc_card *card;
struct acp3x_platform_info *pinfo;
struct i2s_dev_data *adata;
u32 val;
u32 reg_val;
u32 reg_val, frmt_reg;
prtd = substream->private_data;
rtd = substream->runtime->private_data;
card = prtd->card;
adata = snd_soc_dai_get_drvdata(dai);
pinfo = snd_soc_card_get_drvdata(card);
if (pinfo) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
......@@ -141,20 +114,29 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_ITER;
frmt_reg = mmACP_BTTDM_TXFRMT;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_ITER;
frmt_reg = mmACP_I2STDM_TXFRMT;
}
} else {
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_IRER;
frmt_reg = mmACP_BTTDM_RXFRMT;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_IRER;
frmt_reg = mmACP_I2STDM_RXFRMT;
}
}
if (adata->tdm_mode) {
val = rv_readl(rtd->acp3x_base + reg_val);
rv_writel(val | 0x2, rtd->acp3x_base + reg_val);
rv_writel(adata->tdm_fmt, rtd->acp3x_base + frmt_reg);
}
val = rv_readl(rtd->acp3x_base + reg_val);
val = val | (rtd->xfer_resolution << 3);
......
......@@ -458,7 +458,8 @@ static int acp3x_resume(struct device *dev)
reg_val = mmACP_I2STDM_ITER;
frmt_val = mmACP_I2STDM_TXFRMT;
}
rv_writel((rtd->xfer_resolution << 3), rtd->acp3x_base + reg_val);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + reg_val);
}
if (adata->capture_stream && adata->capture_stream->runtime) {
struct i2s_stream_instance *rtd =
......@@ -474,7 +475,8 @@ static int acp3x_resume(struct device *dev)
reg_val = mmACP_I2STDM_IRER;
frmt_val = mmACP_I2STDM_RXFRMT;
}
rv_writel((rtd->xfer_resolution << 3), rtd->acp3x_base + reg_val);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + reg_val);
}
if (adata->tdm_mode == TDM_ENABLE) {
rv_writel(adata->tdm_fmt, adata->acp3x_base + frmt_val);
......
......@@ -38,8 +38,13 @@ static int acp3x_power_on(void __iomem *acp3x_base)
timeout = 0;
while (++timeout < 500) {
val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
if (!val)
if (!val) {
/* Set PME_EN as after ACP power On,
* PME_EN gets cleared
*/
rv_writel(0x1, acp3x_base + mmACP_PME_EN);
return 0;
}
udelay(1);
}
return -ETIMEDOUT;
......
......@@ -56,7 +56,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct atmel_pcm_dma_params *prtd;
prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
prtd = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
if (ssc_sr & prtd->mask->ssc_error) {
if (snd_pcm_running(substream))
......@@ -83,7 +83,7 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
struct ssc_device *ssc;
int ret;
prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
prtd = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
ssc = prtd->ssc;
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
......
......@@ -213,7 +213,7 @@ static int atmel_pcm_hw_params(struct snd_soc_component *component,
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
prtd->params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
prtd->dma_buffer = runtime->dma_addr;
......
......@@ -27,7 +27,7 @@ static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK,
......
......@@ -239,10 +239,10 @@ struct mchp_i2s_mcc_dev {
unsigned int frame_length;
int tdm_slots;
int channels;
int gclk_use:1;
int gclk_running:1;
int tx_rdy:1;
int rx_rdy:1;
unsigned int gclk_use:1;
unsigned int gclk_running:1;
unsigned int tx_rdy:1;
unsigned int rx_rdy:1;
};
static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
......
......@@ -21,7 +21,7 @@
static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
/* Set proto sysclk */
int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
......
......@@ -96,7 +96,7 @@ static const struct snd_soc_dapm_route intercon[] = {
*/
static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct device *dev = rtd->dev;
int ret;
......
......@@ -40,7 +40,7 @@ struct sam9x5_drvdata {
*/
static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct device *dev = rtd->dev;
int ret;
......
......@@ -95,7 +95,7 @@ static struct snd_soc_card db1550_ac97_machine = {
static int db1200_i2s_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
/* WM8731 has its own 12MHz crystal */
snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
......
......@@ -281,7 +281,7 @@ static int au1xpsc_pcm_open(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int stype = substream->stream, *dmaids;
dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
dmaids = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
if (!dmaids)
return -ENODEV; /* whoa, has ordering changed? */
......
......@@ -195,7 +195,7 @@ static int alchemy_pcm_open(struct snd_soc_component *component,
int *dmaids, s = substream->stream;
char *name;
dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
dmaids = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
if (!dmaids)
return -ENODEV; /* whoa, has ordering changed? */
......
......@@ -58,7 +58,7 @@ static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
{
struct snd_soc_card *c = x->bus->card->private_data;
return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
return snd_soc_dai_get_drvdata(c->asoc_rtd_to_cpu(rtd, 0));
}
#else
......
......@@ -17,3 +17,12 @@ config SND_SOC_CYGNUS
Cygnus chips (bcm958300, bcm958305, bcm911360)
If you don't know what to do here, say N.
config SND_BCM63XX_I2S_WHISTLER
tristate "SoC Audio support for the Broadcom BCM63XX I2S module"
select REGMAP_MMIO
help
Say Y if you want to add support for ASoC audio on Broadcom
DSL/PON chips (bcm63158, bcm63178)
If you don't know what to do here, say N
......@@ -9,3 +9,7 @@ snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o
obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o
# BCM63XX Platform Support
snd-soc-63xx-objs := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o
obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
\ No newline at end of file
// SPDX-License-Identifier: GPL-2.0-or-later
// linux/sound/bcm/bcm63xx-i2s-whistler.c
// BCM63xx whistler i2s driver
// Copyright (c) 2020 Broadcom Corporation
// Author: Kevin-Ke Li <kevin-ke.li@broadcom.com>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "bcm63xx-i2s.h"
#define DRV_NAME "brcm-i2s"
static bool brcm_i2s_wr_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case I2S_TX_CFG ... I2S_TX_DESC_IFF_LEN:
case I2S_TX_CFG_2 ... I2S_RX_DESC_IFF_LEN:
case I2S_RX_CFG_2 ... I2S_REG_MAX:
return true;
default:
return false;
}
}
static bool brcm_i2s_rd_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case I2S_TX_CFG ... I2S_REG_MAX:
return true;
default:
return false;
}
}
static bool brcm_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case I2S_TX_CFG:
case I2S_TX_IRQ_CTL:
case I2S_TX_DESC_IFF_ADDR:
case I2S_TX_DESC_IFF_LEN:
case I2S_TX_DESC_OFF_ADDR:
case I2S_TX_DESC_OFF_LEN:
case I2S_TX_CFG_2:
case I2S_RX_CFG:
case I2S_RX_IRQ_CTL:
case I2S_RX_DESC_OFF_ADDR:
case I2S_RX_DESC_OFF_LEN:
case I2S_RX_DESC_IFF_LEN:
case I2S_RX_DESC_IFF_ADDR:
case I2S_RX_CFG_2:
return true;
default:
return false;
}
}
static const struct regmap_config brcm_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = I2S_REG_MAX,
.writeable_reg = brcm_i2s_wr_reg,
.readable_reg = brcm_i2s_rd_reg,
.volatile_reg = brcm_i2s_volatile_reg,
.cache_type = REGCACHE_FLAT,
};
static int bcm63xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
int ret = 0;
struct bcm_i2s_priv *i2s_priv = snd_soc_dai_get_drvdata(dai);
ret = clk_set_rate(i2s_priv->i2s_clk, params_rate(params));
if (ret < 0)
dev_err(i2s_priv->dev,
"Can't set sample rate, err: %d\n", ret);
return ret;
}
static int bcm63xx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
unsigned int slavemode;
struct bcm_i2s_priv *i2s_priv = snd_soc_dai_get_drvdata(dai);
struct regmap *regmap_i2s = i2s_priv->regmap_i2s;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
regmap_update_bits(regmap_i2s, I2S_TX_CFG,
I2S_TX_OUT_R | I2S_TX_DATA_ALIGNMENT |
I2S_TX_DATA_ENABLE | I2S_TX_CLOCK_ENABLE,
I2S_TX_OUT_R | I2S_TX_DATA_ALIGNMENT |
I2S_TX_DATA_ENABLE | I2S_TX_CLOCK_ENABLE);
regmap_write(regmap_i2s, I2S_TX_IRQ_CTL, 0);
regmap_write(regmap_i2s, I2S_TX_IRQ_IFF_THLD, 0);
regmap_write(regmap_i2s, I2S_TX_IRQ_OFF_THLD, 1);
/* TX and RX block each have an independent bit to indicate
* if it is generating the clock for the I2S bus. The bus
* clocks need to be generated from either the TX or RX block,
* but not both
*/
regmap_read(regmap_i2s, I2S_RX_CFG_2, &slavemode);
if (slavemode & I2S_RX_SLAVE_MODE_MASK)
regmap_update_bits(regmap_i2s, I2S_TX_CFG_2,
I2S_TX_SLAVE_MODE_MASK,
I2S_TX_MASTER_MODE);
else
regmap_update_bits(regmap_i2s, I2S_TX_CFG_2,
I2S_TX_SLAVE_MODE_MASK,
I2S_TX_SLAVE_MODE);
} else {
regmap_update_bits(regmap_i2s, I2S_RX_CFG,
I2S_RX_IN_R | I2S_RX_DATA_ALIGNMENT |
I2S_RX_CLOCK_ENABLE,
I2S_RX_IN_R | I2S_RX_DATA_ALIGNMENT |
I2S_RX_CLOCK_ENABLE);
regmap_write(regmap_i2s, I2S_RX_IRQ_CTL, 0);
regmap_write(regmap_i2s, I2S_RX_IRQ_IFF_THLD, 0);
regmap_write(regmap_i2s, I2S_RX_IRQ_OFF_THLD, 1);
regmap_read(regmap_i2s, I2S_TX_CFG_2, &slavemode);
if (slavemode & I2S_TX_SLAVE_MODE_MASK)
regmap_update_bits(regmap_i2s, I2S_RX_CFG_2,
I2S_RX_SLAVE_MODE_MASK, 0);
else
regmap_update_bits(regmap_i2s, I2S_RX_CFG_2,
I2S_RX_SLAVE_MODE_MASK,
I2S_RX_SLAVE_MODE);
}
return 0;
}
static void bcm63xx_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
unsigned int enabled, slavemode;
struct bcm_i2s_priv *i2s_priv = snd_soc_dai_get_drvdata(dai);
struct regmap *regmap_i2s = i2s_priv->regmap_i2s;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
regmap_update_bits(regmap_i2s, I2S_TX_CFG,
I2S_TX_OUT_R | I2S_TX_DATA_ALIGNMENT |
I2S_TX_DATA_ENABLE | I2S_TX_CLOCK_ENABLE, 0);
regmap_write(regmap_i2s, I2S_TX_IRQ_CTL, 1);
regmap_write(regmap_i2s, I2S_TX_IRQ_IFF_THLD, 4);
regmap_write(regmap_i2s, I2S_TX_IRQ_OFF_THLD, 4);
regmap_read(regmap_i2s, I2S_TX_CFG_2, &slavemode);
slavemode = slavemode & I2S_TX_SLAVE_MODE_MASK;
if (!slavemode) {
regmap_read(regmap_i2s, I2S_RX_CFG, &enabled);
enabled = enabled & I2S_RX_ENABLE_MASK;
if (enabled)
regmap_update_bits(regmap_i2s, I2S_RX_CFG_2,
I2S_RX_SLAVE_MODE_MASK,
I2S_RX_MASTER_MODE);
}
regmap_update_bits(regmap_i2s, I2S_TX_CFG_2,
I2S_TX_SLAVE_MODE_MASK,
I2S_TX_SLAVE_MODE);
} else {
regmap_update_bits(regmap_i2s, I2S_RX_CFG,
I2S_RX_IN_R | I2S_RX_DATA_ALIGNMENT |
I2S_RX_CLOCK_ENABLE, 0);
regmap_write(regmap_i2s, I2S_RX_IRQ_CTL, 1);
regmap_write(regmap_i2s, I2S_RX_IRQ_IFF_THLD, 4);
regmap_write(regmap_i2s, I2S_RX_IRQ_OFF_THLD, 4);
regmap_read(regmap_i2s, I2S_RX_CFG_2, &slavemode);
slavemode = slavemode & I2S_RX_SLAVE_MODE_MASK;
if (!slavemode) {
regmap_read(regmap_i2s, I2S_TX_CFG, &enabled);
enabled = enabled & I2S_TX_ENABLE_MASK;
if (enabled)
regmap_update_bits(regmap_i2s, I2S_TX_CFG_2,
I2S_TX_SLAVE_MODE_MASK,
I2S_TX_MASTER_MODE);
}
regmap_update_bits(regmap_i2s, I2S_RX_CFG_2,
I2S_RX_SLAVE_MODE_MASK, I2S_RX_SLAVE_MODE);
}
}
static const struct snd_soc_dai_ops bcm63xx_i2s_dai_ops = {
.startup = bcm63xx_i2s_startup,
.shutdown = bcm63xx_i2s_shutdown,
.hw_params = bcm63xx_i2s_hw_params,
};
static struct snd_soc_dai_driver bcm63xx_i2s_dai = {
.name = DRV_NAME,
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &bcm63xx_i2s_dai_ops,
.symmetric_rates = 1,
.symmetric_channels = 1,
};
static const struct snd_soc_component_driver bcm63xx_i2s_component = {
.name = "bcm63xx",
};
static int bcm63xx_i2s_dev_probe(struct platform_device *pdev)
{
int ret = 0;
void __iomem *regs;
struct resource *r_mem, *region;
struct bcm_i2s_priv *i2s_priv;
struct regmap *regmap_i2s;
struct clk *i2s_clk;
i2s_priv = devm_kzalloc(&pdev->dev, sizeof(*i2s_priv), GFP_KERNEL);
if (!i2s_priv)
return -ENOMEM;
i2s_clk = devm_clk_get(&pdev->dev, "i2sclk");
if (IS_ERR(i2s_clk)) {
dev_err(&pdev->dev, "%s: cannot get a brcm clock: %ld\n",
__func__, PTR_ERR(i2s_clk));
return PTR_ERR(i2s_clk);
}
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r_mem) {
dev_err(&pdev->dev, "Unable to get register resource.\n");
return -ENODEV;
}
region = devm_request_mem_region(&pdev->dev, r_mem->start,
resource_size(r_mem), DRV_NAME);
if (!region) {
dev_err(&pdev->dev, "Memory region already claimed\n");
return -EBUSY;
}
regs = devm_ioremap_resource(&pdev->dev, r_mem);
if (IS_ERR(regs)) {
ret = PTR_ERR(regs);
return ret;
}
regmap_i2s = devm_regmap_init_mmio(&pdev->dev,
regs, &brcm_i2s_regmap_config);
if (IS_ERR(regmap_i2s))
return PTR_ERR(regmap_i2s);
regmap_update_bits(regmap_i2s, I2S_MISC_CFG,
I2S_PAD_LVL_LOOP_DIS_MASK,
I2S_PAD_LVL_LOOP_DIS_ENABLE);
ret = devm_snd_soc_register_component(&pdev->dev,
&bcm63xx_i2s_component,
&bcm63xx_i2s_dai, 1);
if (ret) {
dev_err(&pdev->dev, "failed to register the dai\n");
return ret;
}
i2s_priv->dev = &pdev->dev;
i2s_priv->i2s_clk = i2s_clk;
i2s_priv->regmap_i2s = regmap_i2s;
dev_set_drvdata(&pdev->dev, i2s_priv);
ret = bcm63xx_soc_platform_probe(pdev, i2s_priv);
if (ret)
dev_err(&pdev->dev, "failed to register the pcm\n");
return ret;
}
static int bcm63xx_i2s_dev_remove(struct platform_device *pdev)
{
bcm63xx_soc_platform_remove(pdev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id snd_soc_bcm_audio_match[] = {
{.compatible = "brcm,bcm63xx-i2s"},
{ }
};
#endif
static struct platform_driver bcm63xx_i2s_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(snd_soc_bcm_audio_match),
},
.probe = bcm63xx_i2s_dev_probe,
.remove = bcm63xx_i2s_dev_remove,
};
module_platform_driver(bcm63xx_i2s_driver);
MODULE_AUTHOR("Kevin,Li <kevin-ke.li@broadcom.com>");
MODULE_DESCRIPTION("Broadcom DSL XPON ASOC I2S Interface");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0-or-later
// linux/sound/soc/bcm/bcm63xx-i2s.h
// Copyright (c) 2020 Broadcom Corporation
// Author: Kevin-Ke Li <kevin-ke.li@broadcom.com>
#ifndef __BCM63XX_I2S_H
#define __BCM63XX_I2S_H
#define I2S_DESC_FIFO_DEPTH 8
#define I2S_MISC_CFG (0x003C)
#define I2S_PAD_LVL_LOOP_DIS_MASK (1 << 2)
#define I2S_PAD_LVL_LOOP_DIS_ENABLE I2S_PAD_LVL_LOOP_DIS_MASK
#define I2S_TX_ENABLE_MASK (1 << 31)
#define I2S_TX_ENABLE I2S_TX_ENABLE_MASK
#define I2S_TX_OUT_R (1 << 19)
#define I2S_TX_DATA_ALIGNMENT (1 << 2)
#define I2S_TX_DATA_ENABLE (1 << 1)
#define I2S_TX_CLOCK_ENABLE (1 << 0)
#define I2S_TX_DESC_OFF_LEVEL_SHIFT 12
#define I2S_TX_DESC_OFF_LEVEL_MASK (0x0F << I2S_TX_DESC_OFF_LEVEL_SHIFT)
#define I2S_TX_DESC_IFF_LEVEL_SHIFT 8
#define I2S_TX_DESC_IFF_LEVEL_MASK (0x0F << I2S_TX_DESC_IFF_LEVEL_SHIFT)
#define I2S_TX_DESC_OFF_INTR_EN_MSK (1 << 1)
#define I2S_TX_DESC_OFF_INTR_EN I2S_TX_DESC_OFF_INTR_EN_MSK
#define I2S_TX_CFG (0x0000)
#define I2S_TX_IRQ_CTL (0x0004)
#define I2S_TX_IRQ_EN (0x0008)
#define I2S_TX_IRQ_IFF_THLD (0x000c)
#define I2S_TX_IRQ_OFF_THLD (0x0010)
#define I2S_TX_DESC_IFF_ADDR (0x0014)
#define I2S_TX_DESC_IFF_LEN (0x0018)
#define I2S_TX_DESC_OFF_ADDR (0x001C)
#define I2S_TX_DESC_OFF_LEN (0x0020)
#define I2S_TX_CFG_2 (0x0024)
#define I2S_TX_SLAVE_MODE_SHIFT 13
#define I2S_TX_SLAVE_MODE_MASK (1 << I2S_TX_SLAVE_MODE_SHIFT)
#define I2S_TX_SLAVE_MODE I2S_TX_SLAVE_MODE_MASK
#define I2S_TX_MASTER_MODE 0
#define I2S_TX_INTR_MASK 0x0F
#define I2S_RX_ENABLE_MASK (1 << 31)
#define I2S_RX_ENABLE I2S_RX_ENABLE_MASK
#define I2S_RX_IN_R (1 << 19)
#define I2S_RX_DATA_ALIGNMENT (1 << 2)
#define I2S_RX_CLOCK_ENABLE (1 << 0)
#define I2S_RX_DESC_OFF_LEVEL_SHIFT 12
#define I2S_RX_DESC_OFF_LEVEL_MASK (0x0F << I2S_RX_DESC_OFF_LEVEL_SHIFT)
#define I2S_RX_DESC_IFF_LEVEL_SHIFT 8
#define I2S_RX_DESC_IFF_LEVEL_MASK (0x0F << I2S_RX_DESC_IFF_LEVEL_SHIFT)
#define I2S_RX_DESC_OFF_INTR_EN_MSK (1 << 1)
#define I2S_RX_DESC_OFF_INTR_EN I2S_RX_DESC_OFF_INTR_EN_MSK
#define I2S_RX_CFG (0x0040) /* 20c0 */
#define I2S_RX_IRQ_CTL (0x0044)
#define I2S_RX_IRQ_EN (0x0048)
#define I2S_RX_IRQ_IFF_THLD (0x004C)
#define I2S_RX_IRQ_OFF_THLD (0x0050)
#define I2S_RX_DESC_IFF_ADDR (0x0054)
#define I2S_RX_DESC_IFF_LEN (0x0058)
#define I2S_RX_DESC_OFF_ADDR (0x005C)
#define I2S_RX_DESC_OFF_LEN (0x0060)
#define I2S_RX_CFG_2 (0x0064)
#define I2S_RX_SLAVE_MODE_SHIFT 13
#define I2S_RX_SLAVE_MODE_MASK (1 << I2S_RX_SLAVE_MODE_SHIFT)
#define I2S_RX_SLAVE_MODE I2S_RX_SLAVE_MODE_MASK
#define I2S_RX_MASTER_MODE 0
#define I2S_RX_INTR_MASK 0x0F
#define I2S_REG_MAX 0x007C
struct bcm_i2s_priv {
struct device *dev;
struct resource *r_irq;
struct regmap *regmap_i2s;
struct clk *i2s_clk;
struct snd_pcm_substream *play_substream;
struct snd_pcm_substream *capture_substream;
struct i2s_dma_desc *play_dma_desc;
struct i2s_dma_desc *capture_dma_desc;
};
extern int bcm63xx_soc_platform_probe(struct platform_device *pdev,
struct bcm_i2s_priv *i2s_priv);
extern int bcm63xx_soc_platform_remove(struct platform_device *pdev);
#endif
This diff is collapsed.
......@@ -209,7 +209,7 @@ static struct cygnus_aio_port *cygnus_dai_get_dma_data(
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
return snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
return snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(soc_runtime, 0), substream);
}
static void ringbuf_set_initial(void __iomem *audio_io,
......@@ -359,7 +359,7 @@ static void disable_intr(struct snd_pcm_substream *substream)
aio = cygnus_dai_get_dma_data(substream);
dev_dbg(rtd->cpu_dai->dev, "%s on port %d\n", __func__, aio->portnum);
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->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);
......@@ -590,7 +590,7 @@ static int cygnus_pcm_open(struct snd_soc_component *component,
if (!aio)
return -ENODEV;
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
snd_soc_set_runtime_hwparams(substream, &cygnus_pcm_hw);
......@@ -623,7 +623,7 @@ static int cygnus_pcm_close(struct snd_soc_component *component,
aio = cygnus_dai_get_dma_data(substream);
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
aio->play_stream = NULL;
......@@ -631,7 +631,7 @@ static int cygnus_pcm_close(struct snd_soc_component *component,
aio->capture_stream = NULL;
if (!aio->play_stream && !aio->capture_stream)
dev_dbg(rtd->cpu_dai->dev, "freed port %d\n", aio->portnum);
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "freed port %d\n", aio->portnum);
return 0;
}
......@@ -645,7 +645,7 @@ static int cygnus_pcm_hw_params(struct snd_soc_component *component,
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);
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
......@@ -660,7 +660,7 @@ static int cygnus_pcm_hw_free(struct snd_soc_component *component,
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);
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
......@@ -678,12 +678,12 @@ static int cygnus_pcm_prepare(struct snd_soc_component *component,
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);
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->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",
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s (buf_size %lu) (period_size %lu)\n",
__func__, bufsize, periodsize);
configure_ringbuf_regs(substream);
......@@ -745,11 +745,11 @@ static int cygnus_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
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",
dev_dbg(asoc_rtd_to_cpu(rtd, 0)->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__);
dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "%s: dma_alloc failed\n", __func__);
return -ENOMEM;
}
buf->bytes = size;
......
......@@ -23,8 +23,8 @@ static int edb93xx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int err;
unsigned int mclk_rate;
unsigned int rate = params_rate(params);
......
......@@ -23,8 +23,8 @@ static int snappercl15_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int err;
err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK,
......
This diff is collapsed.
......@@ -177,6 +177,7 @@ snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o
snd-soc-rt5682-objs := rt5682.o
snd-soc-rt5682-sdw-objs := rt5682-sdw.o
snd-soc-rt700-objs := rt700.o rt700-sdw.o
snd-soc-rt711-objs := rt711.o rt711-sdw.o
snd-soc-rt715-objs := rt715.o rt715-sdw.o
......@@ -218,6 +219,7 @@ snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-tlv320adcx140-objs := tlv320adcx140.o
snd-soc-tscs42xx-objs := tscs42xx.o
snd-soc-tscs454-objs := tscs454.o
snd-soc-ts3a227e-objs := ts3a227e.o
......@@ -476,6 +478,7 @@ obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
obj-$(CONFIG_SND_SOC_RT5682) += snd-soc-rt5682.o
obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o
obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o
obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o
obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o
......@@ -516,6 +519,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TLV320ADCX140) += snd-soc-tlv320adcx140.o
obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o
obj-$(CONFIG_SND_SOC_TSCS454) += snd-soc-tscs454.o
obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
......
......@@ -45,6 +45,9 @@ struct cros_ec_codec_priv {
/* DMIC */
atomic_t dmic_probed;
/* I2S_RX */
uint32_t i2s_rx_bclk_ratio;
/* WoV */
bool wov_enabled;
uint8_t *wov_audio_shm_p;
......@@ -259,6 +262,7 @@ static int i2s_rx_hw_params(struct snd_pcm_substream *substream,
snd_soc_component_get_drvdata(component);
struct ec_param_ec_codec_i2s_rx p;
enum ec_codec_i2s_rx_sample_depth depth;
uint32_t bclk;
int ret;
if (params_rate(params) != 48000)
......@@ -284,15 +288,29 @@ static int i2s_rx_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
dev_dbg(component->dev, "set bclk to %u\n",
snd_soc_params_to_bclk(params));
if (priv->i2s_rx_bclk_ratio)
bclk = params_rate(params) * priv->i2s_rx_bclk_ratio;
else
bclk = snd_soc_params_to_bclk(params);
dev_dbg(component->dev, "set bclk to %u\n", bclk);
p.cmd = EC_CODEC_I2S_RX_SET_BCLK;
p.set_bclk_param.bclk = snd_soc_params_to_bclk(params);
p.set_bclk_param.bclk = bclk;
return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX,
(uint8_t *)&p, sizeof(p), NULL, 0);
}
static int i2s_rx_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
{
struct snd_soc_component *component = dai->component;
struct cros_ec_codec_priv *priv =
snd_soc_component_get_drvdata(component);
priv->i2s_rx_bclk_ratio = ratio;
return 0;
}
static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
......@@ -340,6 +358,7 @@ static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static const struct snd_soc_dai_ops i2s_rx_dai_ops = {
.hw_params = i2s_rx_hw_params,
.set_fmt = i2s_rx_set_fmt,
.set_bclk_ratio = i2s_rx_set_bclk_ratio,
};
static int i2s_rx_event(struct snd_soc_dapm_widget *w,
......
......@@ -356,9 +356,9 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
*/
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
!dai->capture_active) ||
!dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]) ||
(substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
!dai->playback_active)) {
!dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK])) {
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN,
CS4271_MODE2_PDN);
......
......@@ -1239,12 +1239,12 @@ static int cs47l15_open(struct snd_compr_stream *stream)
struct madera *madera = priv->madera;
int n_adsp;
if (strcmp(rtd->codec_dai->name, "cs47l15-dsp-trace") == 0) {
if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l15-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(madera->dev,
"No suitable compressed stream for DAI '%s'\n",
rtd->codec_dai->name);
asoc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
......
......@@ -1076,14 +1076,14 @@ static int cs47l24_open(struct snd_compr_stream *stream)
struct arizona *arizona = priv->core.arizona;
int n_adsp;
if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) {
if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l24-dsp-voicectrl") == 0) {
n_adsp = 2;
} else if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-trace") == 0) {
} else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l24-dsp-trace") == 0) {
n_adsp = 1;
} else {
dev_err(arizona->dev,
"No suitable compressed stream for DAI '%s'\n",
rtd->codec_dai->name);
asoc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment