Merge branch 'asoc-5.7' into asoc-next
This commit is contained in:
Коммит
1c521d7e62
|
@ -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 = <&>;
|
||||
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 = <®_audio>;
|
||||
VD-supply = <®_audio>;
|
||||
VA-supply = <®_audio>;
|
||||
VAHP-supply = <®_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 = <®_audio>;
|
||||
VD-supply = <®_audio>;
|
||||
VA-supply = <®_audio>;
|
||||
VAHP-supply = <®_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__ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче