Merge branch 'asoc-5.7' into asoc-next

This commit is contained in:
Mark Brown 2020-03-27 17:29:20 +00:00
Родитель 8e3bb8ec11 3d2cdb8546
Коммит 1c521d7e62
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 24D68B725D5487D0
372 изменённых файлов: 17411 добавлений и 3703 удалений

Просмотреть файл

@ -0,0 +1,113 @@
# 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>;
};

Просмотреть файл

@ -0,0 +1,51 @@
# 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>;
};

Просмотреть файл

@ -0,0 +1,113 @@
# 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>;
};
};
};

Просмотреть файл

@ -0,0 +1,58 @@
# 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>;
};

Просмотреть файл

@ -0,0 +1,29 @@
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";
};

Просмотреть файл

@ -0,0 +1,69 @@
# 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>;
};
};
...

Просмотреть файл

@ -1,33 +0,0 @@
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>;
};

Просмотреть файл

@ -1,44 +0,0 @@
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>;
};
};

Просмотреть файл

@ -0,0 +1,67 @@
# 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>;
};
};
};

Просмотреть файл

@ -0,0 +1,92 @@
# 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";
};

Просмотреть файл

@ -1,23 +0,0 @@
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";
};

Просмотреть файл

@ -1,49 +0,0 @@
* 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>;
};

Просмотреть файл

@ -0,0 +1,111 @@
# 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";
};

Просмотреть файл

@ -1,62 +0,0 @@
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>;
};
};
};

Просмотреть файл

@ -0,0 +1,87 @@
# 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>;
};
...

Просмотреть файл

@ -1,56 +0,0 @@
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>;
};

Просмотреть файл

@ -0,0 +1,80 @@
# 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.

Просмотреть файл

@ -0,0 +1,82 @@
# 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,13 +167,15 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
return ret;
}
/* Program DPN_BlockCtrl1 register */
ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1));
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_BlockCtrl1 register write failed for port %d\n",
t_params->port_num);
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) {
dev_err(&s_rt->slave->dev,
"DPN_BlockCtrl1 register write failed for port %d\n",
t_params->port_num);
return ret;
}
}
/* Program DPN_SampleCtrl1 register */

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,18 @@
/* 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 */

Просмотреть файл

@ -0,0 +1,10 @@
/* 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,
struct snd_dma_buffer *bufp)
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;
runtime->dma_buffer_p = bufp;
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)\
for ((i) = 0; \
((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
#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_codec_dai_rollback(rtd, i, dai) \
#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_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 @@ out:
}
#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",

Просмотреть файл

@ -0,0 +1,376 @@
// SPDX-License-Identifier: GPL-2.0+
//
// Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec.
//
//Copyright 2016 Advanced Micro Devices, Inc.
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/acpi.h>
#include "raven/acp3x.h"
#include "../codecs/rt5682.h"
#define PCO_PLAT_CLK 48000000
#define RT5682_PLL_FREQ (48000 * 512)
#define DUAL_CHANNEL 2
static struct snd_soc_jack pco_jack;
static struct clk *rt5682_dai_wclk;
static struct clk *rt5682_dai_bclk;
static struct gpio_desc *dmic_sel;
static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_card *card = rtd->card;
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);
/* set rt5682 dai fmt */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
dev_err(rtd->card->dev,
"Failed to set rt5682 dai fmt: %d\n", ret);
return ret;
}
/* set codec PLL */
ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK,
PCO_PLAT_CLK, RT5682_PLL_FREQ);
if (ret < 0) {
dev_err(rtd->dev, "can't set rt5682 PLL: %d\n", ret);
return ret;
}
/* Set codec sysclk */
ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2,
RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(rtd->dev,
"Failed to set rt5682 SYSCLK: %d\n", ret);
return ret;
}
/* Set tdm/i2s1 master bclk ratio */
ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
if (ret < 0) {
dev_err(rtd->dev,
"Failed to set rt5682 tdm bclk ratio: %d\n", ret);
return ret;
}
rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk");
rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk");
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&pco_jack, NULL, 0);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
}
return ret;
}
static int rt5682_clk_enable(struct snd_pcm_substream *substream)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
/* RT5682 will support only 48K output with 48M mclk */
clk_set_rate(rt5682_dai_wclk, 48000);
clk_set_rate(rt5682_dai_bclk, 48000 * 64);
ret = clk_prepare_enable(rt5682_dai_wclk);
if (ret < 0) {
dev_err(rtd->dev, "can't enable wclk %d\n", ret);
return ret;
}
return ret;
}
static void rt5682_clk_disable(void)
{
clk_disable_unprepare(rt5682_dai_wclk);
}
static const unsigned int channels[] = {
DUAL_CHANNEL,
};
static const unsigned int rates[] = {
48000,
};
static const struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static const struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
};
static int acp3x_5682_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->play_i2s_instance = I2S_SP_INSTANCE;
machine->cap_i2s_instance = I2S_SP_INSTANCE;
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
return rt5682_clk_enable(substream);
}
static int acp3x_max_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->play_i2s_instance = I2S_BT_INSTANCE;
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
return rt5682_clk_enable(substream);
}
static int acp3x_ec_dmic0_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->cap_i2s_instance = I2S_BT_INSTANCE;
snd_soc_dai_set_bclk_ratio(codec_dai, 64);
if (dmic_sel)
gpiod_set_value(dmic_sel, 0);
return rt5682_clk_enable(substream);
}
static int acp3x_ec_dmic1_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->cap_i2s_instance = I2S_BT_INSTANCE;
snd_soc_dai_set_bclk_ratio(codec_dai, 64);
if (dmic_sel)
gpiod_set_value(dmic_sel, 1);
return rt5682_clk_enable(substream);
}
static void rt5682_shutdown(struct snd_pcm_substream *substream)
{
rt5682_clk_disable();
}
static const struct snd_soc_ops acp3x_5682_ops = {
.startup = acp3x_5682_startup,
.shutdown = rt5682_shutdown,
};
static const struct snd_soc_ops acp3x_max_play_ops = {
.startup = acp3x_max_startup,
.shutdown = rt5682_shutdown,
};
static const struct snd_soc_ops acp3x_ec_cap0_ops = {
.startup = acp3x_ec_dmic0_startup,
.shutdown = rt5682_shutdown,
};
static const struct snd_soc_ops acp3x_ec_cap1_ops = {
.startup = acp3x_ec_dmic1_startup,
.shutdown = rt5682_shutdown,
};
SND_SOC_DAILINK_DEF(acp3x_i2s,
DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.0")));
SND_SOC_DAILINK_DEF(acp3x_bt,
DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.2")));
SND_SOC_DAILINK_DEF(rt5682,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
SND_SOC_DAILINK_DEF(max,
DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi")));
SND_SOC_DAILINK_DEF(cros_ec,
DAILINK_COMP_ARRAY(COMP_CODEC("GOOG0013:00", "EC Codec I2S RX")));
SND_SOC_DAILINK_DEF(platform,
DAILINK_COMP_ARRAY(COMP_PLATFORM("acp3x_rv_i2s_dma.0")));
static struct snd_soc_dai_link acp3x_dai_5682_98357[] = {
{
.name = "acp3x-5682-play",
.stream_name = "Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.init = acp3x_5682_init,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ops = &acp3x_5682_ops,
SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform),
},
{
.name = "acp3x-max98357-play",
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_playback = 1,
.ops = &acp3x_max_play_ops,
SND_SOC_DAILINK_REG(acp3x_bt, max, platform),
},
{
.name = "acp3x-ec-dmic0-capture",
.stream_name = "Capture DMIC0",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.dpcm_capture = 1,
.ops = &acp3x_ec_cap0_ops,
SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform),
},
{
.name = "acp3x-ec-dmic1-capture",
.stream_name = "Capture DMIC1",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.dpcm_capture = 1,
.ops = &acp3x_ec_cap1_ops,
SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform),
},
};
static const struct snd_soc_dapm_widget acp3x_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_SPK("Spk", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
static const struct snd_soc_dapm_route acp3x_audio_route[] = {
{"Headphone Jack", NULL, "HPOL"},
{"Headphone Jack", NULL, "HPOR"},
{"IN1P", NULL, "Headset Mic"},
{"Spk", NULL, "Speaker"},
};
static const struct snd_kcontrol_new acp3x_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Spk"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
static struct snd_soc_card acp3x_card = {
.name = "acp3xalc5682m98357",
.owner = THIS_MODULE,
.dai_link = acp3x_dai_5682_98357,
.num_links = ARRAY_SIZE(acp3x_dai_5682_98357),
.dapm_widgets = acp3x_widgets,
.num_dapm_widgets = ARRAY_SIZE(acp3x_widgets),
.dapm_routes = acp3x_audio_route,
.num_dapm_routes = ARRAY_SIZE(acp3x_audio_route),
.controls = acp3x_mc_controls,
.num_controls = ARRAY_SIZE(acp3x_mc_controls),
};
static int acp3x_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card;
struct acp3x_platform_info *machine;
machine = devm_kzalloc(&pdev->dev, sizeof(*machine), GFP_KERNEL);
if (!machine)
return -ENOMEM;
card = &acp3x_card;
acp3x_card.dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
if (IS_ERR(dmic_sel)) {
dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n",
PTR_ERR(dmic_sel));
return PTR_ERR(dmic_sel);
}
ret = devm_snd_soc_register_card(&pdev->dev, &acp3x_card);
if (ret) {
dev_err(&pdev->dev,
"devm_snd_soc_register_card(%s) failed: %d\n",
acp3x_card.name, ret);
return ret;
}
return 0;
}
static const struct acpi_device_id acp3x_audio_acpi_match[] = {
{ "AMDI5682", 0 },
{},
};
MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match);
static struct platform_driver acp3x_audio = {
.driver = {
.name = "acp3x-alc5682-max98357",
.acpi_match_table = ACPI_PTR(acp3x_audio_acpi_match),
.pm = &snd_soc_pm_ops,
},
.probe = acp3x_probe,
};
module_platform_driver(acp3x_audio);
MODULE_AUTHOR("akshu.agrawal@amd.com");
MODULE_DESCRIPTION("ALC5682 & MAX98357 audio support");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -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,21 +114,30 @@ 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);
rv_writel(val, rtd->acp3x_base + reg_val);

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,317 @@
// 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");

Просмотреть файл

@ -0,0 +1,90 @@
// 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

Просмотреть файл

@ -0,0 +1,485 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// linux/sound/bcm/bcm63xx-pcm-whistler.c
// BCM63xx whistler pcm interface
// Copyright (c) 2020 Broadcom Corporation
// Author: Kevin-Ke Li <kevin-ke.li@broadcom.com>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/module.h>
#include <sound/pcm_params.h>
#include <linux/regmap.h>
#include <linux/of_device.h>
#include <sound/soc.h>
#include "bcm63xx-i2s.h"
struct i2s_dma_desc {
unsigned char *dma_area;
dma_addr_t dma_addr;
unsigned int dma_len;
};
struct bcm63xx_runtime_data {
int dma_len;
dma_addr_t dma_addr;
dma_addr_t dma_addr_next;
};
static const struct snd_pcm_hardware bcm63xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S32_LE, /* support S32 only */
.period_bytes_max = 8192 - 32,
.periods_min = 1,
.periods_max = PAGE_SIZE/sizeof(struct i2s_dma_desc),
.buffer_bytes_max = 128 * 1024,
.fifo_size = 32,
};
static int bcm63xx_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct i2s_dma_desc *dma_desc;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT);
if (!dma_desc)
return -ENOMEM;
snd_soc_dai_set_dma_data(asoc_rtd_to_cpu(rtd, 0), substream, dma_desc);
return 0;
}
static int bcm63xx_pcm_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct i2s_dma_desc *dma_desc;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
kfree(dma_desc);
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
static int bcm63xx_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd;
struct bcm_i2s_priv *i2s_priv;
struct regmap *regmap_i2s;
rtd = substream->private_data;
i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
regmap_i2s = i2s_priv->regmap_i2s;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
regmap_update_bits(regmap_i2s,
I2S_TX_IRQ_EN,
I2S_TX_DESC_OFF_INTR_EN,
I2S_TX_DESC_OFF_INTR_EN);
regmap_update_bits(regmap_i2s,
I2S_TX_CFG,
I2S_TX_ENABLE_MASK,
I2S_TX_ENABLE);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
regmap_write(regmap_i2s,
I2S_TX_IRQ_EN,
0);
regmap_update_bits(regmap_i2s,
I2S_TX_CFG,
I2S_TX_ENABLE_MASK,
0);
break;
default:
ret = -EINVAL;
}
} else {
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
regmap_update_bits(regmap_i2s,
I2S_RX_IRQ_EN,
I2S_RX_DESC_OFF_INTR_EN_MSK,
I2S_RX_DESC_OFF_INTR_EN);
regmap_update_bits(regmap_i2s,
I2S_RX_CFG,
I2S_RX_ENABLE_MASK,
I2S_RX_ENABLE);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
regmap_update_bits(regmap_i2s,
I2S_RX_IRQ_EN,
I2S_RX_DESC_OFF_INTR_EN_MSK,
0);
regmap_update_bits(regmap_i2s,
I2S_RX_CFG,
I2S_RX_ENABLE_MASK,
0);
break;
default:
ret = -EINVAL;
}
}
return ret;
}
static int bcm63xx_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct i2s_dma_desc *dma_desc;
struct regmap *regmap_i2s;
struct bcm_i2s_priv *i2s_priv;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
uint32_t regaddr_desclen, regaddr_descaddr;
dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
dma_desc->dma_len = snd_pcm_lib_period_bytes(substream);
dma_desc->dma_addr = runtime->dma_addr;
dma_desc->dma_area = runtime->dma_area;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
regaddr_desclen = I2S_TX_DESC_IFF_LEN;
regaddr_descaddr = I2S_TX_DESC_IFF_ADDR;
} else {
regaddr_desclen = I2S_RX_DESC_IFF_LEN;
regaddr_descaddr = I2S_RX_DESC_IFF_ADDR;
}
i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
regmap_i2s = i2s_priv->regmap_i2s;
regmap_write(regmap_i2s, regaddr_desclen, dma_desc->dma_len);
regmap_write(regmap_i2s, regaddr_descaddr, dma_desc->dma_addr);
return 0;
}
static snd_pcm_uframes_t
bcm63xx_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
snd_pcm_uframes_t x;
struct bcm63xx_runtime_data *prtd = substream->runtime->private_data;
if ((void *)prtd->dma_addr_next == NULL)
prtd->dma_addr_next = substream->runtime->dma_addr;
x = bytes_to_frames(substream->runtime,
prtd->dma_addr_next - substream->runtime->dma_addr);
return x == substream->runtime->buffer_size ? 0 : x;
}
static int bcm63xx_pcm_mmap(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
return dma_mmap_wc(substream->pcm->card->dev, vma,
runtime->dma_area,
runtime->dma_addr,
runtime->dma_bytes);
}
static int bcm63xx_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct bcm63xx_runtime_data *prtd;
runtime->hw = bcm63xx_pcm_hardware;
ret = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
if (ret)
goto out;
ret = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
if (ret)
goto out;
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto out;
ret = -ENOMEM;
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
if (!prtd)
goto out;
runtime->private_data = prtd;
return 0;
out:
return ret;
}
static int bcm63xx_pcm_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct bcm63xx_runtime_data *prtd = runtime->private_data;
kfree(prtd);
return 0;
}
static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv)
{
unsigned int availdepth, ifflevel, offlevel, int_status, val_1, val_2;
struct bcm63xx_runtime_data *prtd;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
struct regmap *regmap_i2s;
struct i2s_dma_desc *dma_desc;
struct snd_soc_pcm_runtime *rtd;
struct bcm_i2s_priv *i2s_priv;
i2s_priv = (struct bcm_i2s_priv *)bcm_i2s_priv;
regmap_i2s = i2s_priv->regmap_i2s;
/* rx */
regmap_read(regmap_i2s, I2S_RX_IRQ_CTL, &int_status);
if (int_status & I2S_RX_DESC_OFF_INTR_EN_MSK) {
substream = i2s_priv->capture_substream;
runtime = substream->runtime;
rtd = substream->private_data;
prtd = runtime->private_data;
dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
offlevel = (int_status & I2S_RX_DESC_OFF_LEVEL_MASK) >>
I2S_RX_DESC_OFF_LEVEL_SHIFT;
while (offlevel) {
regmap_read(regmap_i2s, I2S_RX_DESC_OFF_ADDR, &val_1);
regmap_read(regmap_i2s, I2S_RX_DESC_OFF_LEN, &val_2);
offlevel--;
}
prtd->dma_addr_next = val_1 + val_2;
ifflevel = (int_status & I2S_RX_DESC_IFF_LEVEL_MASK) >>
I2S_RX_DESC_IFF_LEVEL_SHIFT;
availdepth = I2S_DESC_FIFO_DEPTH - ifflevel;
while (availdepth) {
dma_desc->dma_addr +=
snd_pcm_lib_period_bytes(substream);
dma_desc->dma_area +=
snd_pcm_lib_period_bytes(substream);
if (dma_desc->dma_addr - runtime->dma_addr >=
runtime->dma_bytes) {
dma_desc->dma_addr = runtime->dma_addr;
dma_desc->dma_area = runtime->dma_area;
}
prtd->dma_addr = dma_desc->dma_addr;
regmap_write(regmap_i2s, I2S_RX_DESC_IFF_LEN,
snd_pcm_lib_period_bytes(substream));
regmap_write(regmap_i2s, I2S_RX_DESC_IFF_ADDR,
dma_desc->dma_addr);
availdepth--;
}
snd_pcm_period_elapsed(substream);
/* Clear interrupt by writing 0 */
regmap_update_bits(regmap_i2s, I2S_RX_IRQ_CTL,
I2S_RX_INTR_MASK, 0);
}
/* tx */
regmap_read(regmap_i2s, I2S_TX_IRQ_CTL, &int_status);
if (int_status & I2S_TX_DESC_OFF_INTR_EN_MSK) {
substream = i2s_priv->play_substream;
runtime = substream->runtime;
rtd = substream->private_data;
prtd = runtime->private_data;
dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
offlevel = (int_status & I2S_TX_DESC_OFF_LEVEL_MASK) >>
I2S_TX_DESC_OFF_LEVEL_SHIFT;
while (offlevel) {
regmap_read(regmap_i2s, I2S_TX_DESC_OFF_ADDR, &val_1);
regmap_read(regmap_i2s, I2S_TX_DESC_OFF_LEN, &val_2);
prtd->dma_addr_next = val_1 + val_2;
offlevel--;
}
ifflevel = (int_status & I2S_TX_DESC_IFF_LEVEL_MASK) >>
I2S_TX_DESC_IFF_LEVEL_SHIFT;
availdepth = I2S_DESC_FIFO_DEPTH - ifflevel;
while (availdepth) {
dma_desc->dma_addr +=
snd_pcm_lib_period_bytes(substream);
dma_desc->dma_area +=
snd_pcm_lib_period_bytes(substream);
if (dma_desc->dma_addr - runtime->dma_addr >=
runtime->dma_bytes) {
dma_desc->dma_addr = runtime->dma_addr;
dma_desc->dma_area = runtime->dma_area;
}
prtd->dma_addr = dma_desc->dma_addr;
regmap_write(regmap_i2s, I2S_TX_DESC_IFF_LEN,
snd_pcm_lib_period_bytes(substream));
regmap_write(regmap_i2s, I2S_TX_DESC_IFF_ADDR,
dma_desc->dma_addr);
availdepth--;
}
snd_pcm_period_elapsed(substream);
/* Clear interrupt by writing 0 */
regmap_update_bits(regmap_i2s, I2S_TX_IRQ_CTL,
I2S_TX_INTR_MASK, 0);
}
return IRQ_HANDLED;
}
static int bcm63xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size = bcm63xx_pcm_hardware.buffer_bytes_max;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
buf->area = dma_alloc_wc(pcm->card->dev,
size, &buf->addr,
GFP_KERNEL);
if (!buf->area)
return -ENOMEM;
buf->bytes = size;
return 0;
}
static int bcm63xx_soc_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm *pcm = rtd->pcm;
struct bcm_i2s_priv *i2s_priv;
int ret;
i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1);
ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(32));
if (ret)
goto out;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = bcm63xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
i2s_priv->play_substream =
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
}
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = bcm63xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
goto out;
i2s_priv->capture_substream =
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
}
out:
return ret;
}
static void bcm63xx_pcm_free_dma_buffers(struct snd_soc_component *component,
struct snd_pcm *pcm)
{
int stream;
struct snd_dma_buffer *buf;
struct snd_pcm_substream *substream;
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
if (!substream)
continue;
buf = &substream->dma_buffer;
if (!buf->area)
continue;
dma_free_wc(pcm->card->dev, buf->bytes,
buf->area, buf->addr);
buf->area = NULL;
}
}
static const struct snd_soc_component_driver bcm63xx_soc_platform = {
.open = bcm63xx_pcm_open,
.close = bcm63xx_pcm_close,
.hw_params = bcm63xx_pcm_hw_params,
.hw_free = bcm63xx_pcm_hw_free,
.prepare = bcm63xx_pcm_prepare,
.trigger = bcm63xx_pcm_trigger,
.pointer = bcm63xx_pcm_pointer,
.mmap = bcm63xx_pcm_mmap,
.pcm_construct = bcm63xx_soc_pcm_new,
.pcm_destruct = bcm63xx_pcm_free_dma_buffers,
};
int bcm63xx_soc_platform_probe(struct platform_device *pdev,
struct bcm_i2s_priv *i2s_priv)
{
int ret;
i2s_priv->r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!i2s_priv->r_irq) {
dev_err(&pdev->dev, "Unable to get register irq resource.\n");
return -ENODEV;
}
ret = devm_request_irq(&pdev->dev, i2s_priv->r_irq->start, i2s_dma_isr,
i2s_priv->r_irq->flags, "i2s_dma", (void *)i2s_priv);
if (ret) {
dev_err(&pdev->dev,
"i2s_init: failed to request interrupt.ret=%d\n", ret);
return ret;
}
return devm_snd_soc_register_component(&pdev->dev,
&bcm63xx_soc_platform, NULL, 0);
}
int bcm63xx_soc_platform_remove(struct platform_device *pdev)
{
return 0;
}
MODULE_AUTHOR("Kevin,Li <kevin-ke.li@broadcom.com>");
MODULE_DESCRIPTION("Broadcom DSL XPON ASOC PCM Interface");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -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,

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -1514,14 +1514,14 @@ static int cs47l35_open(struct snd_compr_stream *stream)
struct madera *madera = priv->madera;
int n_adsp;
if (strcmp(rtd->codec_dai->name, "cs47l35-dsp-voicectrl") == 0) {
if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l35-dsp-voicectrl") == 0) {
n_adsp = 2;
} else if (strcmp(rtd->codec_dai->name, "cs47l35-dsp-trace") == 0) {
} else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l35-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;
}

Просмотреть файл

@ -2457,14 +2457,14 @@ static int cs47l85_open(struct snd_compr_stream *stream)
struct madera *madera = priv->madera;
int n_adsp;
if (strcmp(rtd->codec_dai->name, "cs47l85-dsp-voicectrl") == 0) {
if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l85-dsp-voicectrl") == 0) {
n_adsp = 5;
} else if (strcmp(rtd->codec_dai->name, "cs47l85-dsp-trace") == 0) {
} else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l85-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;
}

Просмотреть файл

@ -2368,14 +2368,14 @@ static int cs47l90_open(struct snd_compr_stream *stream)
struct madera *madera = priv->madera;
int n_adsp;
if (strcmp(rtd->codec_dai->name, "cs47l90-dsp-voicectrl") == 0) {
if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l90-dsp-voicectrl") == 0) {
n_adsp = 5;
} else if (strcmp(rtd->codec_dai->name, "cs47l90-dsp-trace") == 0) {
} else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l90-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;
}

Просмотреть файл

@ -1840,12 +1840,12 @@ static int cs47l92_open(struct snd_compr_stream *stream)
struct madera *madera = priv->madera;
int n_adsp;
if (strcmp(rtd->codec_dai->name, "cs47l92-dsp-trace") == 0) {
if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l92-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;
}

Просмотреть файл

@ -1998,11 +1998,11 @@ static struct hdac_hdmi_drv_data intel_drv_data = {
static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
{
struct hdac_hdmi_priv *hdmi_priv = NULL;
struct hdac_hdmi_priv *hdmi_priv;
struct snd_soc_dai_driver *hdmi_dais = NULL;
struct hdac_ext_link *hlink = NULL;
struct hdac_ext_link *hlink;
int num_dais = 0;
int ret = 0;
int ret;
struct hdac_driver *hdrv = drv_to_hdac_driver(hdev->dev.driver);
const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);

Просмотреть файл

@ -5,6 +5,7 @@
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio.h>
@ -24,26 +25,24 @@ struct max98357a_priv {
unsigned int sdmode_delay;
};
static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
static int max98357a_sdmode_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct max98357a_priv *max98357a = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct max98357a_priv *max98357a =
snd_soc_component_get_drvdata(component);
if (!max98357a->sdmode)
return 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
mdelay(max98357a->sdmode_delay);
if (event & SND_SOC_DAPM_POST_PMU) {
msleep(max98357a->sdmode_delay);
gpiod_set_value(max98357a->sdmode, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dev_dbg(component->dev, "set sdmode to 1");
} else if (event & SND_SOC_DAPM_PRE_PMD) {
gpiod_set_value(max98357a->sdmode, 0);
break;
dev_dbg(component->dev, "set sdmode to 0");
}
return 0;
@ -51,10 +50,14 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("Speaker"),
SND_SOC_DAPM_OUT_DRV_E("SD_MODE", SND_SOC_NOPM, 0, 0, NULL, 0,
max98357a_sdmode_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
};
static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
{"Speaker", NULL, "HiFi Playback"},
{"SD_MODE", NULL, "HiFi Playback"},
{"Speaker", NULL, "SD_MODE"},
};
static const struct snd_soc_component_driver max98357a_component_driver = {
@ -68,10 +71,6 @@ static const struct snd_soc_component_driver max98357a_component_driver = {
.non_legacy_dai_naming = 1,
};
static const struct snd_soc_dai_ops max98357a_dai_ops = {
.trigger = max98357a_daiops_trigger,
};
static struct snd_soc_dai_driver max98357a_dai_driver = {
.name = "HiFi",
.playback = {
@ -91,7 +90,6 @@ static struct snd_soc_dai_driver max98357a_dai_driver = {
.channels_min = 1,
.channels_max = 2,
},
.ops = &max98357a_dai_ops,
};
static int max98357a_platform_probe(struct platform_device *pdev)

Просмотреть файл

@ -1,15 +1,13 @@
// SPDX-License-Identifier: GPL-2.0 //
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 MediaTek Inc.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
@ -225,14 +223,87 @@ static int _mt6660_chip_power_on(struct mt6660_chip *chip, int on_off)
0x01, on_off ? 0x00 : 0x01);
}
struct reg_table {
uint32_t addr;
uint32_t mask;
uint32_t val;
};
static const struct reg_table mt6660_setting_table[] = {
{ 0x20, 0x80, 0x00 },
{ 0x30, 0x01, 0x00 },
{ 0x50, 0x1c, 0x04 },
{ 0xB1, 0x0c, 0x00 },
{ 0xD3, 0x03, 0x03 },
{ 0xE0, 0x01, 0x00 },
{ 0x98, 0x44, 0x04 },
{ 0xB9, 0xff, 0x82 },
{ 0xB7, 0x7777, 0x7273 },
{ 0xB6, 0x07, 0x03 },
{ 0x6B, 0xe0, 0x20 },
{ 0x07, 0xff, 0x70 },
{ 0xBB, 0xff, 0x20 },
{ 0x69, 0xff, 0x40 },
{ 0xBD, 0xffff, 0x17f8 },
{ 0x70, 0xff, 0x15 },
{ 0x7C, 0xff, 0x00 },
{ 0x46, 0xff, 0x1d },
{ 0x1A, 0xffffffff, 0x7fdb7ffe },
{ 0x1B, 0xffffffff, 0x7fdb7ffe },
{ 0x51, 0xff, 0x58 },
{ 0xA2, 0xff, 0xce },
{ 0x33, 0xffff, 0x7fff },
{ 0x4C, 0xffff, 0x0116 },
{ 0x16, 0x1800, 0x0800 },
{ 0x68, 0x1f, 0x07 },
};
static int mt6660_component_setting(struct snd_soc_component *component)
{
struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
int ret = 0;
size_t i = 0;
ret = _mt6660_chip_power_on(chip, 1);
if (ret < 0) {
dev_err(component->dev, "%s chip power on failed\n", __func__);
return ret;
}
for (i = 0; i < ARRAY_SIZE(mt6660_setting_table); i++) {
ret = snd_soc_component_update_bits(component,
mt6660_setting_table[i].addr,
mt6660_setting_table[i].mask,
mt6660_setting_table[i].val);
if (ret < 0) {
dev_err(component->dev, "%s update 0x%02x failed\n",
__func__, mt6660_setting_table[i].addr);
return ret;
}
}
ret = _mt6660_chip_power_on(chip, 0);
if (ret < 0) {
dev_err(component->dev, "%s chip power off failed\n", __func__);
return ret;
}
return 0;
}
static int mt6660_component_probe(struct snd_soc_component *component)
{
struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
int ret;
dev_dbg(component->dev, "%s\n", __func__);
snd_soc_component_init_regmap(component, chip->regmap);
return 0;
ret = mt6660_component_setting(component);
if (ret < 0)
dev_err(chip->dev, "mt6660 component setting failed\n");
return ret;
}
static void mt6660_component_remove(struct snd_soc_component *component)
@ -506,4 +577,4 @@ module_i2c_driver(mt6660_i2c_driver);
MODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>");
MODULE_DESCRIPTION("MT6660 SPKAMP Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.7_G");
MODULE_VERSION("1.0.8_G");

Просмотреть файл

@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@ -31,7 +32,7 @@
struct rk3328_codec_priv {
struct regmap *regmap;
struct regmap *grf;
struct gpio_desc *mute;
struct clk *mclk;
struct clk *pclk;
unsigned int sclk;
@ -106,16 +107,6 @@ static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
static void rk3328_analog_output(struct rk3328_codec_priv *rk3328, int mute)
{
unsigned int val = BIT(17);
if (mute)
val |= BIT(1);
regmap_write(rk3328->grf, RK3328_GRF_SOC_CON10, val);
}
static int rk3328_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct rk3328_codec_priv *rk3328 =
@ -205,7 +196,7 @@ static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328)
}
msleep(rk3328->spk_depop_time);
rk3328_analog_output(rk3328, 1);
gpiod_set_value(rk3328->mute, 0);
regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
HPOUTL_GAIN_MASK, OUT_VOLUME);
@ -246,7 +237,7 @@ static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328)
{
size_t i;
rk3328_analog_output(rk3328, 0);
gpiod_set_value(rk3328->mute, 1);
regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
HPOUTL_GAIN_MASK, 0);
@ -446,7 +437,6 @@ static int rk3328_platform_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "missing 'rockchip,grf'\n");
return PTR_ERR(grf);
}
rk3328->grf = grf;
/* enable i2s_acodec_en */
regmap_write(grf, RK3328_GRF_SOC_CON2,
(BIT(14) << 16 | BIT(14)));
@ -458,7 +448,18 @@ static int rk3328_platform_probe(struct platform_device *pdev)
rk3328->spk_depop_time = 200;
}
rk3328_analog_output(rk3328, 0);
rk3328->mute = gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_HIGH);
if (IS_ERR(rk3328->mute))
return PTR_ERR(rk3328->mute);
/*
* Rock64 is the only supported platform to have widely relied on
* this; if we do happen to come across an old DTB, just leave the
* external mute forced off.
*/
if (!rk3328->mute && of_machine_is_compatible("pine64,rock64")) {
dev_warn(&pdev->dev, "assuming implicit control of GPIO_MUTE; update devicetree if possible\n");
regmap_write(grf, RK3328_GRF_SOC_CON10, BIT(17) | BIT(1));
}
rk3328->mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(rk3328->mclk))

Просмотреть файл

@ -102,6 +102,7 @@ struct pll_calc_map {
static const struct pll_calc_map pll_preset_table[] = {
{19200000, 4096000, 23, 14, 1, false},
{19200000, 24576000, 3, 30, 3, false},
{3840000, 24576000, 3, 30, 0, true},
};
static unsigned int find_best_div(unsigned int in,

Просмотреть файл

@ -10,7 +10,7 @@
#ifndef __RL6231_H__
#define __RL6231_H__
#define RL6231_PLL_INP_MAX 40000000
#define RL6231_PLL_INP_MAX 50000000
#define RL6231_PLL_INP_MIN 256000
#define RL6231_PLL_N_MAX 0x1ff
#define RL6231_PLL_K_MAX 0x1f

Просмотреть файл

@ -444,7 +444,7 @@ static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
return 0;
}
static int rt5518_bypass_boost_get(struct snd_kcontrol *kcontrol,
static int rt1015_bypass_boost_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@ -457,7 +457,7 @@ static int rt5518_bypass_boost_get(struct snd_kcontrol *kcontrol,
return 0;
}
static int rt5518_bypass_boost_put(struct snd_kcontrol *kcontrol,
static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@ -497,7 +497,7 @@ static const struct snd_kcontrol_new rt1015_snd_controls[] = {
rt1015_boost_mode_get, rt1015_boost_mode_put),
SOC_ENUM("Mono LR Select", rt1015_mono_lr_sel),
SOC_SINGLE_EXT("Bypass Boost", SND_SOC_NOPM, 0, 1, 0,
rt5518_bypass_boost_get, rt5518_bypass_boost_put),
rt1015_bypass_boost_get, rt1015_bypass_boost_put),
};
static int rt1015_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
@ -841,12 +841,12 @@ static void rt1015_remove(struct snd_soc_component *component)
#define RT1015_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
struct snd_soc_dai_ops rt1015_aif_dai_ops = {
static struct snd_soc_dai_ops rt1015_aif_dai_ops = {
.hw_params = rt1015_hw_params,
.set_fmt = rt1015_set_dai_fmt,
};
struct snd_soc_dai_driver rt1015_dai[] = {
static struct snd_soc_dai_driver rt1015_dai[] = {
{
.name = "rt1015-aif",
.id = 0,

Просмотреть файл

@ -507,6 +507,28 @@ static void rt1308_sdw_shutdown(struct snd_pcm_substream *substream,
kfree(stream);
}
static int rt1308_sdw_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask,
unsigned int rx_mask,
int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
struct rt1308_sdw_priv *rt1308 =
snd_soc_component_get_drvdata(component);
if (tx_mask)
return -EINVAL;
if (slots > 2)
return -EINVAL;
rt1308->rx_mask = rx_mask;
rt1308->slots = slots;
/* slot_width is not used since it's irrelevant for SoundWire */
return 0;
}
static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
@ -517,7 +539,7 @@ static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream,
struct sdw_port_config port_config;
enum sdw_data_direction direction;
struct sdw_stream_data *stream;
int retval, port, num_channels;
int retval, port, num_channels, ch_mask;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
stream = snd_soc_dai_get_dma_data(dai, substream);
@ -537,13 +559,20 @@ static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
if (rt1308->slots) {
num_channels = rt1308->slots;
ch_mask = rt1308->rx_mask;
} else {
num_channels = params_channels(params);
ch_mask = (1 << num_channels) - 1;
}
stream_config.frame_rate = params_rate(params);
stream_config.ch_count = params_channels(params);
stream_config.ch_count = num_channels;
stream_config.bps = snd_pcm_format_width(params_format(params));
stream_config.direction = direction;
num_channels = params_channels(params);
port_config.ch_mask = (1 << (num_channels)) - 1;
port_config.ch_mask = ch_mask;
port_config.num = port;
retval = sdw_stream_add_slave(rt1308->sdw_slave, &stream_config,
@ -597,6 +626,7 @@ static const struct snd_soc_dai_ops rt1308_aif_dai_ops = {
.hw_free = rt1308_sdw_pcm_hw_free,
.set_sdw_stream = rt1308_set_sdw_stream,
.shutdown = rt1308_sdw_shutdown,
.set_tdm_slot = rt1308_sdw_set_tdm_slot,
};
#define RT1308_STEREO_RATES SNDRV_PCM_RATE_48000

Просмотреть файл

@ -160,6 +160,8 @@ struct rt1308_sdw_priv {
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
int rx_mask;
int slots;
};
struct sdw_stream_data {

Просмотреть файл

@ -1604,7 +1604,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
int pd, idx = -EINVAL;
int pd, idx;
pd = rl6231_get_pre_div(rt5659->regmap,
RT5659_ADDA_CLK_1, RT5659_I2S_PD1_SFT);

Просмотреть файл

@ -0,0 +1,333 @@
// SPDX-License-Identifier: GPL-2.0-only
//
// rt5682-sdw.c -- RT5682 ALSA SoC audio component driver
//
// Copyright 2019 Realtek Semiconductor Corp.
// Author: Oder Chiou <oder_chiou@realtek.com>
//
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "rt5682.h"
#include "rt5682-sdw.h"
static bool rt5682_sdw_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case 0x00e0:
case 0x00f0:
case 0x3000:
case 0x3001:
case 0x3004:
case 0x3005:
case 0x3008:
return true;
default:
return false;
}
}
const struct regmap_config rt5682_sdw_regmap = {
.name = "sdw",
.reg_bits = 32,
.val_bits = 8,
.max_register = RT5682_I2C_MODE,
.readable_reg = rt5682_sdw_readable_register,
.cache_type = REGCACHE_NONE,
.use_single_read = true,
.use_single_write = true,
};
static int rt5682_update_status(struct sdw_slave *slave,
enum sdw_slave_status status)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
/* Update the status */
rt5682->status = status;
if (status == SDW_SLAVE_UNATTACHED)
rt5682->hw_init = false;
/*
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
if (rt5682->hw_init || rt5682->status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
return rt5682_io_init(&slave->dev, slave);
}
static int rt5682_read_prop(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int nval, i, num_of_ports = 1;
u32 bit;
unsigned long addr;
struct sdw_dpn_prop *dpn;
prop->paging_support = false;
/* first we need to allocate memory for set bits in port lists */
prop->source_ports = 0x4; /* BITMAP: 00000100 */
prop->sink_ports = 0x2; /* BITMAP: 00000010 */
nval = hweight32(prop->source_ports);
num_of_ports += nval;
prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->src_dpn_prop),
GFP_KERNEL);
if (!prop->src_dpn_prop)
return -ENOMEM;
i = 0;
dpn = prop->src_dpn_prop;
addr = prop->source_ports;
for_each_set_bit(bit, &addr, 32) {
dpn[i].num = bit;
dpn[i].type = SDW_DPN_FULL;
dpn[i].simple_ch_prep_sm = true;
dpn[i].ch_prep_timeout = 10;
i++;
}
/* do this again for sink now */
nval = hweight32(prop->sink_ports);
num_of_ports += nval;
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
if (!prop->sink_dpn_prop)
return -ENOMEM;
i = 0;
dpn = prop->sink_dpn_prop;
addr = prop->sink_ports;
for_each_set_bit(bit, &addr, 32) {
dpn[i].num = bit;
dpn[i].type = SDW_DPN_FULL;
dpn[i].simple_ch_prep_sm = true;
dpn[i].ch_prep_timeout = 10;
i++;
}
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
/* set the timeout values */
prop->clk_stop_timeout = 20;
/* wake-up event */
prop->wake_capable = 1;
return 0;
}
/* Bus clock frequency */
#define RT5682_CLK_FREQ_9600000HZ 9600000
#define RT5682_CLK_FREQ_12000000HZ 12000000
#define RT5682_CLK_FREQ_6000000HZ 6000000
#define RT5682_CLK_FREQ_4800000HZ 4800000
#define RT5682_CLK_FREQ_2400000HZ 2400000
#define RT5682_CLK_FREQ_12288000HZ 12288000
static int rt5682_clock_config(struct device *dev)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
unsigned int clk_freq, value;
clk_freq = (rt5682->params.curr_dr_freq >> 1);
switch (clk_freq) {
case RT5682_CLK_FREQ_12000000HZ:
value = 0x0;
break;
case RT5682_CLK_FREQ_6000000HZ:
value = 0x1;
break;
case RT5682_CLK_FREQ_9600000HZ:
value = 0x2;
break;
case RT5682_CLK_FREQ_4800000HZ:
value = 0x3;
break;
case RT5682_CLK_FREQ_2400000HZ:
value = 0x4;
break;
case RT5682_CLK_FREQ_12288000HZ:
value = 0x5;
break;
default:
return -EINVAL;
}
regmap_write(rt5682->sdw_regmap, 0xe0, value);
regmap_write(rt5682->sdw_regmap, 0xf0, value);
dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq);
return 0;
}
static int rt5682_bus_config(struct sdw_slave *slave,
struct sdw_bus_params *params)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
int ret;
memcpy(&rt5682->params, params, sizeof(*params));
ret = rt5682_clock_config(&slave->dev);
if (ret < 0)
dev_err(&slave->dev, "Invalid clk config");
return ret;
}
static int rt5682_interrupt_callback(struct sdw_slave *slave,
struct sdw_slave_intr_status *status)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
if (status->control_port & 0x4) {
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, msecs_to_jiffies(250));
}
return 0;
}
static struct sdw_slave_ops rt5682_slave_ops = {
.read_prop = rt5682_read_prop,
.interrupt_callback = rt5682_interrupt_callback,
.update_status = rt5682_update_status,
.bus_config = rt5682_bus_config,
};
static int rt5682_sdw_probe(struct sdw_slave *slave,
const struct sdw_device_id *id)
{
struct regmap *regmap;
/* Assign ops */
slave->ops = &rt5682_slave_ops;
/* Regmap Initialization */
regmap = devm_regmap_init_sdw(slave, &rt5682_sdw_regmap);
if (IS_ERR(regmap))
return -EINVAL;
rt5682_sdw_init(&slave->dev, regmap, slave);
return 0;
}
static int rt5682_sdw_remove(struct sdw_slave *slave)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
if (rt5682 && rt5682->hw_init)
cancel_delayed_work(&rt5682->jack_detect_work);
return 0;
}
static const struct sdw_device_id rt5682_id[] = {
SDW_SLAVE_ENTRY(0x025d, 0x5682, 0),
{},
};
MODULE_DEVICE_TABLE(sdw, rt5682_id);
static int __maybe_unused rt5682_dev_suspend(struct device *dev)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
if (!rt5682->hw_init)
return 0;
regcache_cache_only(rt5682->regmap, true);
regcache_mark_dirty(rt5682->regmap);
return 0;
}
static int __maybe_unused rt5682_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
unsigned long time;
if (!rt5682->hw_init)
return 0;
if (!slave->unattach_request)
goto regmap_sync;
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT5682_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
return -ETIMEDOUT;
}
regmap_sync:
slave->unattach_request = 0;
regcache_cache_only(rt5682->regmap, false);
regcache_sync(rt5682->regmap);
return 0;
}
static const struct dev_pm_ops rt5682_pm = {
SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume)
SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL)
};
static struct sdw_driver rt5682_sdw_driver = {
.driver = {
.name = "rt5682",
.owner = THIS_MODULE,
.pm = &rt5682_pm,
},
.probe = rt5682_sdw_probe,
.remove = rt5682_sdw_remove,
.ops = &rt5682_slave_ops,
.id_table = rt5682_id,
};
module_sdw_driver(rt5682_sdw_driver);
MODULE_DESCRIPTION("ASoC RT5682 driver SDW");
MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* rt5682-sdw.h -- RT5682 SDW ALSA SoC audio driver
*
* Copyright 2019 Realtek Semiconductor Corp.
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
#ifndef __RT5682_SDW_H__
#define __RT5682_SDW_H__
#define RT5682_SDW_ADDR_L 0x3000
#define RT5682_SDW_ADDR_H 0x3001
#define RT5682_SDW_DATA_L 0x3004
#define RT5682_SDW_DATA_H 0x3005
#define RT5682_SDW_CMD 0x3008
#define RT5682_PROBE_TIMEOUT 2000
#endif /* __RT5682_SDW_H__ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше