mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
ASoC: rsnd: Add RZ/G3E audio driver support
John Madieu <john.madieu.xa@bp.renesas.com> says:
Add audio support for the Renesas RZ/G3E SoC to the R-Car Sound
driver. The RZ/G3E audio subsystem is based on R-Car Sound IP but
has several differences requiring dedicated handling:
- SSI operates exclusively in BUSIF mode (no PIO)
- 2-4 BUSIF channels per SSI (layout differs from R-Car)
- Separate register regions for SCU, ADG, SSIU, SSI accessed by name
- Per-SSI ADG and SSIF supply clocks
- Dedicated audmapp clock/reset for Audio DMAC peri-peri
- Per-SSI and per-module reset controllers via CPG
- Unprefixed DT sub-node names (ssi, ssiu, src, ...) instead of
rcar_sound,xxx
- Hyphenated indexed clock/reset names (ssi-0, src-0, adg-ssi-0,
audio-clka, ...) instead of the legacy dotted form
Link: https://patch.msgid.link/20260525110230.4014435-1-john.madieu.xa@bp.renesas.com
This commit is contained in:
commit
debea6d6bc
|
|
@ -0,0 +1,800 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/renesas,r9a09g047-sound.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/G3E Sound Controller
|
||||
|
||||
maintainers:
|
||||
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
- John Madieu <john.madieu.xa@bp.renesas.com>
|
||||
|
||||
description:
|
||||
The RZ/G3E (R9A09G047) sound controller is based on R-Car Sound IP
|
||||
with extended DMA channel support (up to 5 DMACs per direction),
|
||||
additional clock domains (47 clocks including per-SSI ADG clocks),
|
||||
and additional reset lines (14 including SCU, ADG and Audio DMAC
|
||||
peri-peri resets). SSI operates exclusively in BUSIF mode with
|
||||
2-4 BUSIF channels per SSI.
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: renesas,r9a09g047-sound
|
||||
|
||||
reg:
|
||||
maxItems: 5
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: scu
|
||||
- const: adg
|
||||
- const: ssiu
|
||||
- const: ssi
|
||||
- const: audmapp
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 47
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ssi-all
|
||||
- const: ssi-0
|
||||
- const: ssi-1
|
||||
- const: ssi-2
|
||||
- const: ssi-3
|
||||
- const: ssi-4
|
||||
- const: ssi-5
|
||||
- const: ssi-6
|
||||
- const: ssi-7
|
||||
- const: ssi-8
|
||||
- const: ssi-9
|
||||
- const: src-0
|
||||
- const: src-1
|
||||
- const: src-2
|
||||
- const: src-3
|
||||
- const: src-4
|
||||
- const: src-5
|
||||
- const: src-6
|
||||
- const: src-7
|
||||
- const: src-8
|
||||
- const: src-9
|
||||
- const: mix-0
|
||||
- const: mix-1
|
||||
- const: ctu-0
|
||||
- const: ctu-1
|
||||
- const: dvc-0
|
||||
- const: dvc-1
|
||||
- const: audio-clka
|
||||
- const: audio-clkb
|
||||
- const: audio-clkc
|
||||
- const: audio-clki
|
||||
- const: ssif_supply
|
||||
- const: scu
|
||||
- const: scu_x2
|
||||
- const: scu_supply
|
||||
- const: adg-ssi-0
|
||||
- const: adg-ssi-1
|
||||
- const: adg-ssi-2
|
||||
- const: adg-ssi-3
|
||||
- const: adg-ssi-4
|
||||
- const: adg-ssi-5
|
||||
- const: adg-ssi-6
|
||||
- const: adg-ssi-7
|
||||
- const: adg-ssi-8
|
||||
- const: adg-ssi-9
|
||||
- const: audmapp
|
||||
- const: adg
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 14
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: ssi-all
|
||||
- const: ssi-0
|
||||
- const: ssi-1
|
||||
- const: ssi-2
|
||||
- const: ssi-3
|
||||
- const: ssi-4
|
||||
- const: ssi-5
|
||||
- const: ssi-6
|
||||
- const: ssi-7
|
||||
- const: ssi-8
|
||||
- const: ssi-9
|
||||
- const: scu
|
||||
- const: adg
|
||||
- const: audmapp
|
||||
|
||||
dvc:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^dvc-[0-1]$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
dmas:
|
||||
maxItems: 5
|
||||
description:
|
||||
List of references to DMA specifiers, one per DMA
|
||||
controller, all for the transmission direction
|
||||
(DVC is playback-only). The dma-engine core falls
|
||||
through the list to find a free channel.
|
||||
|
||||
dma-names:
|
||||
maxItems: 5
|
||||
allOf:
|
||||
- items:
|
||||
enum:
|
||||
- tx
|
||||
|
||||
required:
|
||||
- dmas
|
||||
- dma-names
|
||||
|
||||
mix:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description:
|
||||
Per-channel Mixer (MIX) sub-nodes. Each mix-N node has no
|
||||
properties of its own. It exists so the driver can enumerate
|
||||
the MIX instances and so that DT labels can be attached to it
|
||||
for the dai/playback/capture phandle routing arrays.
|
||||
|
||||
patternProperties:
|
||||
"^mix-[0-1]$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
ctu:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description:
|
||||
Per-channel Channel Transfer Unit (CTU) sub-nodes. Each ctu-N
|
||||
node has no properties of its own. It exists so the driver
|
||||
can enumerate the CTU instances and so that DT labels can be
|
||||
attached to it for the dai/playback/capture phandle routing arrays.
|
||||
|
||||
patternProperties:
|
||||
"^ctu-[0-7]$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
src:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^src-[0-9]$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
maxItems: 10
|
||||
description:
|
||||
Must contain a list of pairs of references to DMA
|
||||
specifiers, one for transmission and one for reception,
|
||||
repeated for each DMA controller. The dma-engine core
|
||||
falls through the list to find a free channel.
|
||||
|
||||
dma-names:
|
||||
maxItems: 10
|
||||
allOf:
|
||||
- items:
|
||||
enum:
|
||||
- tx
|
||||
- rx
|
||||
|
||||
ssiu:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^ssiu-[0-9]+$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
dmas:
|
||||
maxItems: 10
|
||||
description:
|
||||
Must contain a list of pairs of references to DMA
|
||||
specifiers, one for transmission and one for reception,
|
||||
repeated for each DMA controller. The dma-engine core
|
||||
falls through the list to find a free channel.
|
||||
|
||||
dma-names:
|
||||
maxItems: 10
|
||||
allOf:
|
||||
- items:
|
||||
enum:
|
||||
- tx
|
||||
- rx
|
||||
|
||||
required:
|
||||
- dmas
|
||||
- dma-names
|
||||
|
||||
ssi:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^ssi-[0-9]$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
shared-pin:
|
||||
description: Shared clock pin.
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
required:
|
||||
- interrupts
|
||||
|
||||
ports:
|
||||
$ref: audio-graph-port.yaml#/definitions/port-base
|
||||
unevaluatedProperties: false
|
||||
patternProperties:
|
||||
'^port@[0-9a-f]+$':
|
||||
$ref: audio-graph-port.yaml#/definitions/port-base
|
||||
unevaluatedProperties: false
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
endpoint:
|
||||
$ref: audio-graph-port.yaml#/definitions/endpoint-base
|
||||
unevaluatedProperties: false
|
||||
properties:
|
||||
playback:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description:
|
||||
Ordered list of phandles to the in-SoC modules used
|
||||
by this DAI in the playback direction. Each phandle
|
||||
must reference one of the ssi-N, src-N, ctu-N,
|
||||
mix-N or dvc-N sub-nodes of the parent sound
|
||||
controller. The list order is the pipeline order
|
||||
from CPU to off-SoC endpoint.
|
||||
capture:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description:
|
||||
Ordered list of phandles to the in-SoC modules used
|
||||
by this DAI in the capture direction. Each phandle
|
||||
must reference one of the ssi-N, src-N, ctu-N,
|
||||
mix-N or dvc-N sub-nodes of the parent sound
|
||||
controller. The list order is the pipeline order
|
||||
from off-SoC endpoint to CPU.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- "#sound-dai-cells"
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
sound@13c00000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#clock-cells = <0>;
|
||||
compatible = "renesas,r9a09g047-sound";
|
||||
reg = <0x13c00000 0x10000>,
|
||||
<0x13c20000 0x10000>,
|
||||
<0x13c30000 0x1000>,
|
||||
<0x13c31000 0x1f000>,
|
||||
<0x13c50000 0x10000>;
|
||||
reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
|
||||
clocks = <&cpg 245>,
|
||||
<&cpg 385>, <&cpg 386>,
|
||||
<&cpg 387>, <&cpg 388>,
|
||||
<&cpg 389>, <&cpg 390>,
|
||||
<&cpg 391>, <&cpg 392>,
|
||||
<&cpg 393>, <&cpg 394>,
|
||||
<&cpg 372>, <&cpg 373>,
|
||||
<&cpg 374>, <&cpg 375>,
|
||||
<&cpg 376>, <&cpg 377>,
|
||||
<&cpg 378>, <&cpg 379>,
|
||||
<&cpg 380>, <&cpg 381>,
|
||||
<&cpg 370>, <&cpg 371>,
|
||||
<&cpg 370>, <&cpg 371>,
|
||||
<&cpg 368>, <&cpg 369>,
|
||||
<&cpg 251>, <&cpg 252>,
|
||||
<&cpg 253>, <&cpg 250>,
|
||||
<&cpg 384>,
|
||||
<&cpg 246>, <&cpg 247>,
|
||||
<&cpg 382>,
|
||||
<&cpg 352>, <&cpg 353>,
|
||||
<&cpg 354>, <&cpg 355>,
|
||||
<&cpg 356>, <&cpg 357>,
|
||||
<&cpg 358>, <&cpg 359>,
|
||||
<&cpg 360>, <&cpg 361>,
|
||||
<&cpg 248>, <&cpg 249>;
|
||||
clock-names = "ssi-all",
|
||||
"ssi-0", "ssi-1",
|
||||
"ssi-2", "ssi-3",
|
||||
"ssi-4", "ssi-5",
|
||||
"ssi-6", "ssi-7",
|
||||
"ssi-8", "ssi-9",
|
||||
"src-0", "src-1",
|
||||
"src-2", "src-3",
|
||||
"src-4", "src-5",
|
||||
"src-6", "src-7",
|
||||
"src-8", "src-9",
|
||||
"mix-0", "mix-1",
|
||||
"ctu-0", "ctu-1",
|
||||
"dvc-0", "dvc-1",
|
||||
"audio-clka", "audio-clkb",
|
||||
"audio-clkc", "audio-clki",
|
||||
"ssif_supply",
|
||||
"scu", "scu_x2",
|
||||
"scu_supply",
|
||||
"adg-ssi-0", "adg-ssi-1",
|
||||
"adg-ssi-2", "adg-ssi-3",
|
||||
"adg-ssi-4", "adg-ssi-5",
|
||||
"adg-ssi-6", "adg-ssi-7",
|
||||
"adg-ssi-8", "adg-ssi-9",
|
||||
"audmapp", "adg";
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg 225>,
|
||||
<&cpg 226>, <&cpg 227>,
|
||||
<&cpg 228>, <&cpg 229>,
|
||||
<&cpg 230>, <&cpg 231>,
|
||||
<&cpg 232>, <&cpg 233>,
|
||||
<&cpg 234>, <&cpg 235>,
|
||||
<&cpg 236>, <&cpg 238>, <&cpg 237>;
|
||||
reset-names = "ssi-all",
|
||||
"ssi-0", "ssi-1",
|
||||
"ssi-2", "ssi-3",
|
||||
"ssi-4", "ssi-5",
|
||||
"ssi-6", "ssi-7",
|
||||
"ssi-8", "ssi-9",
|
||||
"scu", "adg",
|
||||
"audmapp";
|
||||
|
||||
ctu {
|
||||
ctu-0 { };
|
||||
ctu-1 { };
|
||||
ctu-2 { };
|
||||
ctu-3 { };
|
||||
ctu-4 { };
|
||||
ctu-5 { };
|
||||
ctu-6 { };
|
||||
ctu-7 { };
|
||||
};
|
||||
|
||||
dvc {
|
||||
dvc0: dvc-0 {
|
||||
dmas = <&dmac0 0x1db3>, <&dmac1 0x1db3>,
|
||||
<&dmac2 0x1db3>, <&dmac3 0x1db3>,
|
||||
<&dmac4 0x1db3>;
|
||||
dma-names = "tx", "tx", "tx", "tx", "tx";
|
||||
};
|
||||
dvc1: dvc-1 {
|
||||
dmas = <&dmac0 0x1db4>, <&dmac1 0x1db4>,
|
||||
<&dmac2 0x1db4>, <&dmac3 0x1db4>,
|
||||
<&dmac4 0x1db4>;
|
||||
dma-names = "tx", "tx", "tx", "tx", "tx";
|
||||
};
|
||||
};
|
||||
|
||||
mix {
|
||||
mix-0 { };
|
||||
mix-1 { };
|
||||
};
|
||||
|
||||
src {
|
||||
src0: src-0 {
|
||||
interrupts = <GIC_SPI 902 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1d9f>, <&dmac0 0x1da9>,
|
||||
<&dmac1 0x1d9f>, <&dmac1 0x1da9>,
|
||||
<&dmac2 0x1d9f>, <&dmac2 0x1da9>,
|
||||
<&dmac3 0x1d9f>, <&dmac3 0x1da9>,
|
||||
<&dmac4 0x1d9f>, <&dmac4 0x1da9>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src1: src-1 {
|
||||
interrupts = <GIC_SPI 903 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da0>, <&dmac0 0x1daa>,
|
||||
<&dmac1 0x1da0>, <&dmac1 0x1daa>,
|
||||
<&dmac2 0x1da0>, <&dmac2 0x1daa>,
|
||||
<&dmac3 0x1da0>, <&dmac3 0x1daa>,
|
||||
<&dmac4 0x1da0>, <&dmac4 0x1daa>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-2 {
|
||||
interrupts = <GIC_SPI 904 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da1>, <&dmac0 0x1dab>,
|
||||
<&dmac1 0x1da1>, <&dmac1 0x1dab>,
|
||||
<&dmac2 0x1da1>, <&dmac2 0x1dab>,
|
||||
<&dmac3 0x1da1>, <&dmac3 0x1dab>,
|
||||
<&dmac4 0x1da1>, <&dmac4 0x1dab>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-3 {
|
||||
interrupts = <GIC_SPI 905 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da2>, <&dmac0 0x1dac>,
|
||||
<&dmac1 0x1da2>, <&dmac1 0x1dac>,
|
||||
<&dmac2 0x1da2>, <&dmac2 0x1dac>,
|
||||
<&dmac3 0x1da2>, <&dmac3 0x1dac>,
|
||||
<&dmac4 0x1da2>, <&dmac4 0x1dac>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-4 {
|
||||
interrupts = <GIC_SPI 906 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da3>, <&dmac0 0x1dad>,
|
||||
<&dmac1 0x1da3>, <&dmac1 0x1dad>,
|
||||
<&dmac2 0x1da3>, <&dmac2 0x1dad>,
|
||||
<&dmac3 0x1da3>, <&dmac3 0x1dad>,
|
||||
<&dmac4 0x1da3>, <&dmac4 0x1dad>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-5 {
|
||||
interrupts = <GIC_SPI 907 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da4>, <&dmac0 0x1dae>,
|
||||
<&dmac1 0x1da4>, <&dmac1 0x1dae>,
|
||||
<&dmac2 0x1da4>, <&dmac2 0x1dae>,
|
||||
<&dmac3 0x1da4>, <&dmac3 0x1dae>,
|
||||
<&dmac4 0x1da4>, <&dmac4 0x1dae>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-6 {
|
||||
interrupts = <GIC_SPI 908 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da5>, <&dmac0 0x1daf>,
|
||||
<&dmac1 0x1da5>, <&dmac1 0x1daf>,
|
||||
<&dmac2 0x1da5>, <&dmac2 0x1daf>,
|
||||
<&dmac3 0x1da5>, <&dmac3 0x1daf>,
|
||||
<&dmac4 0x1da5>, <&dmac4 0x1daf>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-7 {
|
||||
interrupts = <GIC_SPI 909 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da6>, <&dmac0 0x1db0>,
|
||||
<&dmac1 0x1da6>, <&dmac1 0x1db0>,
|
||||
<&dmac2 0x1da6>, <&dmac2 0x1db0>,
|
||||
<&dmac3 0x1da6>, <&dmac3 0x1db0>,
|
||||
<&dmac4 0x1da6>, <&dmac4 0x1db0>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-8 {
|
||||
interrupts = <GIC_SPI 910 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da7>, <&dmac0 0x1db1>,
|
||||
<&dmac1 0x1da7>, <&dmac1 0x1db1>,
|
||||
<&dmac2 0x1da7>, <&dmac2 0x1db1>,
|
||||
<&dmac3 0x1da7>, <&dmac3 0x1db1>,
|
||||
<&dmac4 0x1da7>, <&dmac4 0x1db1>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
src-9 {
|
||||
interrupts = <GIC_SPI 911 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac0 0x1da8>, <&dmac0 0x1db2>,
|
||||
<&dmac1 0x1da8>, <&dmac1 0x1db2>,
|
||||
<&dmac2 0x1da8>, <&dmac2 0x1db2>,
|
||||
<&dmac3 0x1da8>, <&dmac3 0x1db2>,
|
||||
<&dmac4 0x1da8>, <&dmac4 0x1db2>;
|
||||
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
|
||||
"rx", "tx", "rx", "tx";
|
||||
};
|
||||
};
|
||||
|
||||
ssi {
|
||||
ssi-0 {
|
||||
interrupts = <GIC_SPI 889 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi-1 {
|
||||
interrupts = <GIC_SPI 890 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi-2 {
|
||||
interrupts = <GIC_SPI 891 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi3: ssi-3 {
|
||||
interrupts = <GIC_SPI 892 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi4: ssi-4 {
|
||||
interrupts = <GIC_SPI 893 IRQ_TYPE_LEVEL_HIGH>;
|
||||
shared-pin;
|
||||
};
|
||||
ssi-5 {
|
||||
interrupts = <GIC_SPI 894 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi-6 {
|
||||
interrupts = <GIC_SPI 895 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi-7 {
|
||||
interrupts = <GIC_SPI 896 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi-8 {
|
||||
interrupts = <GIC_SPI 897 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
ssi-9 {
|
||||
interrupts = <GIC_SPI 898 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
ssiu {
|
||||
ssiu-0 {
|
||||
dmas = <&dmac0 0x1d61>, <&dmac0 0x1d62>,
|
||||
<&dmac1 0x1d61>, <&dmac1 0x1d62>,
|
||||
<&dmac2 0x1d61>, <&dmac2 0x1d62>,
|
||||
<&dmac3 0x1d61>, <&dmac3 0x1d62>,
|
||||
<&dmac4 0x1d61>, <&dmac4 0x1d62>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-1 {
|
||||
dmas = <&dmac0 0x1d63>, <&dmac0 0x1d64>,
|
||||
<&dmac1 0x1d63>, <&dmac1 0x1d64>,
|
||||
<&dmac2 0x1d63>, <&dmac2 0x1d64>,
|
||||
<&dmac3 0x1d63>, <&dmac3 0x1d64>,
|
||||
<&dmac4 0x1d63>, <&dmac4 0x1d64>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-2 {
|
||||
dmas = <&dmac0 0x1d65>, <&dmac0 0x1d66>,
|
||||
<&dmac1 0x1d65>, <&dmac1 0x1d66>,
|
||||
<&dmac2 0x1d65>, <&dmac2 0x1d66>,
|
||||
<&dmac3 0x1d65>, <&dmac3 0x1d66>,
|
||||
<&dmac4 0x1d65>, <&dmac4 0x1d66>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-3 {
|
||||
dmas = <&dmac0 0x1d67>, <&dmac0 0x1d68>,
|
||||
<&dmac1 0x1d67>, <&dmac1 0x1d68>,
|
||||
<&dmac2 0x1d67>, <&dmac2 0x1d68>,
|
||||
<&dmac3 0x1d67>, <&dmac3 0x1d68>,
|
||||
<&dmac4 0x1d67>, <&dmac4 0x1d68>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-4 {
|
||||
dmas = <&dmac0 0x1d69>, <&dmac0 0x1d6a>,
|
||||
<&dmac1 0x1d69>, <&dmac1 0x1d6a>,
|
||||
<&dmac2 0x1d69>, <&dmac2 0x1d6a>,
|
||||
<&dmac3 0x1d69>, <&dmac3 0x1d6a>,
|
||||
<&dmac4 0x1d69>, <&dmac4 0x1d6a>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-5 {
|
||||
dmas = <&dmac0 0x1d6b>, <&dmac0 0x1d6c>,
|
||||
<&dmac1 0x1d6b>, <&dmac1 0x1d6c>,
|
||||
<&dmac2 0x1d6b>, <&dmac2 0x1d6c>,
|
||||
<&dmac3 0x1d6b>, <&dmac3 0x1d6c>,
|
||||
<&dmac4 0x1d6b>, <&dmac4 0x1d6c>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-6 {
|
||||
dmas = <&dmac0 0x1d6d>, <&dmac0 0x1d6e>,
|
||||
<&dmac1 0x1d6d>, <&dmac1 0x1d6e>,
|
||||
<&dmac2 0x1d6d>, <&dmac2 0x1d6e>,
|
||||
<&dmac3 0x1d6d>, <&dmac3 0x1d6e>,
|
||||
<&dmac4 0x1d6d>, <&dmac4 0x1d6e>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-7 {
|
||||
dmas = <&dmac0 0x1d6f>, <&dmac0 0x1d70>,
|
||||
<&dmac1 0x1d6f>, <&dmac1 0x1d70>,
|
||||
<&dmac2 0x1d6f>, <&dmac2 0x1d70>,
|
||||
<&dmac3 0x1d6f>, <&dmac3 0x1d70>,
|
||||
<&dmac4 0x1d6f>, <&dmac4 0x1d70>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-8 {
|
||||
dmas = <&dmac0 0x1d71>, <&dmac0 0x1d72>,
|
||||
<&dmac1 0x1d71>, <&dmac1 0x1d72>,
|
||||
<&dmac2 0x1d71>, <&dmac2 0x1d72>,
|
||||
<&dmac3 0x1d71>, <&dmac3 0x1d72>,
|
||||
<&dmac4 0x1d71>, <&dmac4 0x1d72>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-9 {
|
||||
dmas = <&dmac0 0x1d73>, <&dmac0 0x1d74>,
|
||||
<&dmac1 0x1d73>, <&dmac1 0x1d74>,
|
||||
<&dmac2 0x1d73>, <&dmac2 0x1d74>,
|
||||
<&dmac3 0x1d73>, <&dmac3 0x1d74>,
|
||||
<&dmac4 0x1d73>, <&dmac4 0x1d74>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-10 {
|
||||
dmas = <&dmac0 0x1d75>, <&dmac0 0x1d76>,
|
||||
<&dmac1 0x1d75>, <&dmac1 0x1d76>,
|
||||
<&dmac2 0x1d75>, <&dmac2 0x1d76>,
|
||||
<&dmac3 0x1d75>, <&dmac3 0x1d76>,
|
||||
<&dmac4 0x1d75>, <&dmac4 0x1d76>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-11 {
|
||||
dmas = <&dmac0 0x1d77>, <&dmac0 0x1d78>,
|
||||
<&dmac1 0x1d77>, <&dmac1 0x1d78>,
|
||||
<&dmac2 0x1d77>, <&dmac2 0x1d78>,
|
||||
<&dmac3 0x1d77>, <&dmac3 0x1d78>,
|
||||
<&dmac4 0x1d77>, <&dmac4 0x1d78>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-12 {
|
||||
dmas = <&dmac0 0x1d79>, <&dmac0 0x1d7a>,
|
||||
<&dmac1 0x1d79>, <&dmac1 0x1d7a>,
|
||||
<&dmac2 0x1d79>, <&dmac2 0x1d7a>,
|
||||
<&dmac3 0x1d79>, <&dmac3 0x1d7a>,
|
||||
<&dmac4 0x1d79>, <&dmac4 0x1d7a>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-13 {
|
||||
dmas = <&dmac0 0x1d7b>, <&dmac0 0x1d7c>,
|
||||
<&dmac1 0x1d7b>, <&dmac1 0x1d7c>,
|
||||
<&dmac2 0x1d7b>, <&dmac2 0x1d7c>,
|
||||
<&dmac3 0x1d7b>, <&dmac3 0x1d7c>,
|
||||
<&dmac4 0x1d7b>, <&dmac4 0x1d7c>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-14 {
|
||||
dmas = <&dmac0 0x1d7d>, <&dmac0 0x1d7e>,
|
||||
<&dmac1 0x1d7d>, <&dmac1 0x1d7e>,
|
||||
<&dmac2 0x1d7d>, <&dmac2 0x1d7e>,
|
||||
<&dmac3 0x1d7d>, <&dmac3 0x1d7e>,
|
||||
<&dmac4 0x1d7d>, <&dmac4 0x1d7e>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-15 {
|
||||
dmas = <&dmac0 0x1d7f>, <&dmac0 0x1d80>,
|
||||
<&dmac1 0x1d7f>, <&dmac1 0x1d80>,
|
||||
<&dmac2 0x1d7f>, <&dmac2 0x1d80>,
|
||||
<&dmac3 0x1d7f>, <&dmac3 0x1d80>,
|
||||
<&dmac4 0x1d7f>, <&dmac4 0x1d80>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-16 {
|
||||
dmas = <&dmac0 0x1d81>, <&dmac0 0x1d82>,
|
||||
<&dmac1 0x1d81>, <&dmac1 0x1d82>,
|
||||
<&dmac2 0x1d81>, <&dmac2 0x1d82>,
|
||||
<&dmac3 0x1d81>, <&dmac3 0x1d82>,
|
||||
<&dmac4 0x1d81>, <&dmac4 0x1d82>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-17 {
|
||||
dmas = <&dmac0 0x1d83>, <&dmac0 0x1d84>,
|
||||
<&dmac1 0x1d83>, <&dmac1 0x1d84>,
|
||||
<&dmac2 0x1d83>, <&dmac2 0x1d84>,
|
||||
<&dmac3 0x1d83>, <&dmac3 0x1d84>,
|
||||
<&dmac4 0x1d83>, <&dmac4 0x1d84>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-18 {
|
||||
dmas = <&dmac0 0x1d85>, <&dmac0 0x1d86>,
|
||||
<&dmac1 0x1d85>, <&dmac1 0x1d86>,
|
||||
<&dmac2 0x1d85>, <&dmac2 0x1d86>,
|
||||
<&dmac3 0x1d85>, <&dmac3 0x1d86>,
|
||||
<&dmac4 0x1d85>, <&dmac4 0x1d86>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-19 {
|
||||
dmas = <&dmac0 0x1d87>, <&dmac0 0x1d88>,
|
||||
<&dmac1 0x1d87>, <&dmac1 0x1d88>,
|
||||
<&dmac2 0x1d87>, <&dmac2 0x1d88>,
|
||||
<&dmac3 0x1d87>, <&dmac3 0x1d88>,
|
||||
<&dmac4 0x1d87>, <&dmac4 0x1d88>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-20 {
|
||||
dmas = <&dmac0 0x1d89>, <&dmac0 0x1d8a>,
|
||||
<&dmac1 0x1d89>, <&dmac1 0x1d8a>,
|
||||
<&dmac2 0x1d89>, <&dmac2 0x1d8a>,
|
||||
<&dmac3 0x1d89>, <&dmac3 0x1d8a>,
|
||||
<&dmac4 0x1d89>, <&dmac4 0x1d8a>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-21 {
|
||||
dmas = <&dmac0 0x1d8b>, <&dmac0 0x1d8c>,
|
||||
<&dmac1 0x1d8b>, <&dmac1 0x1d8c>,
|
||||
<&dmac2 0x1d8b>, <&dmac2 0x1d8c>,
|
||||
<&dmac3 0x1d8b>, <&dmac3 0x1d8c>,
|
||||
<&dmac4 0x1d8b>, <&dmac4 0x1d8c>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-22 {
|
||||
dmas = <&dmac0 0x1d8d>, <&dmac0 0x1d8e>,
|
||||
<&dmac1 0x1d8d>, <&dmac1 0x1d8e>,
|
||||
<&dmac2 0x1d8d>, <&dmac2 0x1d8e>,
|
||||
<&dmac3 0x1d8d>, <&dmac3 0x1d8e>,
|
||||
<&dmac4 0x1d8d>, <&dmac4 0x1d8e>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-23 {
|
||||
dmas = <&dmac0 0x1d8f>, <&dmac0 0x1d90>,
|
||||
<&dmac1 0x1d8f>, <&dmac1 0x1d90>,
|
||||
<&dmac2 0x1d8f>, <&dmac2 0x1d90>,
|
||||
<&dmac3 0x1d8f>, <&dmac3 0x1d90>,
|
||||
<&dmac4 0x1d8f>, <&dmac4 0x1d90>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-24 {
|
||||
dmas = <&dmac0 0x1d91>, <&dmac0 0x1d92>,
|
||||
<&dmac1 0x1d91>, <&dmac1 0x1d92>,
|
||||
<&dmac2 0x1d91>, <&dmac2 0x1d92>,
|
||||
<&dmac3 0x1d91>, <&dmac3 0x1d92>,
|
||||
<&dmac4 0x1d91>, <&dmac4 0x1d92>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-25 {
|
||||
dmas = <&dmac0 0x1d93>, <&dmac0 0x1d94>,
|
||||
<&dmac1 0x1d93>, <&dmac1 0x1d94>,
|
||||
<&dmac2 0x1d93>, <&dmac2 0x1d94>,
|
||||
<&dmac3 0x1d93>, <&dmac3 0x1d94>,
|
||||
<&dmac4 0x1d93>, <&dmac4 0x1d94>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-26 {
|
||||
dmas = <&dmac0 0x1d95>, <&dmac0 0x1d96>,
|
||||
<&dmac1 0x1d95>, <&dmac1 0x1d96>,
|
||||
<&dmac2 0x1d95>, <&dmac2 0x1d96>,
|
||||
<&dmac3 0x1d95>, <&dmac3 0x1d96>,
|
||||
<&dmac4 0x1d95>, <&dmac4 0x1d96>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
ssiu-27 {
|
||||
dmas = <&dmac0 0x1d97>, <&dmac0 0x1d98>,
|
||||
<&dmac1 0x1d97>, <&dmac1 0x1d98>,
|
||||
<&dmac2 0x1d97>, <&dmac2 0x1d98>,
|
||||
<&dmac3 0x1d97>, <&dmac3 0x1d98>,
|
||||
<&dmac4 0x1d97>, <&dmac4 0x1d98>;
|
||||
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
|
||||
};
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
rsnd_endpoint0: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
dai-format = "i2s";
|
||||
bitclock-master = <&rsnd_endpoint0>;
|
||||
frame-master = <&rsnd_endpoint0>;
|
||||
playback = <&ssi3>, <&src1>, <&dvc1>;
|
||||
capture = <&ssi4>, <&src0>, <&dvc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -19,6 +19,9 @@
|
|||
#define CLKOUT3 3
|
||||
#define CLKOUTMAX 4
|
||||
|
||||
/* Maximum SSI count for per-SSI clocks */
|
||||
#define ADG_SSI_MAX 10
|
||||
|
||||
#define BRGCKR_31 (1 << 31)
|
||||
#define BRRx_MASK(x) (0x3FF & x)
|
||||
|
||||
|
|
@ -34,10 +37,14 @@ struct rsnd_adg {
|
|||
struct clk *adg;
|
||||
struct clk *clkin[CLKINMAX];
|
||||
struct clk *clkout[CLKOUTMAX];
|
||||
/* RZ/G3E: per-SSI ADG clocks (adg-ssi-0 through adg-ssi-9) */
|
||||
struct clk *clk_adg_ssi[ADG_SSI_MAX];
|
||||
struct clk *clk_ssif_supply;
|
||||
struct clk *null_clk;
|
||||
struct clk_onecell_data onecell;
|
||||
struct rsnd_mod mod;
|
||||
int clkin_rate[CLKINMAX];
|
||||
bool ssi_clk_prepared;
|
||||
int clkin_size;
|
||||
int clkout_size;
|
||||
u32 ckr;
|
||||
|
|
@ -70,6 +77,13 @@ static const char * const clkin_name_gen2[] = {
|
|||
[CLKI] = "clk_i",
|
||||
};
|
||||
|
||||
static const char * const clkin_name_rzg3e[] = {
|
||||
[CLKA] = "audio-clka",
|
||||
[CLKB] = "audio-clkb",
|
||||
[CLKC] = "audio-clkc",
|
||||
[CLKI] = "audio-clki",
|
||||
};
|
||||
|
||||
static const char * const clkout_name_gen2[] = {
|
||||
[CLKOUT] = "audio_clkout",
|
||||
[CLKOUT1] = "audio_clkout1",
|
||||
|
|
@ -343,8 +357,16 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
|
|||
|
||||
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
int id = rsnd_mod_id(ssi_mod);
|
||||
|
||||
rsnd_adg_set_ssi_clk(ssi_mod, 0);
|
||||
|
||||
/* RZ/G3E: only disable here, unprepare is done in hw_free */
|
||||
clk_disable(adg->clk_adg_ssi[id]);
|
||||
clk_disable(adg->clk_ssif_supply);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +376,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
|
|||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
|
||||
int data;
|
||||
int id = rsnd_mod_id(ssi_mod);
|
||||
int ret, data;
|
||||
u32 ckr = 0;
|
||||
|
||||
data = rsnd_adg_clk_query(priv, rate);
|
||||
|
|
@ -376,9 +399,63 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
|
|||
(ckr) ? adg->brg_rate[ADG_HZ_48] :
|
||||
adg->brg_rate[ADG_HZ_441]);
|
||||
|
||||
/*
|
||||
* RZ/G3E: enable per-SSI and supply clocks
|
||||
*/
|
||||
ret = clk_enable(adg->clk_adg_ssi[id]);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot enable adg-ssi-%d ADG clock\n", id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_enable(adg->clk_ssif_supply);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot enable SSIF supply clock\n");
|
||||
clk_disable(adg->clk_adg_ssi[id]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_adg_ssi_clk_prepare(struct rsnd_adg *adg)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (adg->ssi_clk_prepared)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ADG_SSI_MAX; i++) {
|
||||
ret = clk_prepare(adg->clk_adg_ssi[i]);
|
||||
if (ret)
|
||||
goto unwind;
|
||||
}
|
||||
ret = clk_prepare(adg->clk_ssif_supply);
|
||||
if (ret)
|
||||
goto unwind;
|
||||
|
||||
adg->ssi_clk_prepared = true;
|
||||
return 0;
|
||||
|
||||
unwind:
|
||||
while (i--)
|
||||
clk_unprepare(adg->clk_adg_ssi[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rsnd_adg_ssi_clk_unprepare(struct rsnd_adg *adg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!adg->ssi_clk_prepared)
|
||||
return;
|
||||
adg->ssi_clk_prepared = false;
|
||||
|
||||
clk_unprepare(adg->clk_ssif_supply);
|
||||
for (i = 0; i < ADG_SSI_MAX; i++)
|
||||
clk_unprepare(adg->clk_adg_ssi[i]);
|
||||
}
|
||||
|
||||
int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
|
||||
{
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
|
|
@ -417,6 +494,28 @@ int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rsnd_adg_clk_enable() might return error (_disable() will not).
|
||||
* We need to rollback in such case
|
||||
*/
|
||||
/*
|
||||
* RZ/G3E per-SSI ADG and SSIF supply clocks.
|
||||
*
|
||||
* Follow the same style as for_each_rsnd_clkin() above: on enable,
|
||||
* try to prepare every clock and accumulate the error. On disable,
|
||||
* unprepare every clock. Absent optional clocks are NULL, for
|
||||
* which clk_prepare() and clk_unprepare() are no-ops.
|
||||
*/
|
||||
if (enable) {
|
||||
int sub_ret = rsnd_adg_ssi_clk_prepare(adg);
|
||||
|
||||
/* Preserve the first error from the clkin loop above. */
|
||||
if (sub_ret && !ret)
|
||||
ret = sub_ret;
|
||||
} else {
|
||||
rsnd_adg_ssi_clk_unprepare(adg);
|
||||
}
|
||||
|
||||
/*
|
||||
* rsnd_adg_clk_enable() might return error (_disable() will not).
|
||||
* We need to rollback in such case
|
||||
|
|
@ -482,6 +581,9 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
|
|||
if (rsnd_is_gen4(priv)) {
|
||||
clkin_name = clkin_name_gen4;
|
||||
clkin_size = ARRAY_SIZE(clkin_name_gen4);
|
||||
} else if (rsnd_is_rzg3e(priv)) {
|
||||
clkin_name = clkin_name_rzg3e;
|
||||
clkin_size = ARRAY_SIZE(clkin_name_rzg3e);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -769,8 +871,34 @@ void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
|
|||
#define rsnd_adg_clk_dbg_info(priv, m)
|
||||
#endif
|
||||
|
||||
static int rsnd_adg_get_ssi_clks(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
char name[16];
|
||||
int i;
|
||||
|
||||
/* SSIF supply clock */
|
||||
adg->clk_ssif_supply = devm_clk_get_optional(dev, "ssif_supply");
|
||||
if (IS_ERR(adg->clk_ssif_supply))
|
||||
return dev_err_probe(dev, PTR_ERR(adg->clk_ssif_supply),
|
||||
"failed to get ssif_supply clock\n");
|
||||
|
||||
/* Per-SSI ADG clocks (RZ/G3E-only; no legacy dotted form exists) */
|
||||
for (i = 0; i < ADG_SSI_MAX; i++) {
|
||||
snprintf(name, sizeof(name), "adg-ssi-%d", i);
|
||||
adg->clk_adg_ssi[i] = devm_clk_get_optional(dev, name);
|
||||
if (IS_ERR(adg->clk_adg_ssi[i]))
|
||||
return dev_err_probe(dev, PTR_ERR(adg->clk_adg_ssi[i]),
|
||||
"failed to get %s clock\n", name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsnd_adg_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct reset_control *rstc;
|
||||
struct rsnd_adg *adg;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int ret;
|
||||
|
|
@ -779,8 +907,11 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
|
|||
if (!adg)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
|
||||
NULL, 0, 0);
|
||||
rstc = devm_reset_control_get_optional_exclusive(dev, "adg");
|
||||
if (IS_ERR(rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(rstc), "failed to get adg reset\n");
|
||||
|
||||
ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, NULL, rstc, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -794,6 +925,11 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* RZ/G3E-specific: per-SSI ADG and SSIF supply clocks */
|
||||
ret = rsnd_adg_get_ssi_clks(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rsnd_adg_clk_enable(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -817,3 +953,29 @@ void rsnd_adg_remove(struct rsnd_priv *priv)
|
|||
/* It should be called after rsnd_adg_clk_disable() */
|
||||
rsnd_adg_null_clk_clean(priv);
|
||||
}
|
||||
|
||||
static struct rsnd_mod *rsnd_adg_mod_get(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
|
||||
if (!adg)
|
||||
return NULL;
|
||||
|
||||
return rsnd_mod_get(adg);
|
||||
}
|
||||
|
||||
void rsnd_adg_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_adg_mod_get(priv);
|
||||
|
||||
if (mod)
|
||||
rsnd_suspend_clk_reset(mod->clk, mod->rstc);
|
||||
}
|
||||
|
||||
void rsnd_adg_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_adg_mod_get(priv);
|
||||
|
||||
if (mod)
|
||||
rsnd_resume_clk_reset(mod->clk, mod->rstc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
|
|||
|
||||
for_each_rsnd_cmd(cmd, priv, i) {
|
||||
int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
|
||||
&rsnd_cmd_ops, NULL,
|
||||
&rsnd_cmd_ops, NULL, NULL,
|
||||
RSND_MOD_CMD, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ static const struct of_device_id rsnd_of_match[] = {
|
|||
{ .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 },
|
||||
/* Special Handling */
|
||||
{ .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) },
|
||||
{ .compatible = "renesas,r9a09g047-sound",
|
||||
.data = (void *)(RSND_RZ3 | RSND_RZG3E | RSND_SSIU_BUSIF_STATUS_COUNT_2) },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rsnd_of_match);
|
||||
|
|
@ -196,18 +198,29 @@ int rsnd_mod_init(struct rsnd_priv *priv,
|
|||
struct rsnd_mod *mod,
|
||||
struct rsnd_mod_ops *ops,
|
||||
struct clk *clk,
|
||||
struct reset_control *rstc,
|
||||
enum rsnd_mod_type type,
|
||||
int id)
|
||||
{
|
||||
int ret = clk_prepare(clk);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_deassert(rstc);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_disable(clk);
|
||||
|
||||
mod->id = id;
|
||||
mod->ops = ops;
|
||||
mod->type = type;
|
||||
mod->clk = clk;
|
||||
mod->rstc = rstc;
|
||||
mod->priv = priv;
|
||||
|
||||
return 0;
|
||||
|
|
@ -215,6 +228,8 @@ int rsnd_mod_init(struct rsnd_priv *priv,
|
|||
|
||||
void rsnd_mod_quit(struct rsnd_mod *mod)
|
||||
{
|
||||
reset_control_assert(mod->rstc);
|
||||
mod->rstc = NULL;
|
||||
clk_unprepare(mod->clk);
|
||||
mod->clk = NULL;
|
||||
}
|
||||
|
|
@ -947,7 +962,8 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
|
|||
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID,
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_RESUME,
|
||||
.buffer_bytes_max = 64 * 1024,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 8192,
|
||||
|
|
@ -1219,6 +1235,107 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name
|
|||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build "<base>-<index>" or "<base>.<index>" and try the hyphen form first,
|
||||
* falling back to the dot form if the hyphen form is not present. This lets
|
||||
* the driver accept both the new DT convention ("ssi-0", "src-0", ...) and
|
||||
* the legacy R-Car convention ("ssi.0", "src.0", ...) transparently.
|
||||
*
|
||||
* @base: name prefix ("ssi", "src", "ctu", "mix", "dvc", "adg.ssi", ...)
|
||||
* @index: integer suffix
|
||||
*
|
||||
* On -ENOENT from the hyphen form, the dot form is tried. All other errors
|
||||
* (including -EPROBE_DEFER) are returned to the caller unchanged, so
|
||||
* behaviour against the clock and reset frameworks is preserved.
|
||||
*/
|
||||
#define RSND_INDEXED_NAME_MAX 32
|
||||
|
||||
static void rsnd_format_indexed_name(char *buf, size_t buflen, char sep,
|
||||
const char *base, int index)
|
||||
{
|
||||
snprintf(buf, buflen, "%s%c%d", base, sep, index);
|
||||
}
|
||||
|
||||
struct clk *rsnd_devm_clk_get_indexed(struct device *dev,
|
||||
const char *base, int index)
|
||||
{
|
||||
char name[RSND_INDEXED_NAME_MAX];
|
||||
struct clk *clk;
|
||||
|
||||
rsnd_format_indexed_name(name, sizeof(name), '-', base, index);
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (!IS_ERR(clk) || PTR_ERR(clk) != -ENOENT)
|
||||
return clk;
|
||||
|
||||
rsnd_format_indexed_name(name, sizeof(name), '.', base, index);
|
||||
return devm_clk_get(dev, name);
|
||||
}
|
||||
|
||||
struct clk *rsnd_devm_clk_get_optional_indexed(struct device *dev,
|
||||
const char *base, int index)
|
||||
{
|
||||
char name[RSND_INDEXED_NAME_MAX];
|
||||
struct clk *clk;
|
||||
|
||||
rsnd_format_indexed_name(name, sizeof(name), '-', base, index);
|
||||
clk = devm_clk_get_optional(dev, name);
|
||||
if (IS_ERR(clk) || clk)
|
||||
return clk;
|
||||
|
||||
rsnd_format_indexed_name(name, sizeof(name), '.', base, index);
|
||||
return devm_clk_get_optional(dev, name);
|
||||
}
|
||||
|
||||
struct reset_control *
|
||||
rsnd_devm_reset_control_get_optional_indexed(struct device *dev,
|
||||
const char *base, int index)
|
||||
{
|
||||
char name[RSND_INDEXED_NAME_MAX];
|
||||
struct reset_control *rstc;
|
||||
|
||||
rsnd_format_indexed_name(name, sizeof(name), '-', base, index);
|
||||
rstc = devm_reset_control_get_optional(dev, name);
|
||||
if (IS_ERR(rstc) || rstc)
|
||||
return rstc;
|
||||
|
||||
rsnd_format_indexed_name(name, sizeof(name), '.', base, index);
|
||||
return devm_reset_control_get_optional(dev, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip the "rcar_sound," prefix from a legacy node name.
|
||||
*
|
||||
* The RZ/G3E binding uses unprefixed sub-node names (e.g. "ssi",
|
||||
* "ssiu") while earlier R-Car bindings use the legacy "rcar_sound,*"
|
||||
* form. This helper returns the unprefixed portion (the part after
|
||||
* the comma) or NULL if there is no prefix.
|
||||
*
|
||||
* Centralising the convention here keeps every call site consistent.
|
||||
*/
|
||||
static const char *rsnd_node_name_strip_prefix(const char *name)
|
||||
{
|
||||
const char *comma = strchr(name, ',');
|
||||
|
||||
return comma ? comma + 1 : NULL;
|
||||
}
|
||||
|
||||
struct device_node *rsnd_parse_of_node(struct rsnd_priv *priv, const char *name)
|
||||
{
|
||||
struct device_node *np = rsnd_priv_to_dev(priv)->of_node;
|
||||
struct device_node *node;
|
||||
const char *unprefixed;
|
||||
|
||||
node = of_get_child_by_name(np, name);
|
||||
if (node)
|
||||
return node;
|
||||
|
||||
unprefixed = rsnd_node_name_strip_prefix(name);
|
||||
if (unprefixed)
|
||||
node = of_get_child_by_name(np, unprefixed);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static struct device_node*
|
||||
rsnd_pick_endpoint_node_for_ports(struct device_node *e_ports,
|
||||
struct device_node *e_port)
|
||||
|
|
@ -2043,11 +2160,35 @@ static void rsnd_remove(struct platform_device *pdev)
|
|||
remove_func[i](priv);
|
||||
}
|
||||
|
||||
void rsnd_suspend_clk_reset(struct clk *clk, struct reset_control *rstc)
|
||||
{
|
||||
clk_unprepare(clk);
|
||||
reset_control_assert(rstc);
|
||||
}
|
||||
|
||||
void rsnd_resume_clk_reset(struct clk *clk, struct reset_control *rstc)
|
||||
{
|
||||
reset_control_deassert(rstc);
|
||||
clk_prepare(clk);
|
||||
}
|
||||
|
||||
static int rsnd_suspend(struct device *dev)
|
||||
{
|
||||
struct rsnd_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* Reverse order of probe:
|
||||
* ADG -> DVC -> MIX -> CTU -> SRC -> SSIU -> SSI -> DMA
|
||||
*/
|
||||
rsnd_adg_clk_disable(priv);
|
||||
rsnd_adg_suspend(priv);
|
||||
rsnd_dvc_suspend(priv);
|
||||
rsnd_mix_suspend(priv);
|
||||
rsnd_ctu_suspend(priv);
|
||||
rsnd_src_suspend(priv);
|
||||
rsnd_ssiu_suspend(priv);
|
||||
rsnd_ssi_suspend(priv);
|
||||
rsnd_dma_suspend(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2056,7 +2197,21 @@ static int rsnd_resume(struct device *dev)
|
|||
{
|
||||
struct rsnd_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return rsnd_adg_clk_enable(priv);
|
||||
/*
|
||||
* Same order as probe:
|
||||
* DMA -> SSI -> SSIU -> SRC -> CTU -> MIX -> DVC -> ADG
|
||||
*/
|
||||
rsnd_dma_resume(priv);
|
||||
rsnd_ssi_resume(priv);
|
||||
rsnd_ssiu_resume(priv);
|
||||
rsnd_src_resume(priv);
|
||||
rsnd_ctu_resume(priv);
|
||||
rsnd_mix_resume(priv);
|
||||
rsnd_dvc_resume(priv);
|
||||
rsnd_adg_resume(priv);
|
||||
rsnd_adg_clk_enable(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rsnd_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "rsnd.h"
|
||||
|
||||
#define CTU_NAME_SIZE 16
|
||||
#define CTU_NAME "ctu"
|
||||
|
||||
/*
|
||||
|
|
@ -319,7 +318,6 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
|
|||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_ctu *ctu;
|
||||
struct clk *clk;
|
||||
char name[CTU_NAME_SIZE];
|
||||
int i, nr, ret;
|
||||
|
||||
node = rsnd_ctu_of_node(priv);
|
||||
|
|
@ -350,17 +348,14 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
|
|||
* CTU00, CTU01, CTU02, CTU03 => CTU0
|
||||
* CTU10, CTU11, CTU12, CTU13 => CTU1
|
||||
*/
|
||||
snprintf(name, CTU_NAME_SIZE, "%s.%d",
|
||||
CTU_NAME, i / 4);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
clk = rsnd_devm_clk_get_indexed(dev, CTU_NAME, i / 4);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_ctu_probe_done;
|
||||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
|
||||
clk, RSND_MOD_CTU, i);
|
||||
clk, NULL, RSND_MOD_CTU, i);
|
||||
if (ret)
|
||||
goto rsnd_ctu_probe_done;
|
||||
|
||||
|
|
@ -383,3 +378,23 @@ void rsnd_ctu_remove(struct rsnd_priv *priv)
|
|||
rsnd_mod_quit(rsnd_mod_get(ctu));
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_ctu_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ctu *ctu;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_ctu(ctu, priv, i)
|
||||
rsnd_suspend_clk_reset(rsnd_mod_get(ctu)->clk,
|
||||
rsnd_mod_get(ctu)->rstc);
|
||||
}
|
||||
|
||||
void rsnd_ctu_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ctu *ctu;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_ctu(ctu, priv, i)
|
||||
rsnd_resume_clk_reset(rsnd_mod_get(ctu)->clk,
|
||||
rsnd_mod_get(ctu)->rstc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ struct rsnd_dma_ctrl {
|
|||
phys_addr_t ppres;
|
||||
int dmaen_num;
|
||||
int dmapp_num;
|
||||
/* RZ/G3E: Audio DMAC peri-peri clock and reset */
|
||||
struct clk *audmapp_clk;
|
||||
struct reset_control *audmapp_rstc;
|
||||
};
|
||||
|
||||
#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma)
|
||||
|
|
@ -478,6 +481,69 @@ static struct rsnd_mod_ops rsnd_dmapp_ops = {
|
|||
DEBUG_INFO
|
||||
};
|
||||
|
||||
struct rsnd_dma_addr {
|
||||
dma_addr_t out_addr;
|
||||
dma_addr_t in_addr;
|
||||
};
|
||||
|
||||
struct rsnd_dma_addr_dir {
|
||||
struct rsnd_dma_addr capture[3];
|
||||
struct rsnd_dma_addr playback[3];
|
||||
};
|
||||
|
||||
struct rsnd_dma_addr_map {
|
||||
struct rsnd_dma_addr_dir src;
|
||||
struct rsnd_dma_addr_dir ssi;
|
||||
struct rsnd_dma_addr_dir ssiu;
|
||||
};
|
||||
|
||||
static dma_addr_t
|
||||
rsnd_dma_addr_lookup(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod,
|
||||
struct rsnd_priv *priv,
|
||||
const struct rsnd_dma_addr_map *map,
|
||||
int is_play, int is_from)
|
||||
{
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
|
||||
!!(rsnd_io_to_mod_ssiu(io) == mod);
|
||||
int use_src = !!rsnd_io_to_mod_src(io);
|
||||
int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
|
||||
!!rsnd_io_to_mod_mix(io) ||
|
||||
!!rsnd_io_to_mod_ctu(io);
|
||||
int id = rsnd_mod_id(mod);
|
||||
const struct rsnd_dma_addr_dir *dir;
|
||||
const struct rsnd_dma_addr *addr;
|
||||
|
||||
/* it shouldn't happen */
|
||||
if (use_cmd && !use_src)
|
||||
dev_err(dev, "DVC is selected without SRC\n");
|
||||
|
||||
/* use SSIU or SSI? */
|
||||
if (is_ssi && rsnd_ssi_use_busif(io))
|
||||
is_ssi++;
|
||||
|
||||
dev_dbg(dev, "dma%d addr : is_ssi=%d use_src=%d use_cmd=%d\n",
|
||||
id, is_ssi, use_src, use_cmd);
|
||||
|
||||
switch (is_ssi) {
|
||||
case 2:
|
||||
dir = &map->ssiu;
|
||||
break;
|
||||
case 1:
|
||||
dir = &map->ssi;
|
||||
break;
|
||||
default:
|
||||
dir = &map->src;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = is_play ? &dir->playback[use_src + use_cmd]
|
||||
: &dir->capture[use_src + use_cmd];
|
||||
|
||||
return is_from ? addr->out_addr : addr->in_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common DMAC Interface
|
||||
*/
|
||||
|
|
@ -524,47 +590,45 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
|
|||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI);
|
||||
phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU);
|
||||
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
|
||||
!!(rsnd_io_to_mod_ssiu(io) == mod);
|
||||
int use_src = !!rsnd_io_to_mod_src(io);
|
||||
int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
|
||||
!!rsnd_io_to_mod_mix(io) ||
|
||||
!!rsnd_io_to_mod_ctu(io);
|
||||
int id = rsnd_mod_id(mod);
|
||||
int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
|
||||
struct dma_addr {
|
||||
dma_addr_t out_addr;
|
||||
dma_addr_t in_addr;
|
||||
} dma_addrs[3][2][3] = {
|
||||
/* SRC */
|
||||
/* Capture */
|
||||
{{{ 0, 0 },
|
||||
{ RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) },
|
||||
{ RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } },
|
||||
/* Playback */
|
||||
{{ 0, 0, },
|
||||
{ RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) },
|
||||
{ RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } }
|
||||
const struct rsnd_dma_addr_map map = {
|
||||
.src = {
|
||||
.capture = {
|
||||
{ 0, 0 },
|
||||
{ RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) },
|
||||
{ RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) },
|
||||
},
|
||||
.playback = {
|
||||
{ 0, 0 },
|
||||
{ RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) },
|
||||
{ RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) },
|
||||
},
|
||||
},
|
||||
/* SSI */
|
||||
/* Capture */
|
||||
{{{ RDMA_SSI_O_N(ssi, id), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 } },
|
||||
/* Playback */
|
||||
{{ 0, RDMA_SSI_I_N(ssi, id) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) } }
|
||||
.ssi = {
|
||||
.capture = {
|
||||
{ RDMA_SSI_O_N(ssi, id), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 },
|
||||
},
|
||||
.playback = {
|
||||
{ 0, RDMA_SSI_I_N(ssi, id) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) },
|
||||
},
|
||||
},
|
||||
.ssiu = {
|
||||
.capture = {
|
||||
{ RDMA_SSIU_O_N(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 },
|
||||
},
|
||||
.playback = {
|
||||
{ 0, RDMA_SSIU_I_N(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) },
|
||||
},
|
||||
},
|
||||
/* SSIU */
|
||||
/* Capture */
|
||||
{{{ RDMA_SSIU_O_N(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P(ssi, id, busif), 0 } },
|
||||
/* Playback */
|
||||
{{ 0, RDMA_SSIU_I_N(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P(ssi, id, busif) } } },
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -577,17 +641,86 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
|
|||
dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
|
||||
id, busif);
|
||||
|
||||
/* it shouldn't happen */
|
||||
if (use_cmd && !use_src)
|
||||
dev_err(dev, "DVC is selected without SRC\n");
|
||||
return rsnd_dma_addr_lookup(io, mod, priv, &map, is_play, is_from);
|
||||
}
|
||||
|
||||
/* use SSIU or SSI ? */
|
||||
if (is_ssi && rsnd_ssi_use_busif(io))
|
||||
is_ssi++;
|
||||
/*
|
||||
* ex) G3E case
|
||||
* mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out
|
||||
* SSI : 0x13C31000 / 0x13C40000 / 0x13C40000
|
||||
* SSIU: 0x13C31000 / 0x13C40000 / 0x13C40000 / 0xEC400000 / 0xEC400000
|
||||
* SCU : 0x13C00000 / 0x13C10000 / 0x13C14000 / 0xEC300000 / 0xEC304000
|
||||
* CMD : 0x13C00000 / / 0x13C18000 0xEC308000
|
||||
*/
|
||||
|
||||
return (is_from) ?
|
||||
dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr :
|
||||
dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
|
||||
/* RZ/G3E DMA address macros */
|
||||
#define RDMA_SSI_I_N_G3E(addr, i) (addr ##_reg + 0x0000F000 + (0x1000 * (i)))
|
||||
#define RDMA_SSI_O_N_G3E(addr, i) (addr ##_reg + 0x0000F000 + (0x1000 * (i)))
|
||||
|
||||
#define RDMA_SSIU_I_N_G3E(addr, i, j) (addr ##_reg + 0x0000F000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
|
||||
#define RDMA_SSIU_O_N_G3E(addr, i, j) RDMA_SSIU_I_N_G3E(addr, i, j)
|
||||
|
||||
#define RDMA_SSIU_I_P_G3E(addr, i, j) (addr ##_reg + 0xD87CF000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
|
||||
#define RDMA_SSIU_O_P_G3E(addr, i, j) RDMA_SSIU_I_P_G3E(addr, i, j)
|
||||
|
||||
#define RDMA_SRC_I_N_G3E(addr, i) (addr ##_reg + 0x00010000 + (0x400 * (i)))
|
||||
#define RDMA_SRC_O_N_G3E(addr, i) (addr ##_reg + 0x00014000 + (0x400 * (i)))
|
||||
|
||||
#define RDMA_SRC_I_P_G3E(addr, i) (addr ##_reg + 0xD8700000 + (0x400 * (i)))
|
||||
#define RDMA_SRC_O_P_G3E(addr, i) (addr ##_reg + 0xD8704000 + (0x400 * (i)))
|
||||
|
||||
#define RDMA_CMD_O_N_G3E(addr, i) (addr ##_reg + 0x00018000 + (0x400 * (i)))
|
||||
#define RDMA_CMD_O_P_G3E(addr, i) (addr ##_reg + 0xD8708000 + (0x400 * (i)))
|
||||
|
||||
static dma_addr_t
|
||||
rsnd_rzg3e_dma_addr(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod, int is_play, int is_from)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_io_to_priv(io);
|
||||
phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI);
|
||||
phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU);
|
||||
int id = rsnd_mod_id(mod);
|
||||
int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
|
||||
const struct rsnd_dma_addr_map map = {
|
||||
.src = {
|
||||
.capture = {
|
||||
{ 0, 0 },
|
||||
{ RDMA_SRC_O_N_G3E(src, id), RDMA_SRC_I_P_G3E(src, id) },
|
||||
{ RDMA_CMD_O_N_G3E(src, id), RDMA_SRC_I_P_G3E(src, id) },
|
||||
},
|
||||
.playback = {
|
||||
{ 0, 0 },
|
||||
{ RDMA_SRC_O_P_G3E(src, id), RDMA_SRC_I_N_G3E(src, id) },
|
||||
{ RDMA_CMD_O_P_G3E(src, id), RDMA_SRC_I_N_G3E(src, id) },
|
||||
},
|
||||
},
|
||||
.ssi = {
|
||||
.capture = {
|
||||
{ RDMA_SSI_O_N_G3E(ssi, id), 0 },
|
||||
{ RDMA_SSIU_O_P_G3E(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P_G3E(ssi, id, busif), 0 },
|
||||
},
|
||||
.playback = {
|
||||
{ 0, RDMA_SSI_I_N_G3E(ssi, id) },
|
||||
{ 0, RDMA_SSIU_I_P_G3E(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P_G3E(ssi, id, busif) },
|
||||
},
|
||||
},
|
||||
.ssiu = {
|
||||
.capture = {
|
||||
{ RDMA_SSIU_O_N_G3E(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P_G3E(ssi, id, busif), 0 },
|
||||
{ RDMA_SSIU_O_P_G3E(ssi, id, busif), 0 },
|
||||
},
|
||||
.playback = {
|
||||
{ 0, RDMA_SSIU_I_N_G3E(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P_G3E(ssi, id, busif) },
|
||||
{ 0, RDMA_SSIU_I_P_G3E(ssi, id, busif) },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return rsnd_dma_addr_lookup(io, mod, priv, &map, is_play, is_from);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -636,6 +769,8 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
|
|||
return 0;
|
||||
else if (rsnd_is_gen4(priv))
|
||||
return rsnd_gen4_dma_addr(io, mod, is_play, is_from);
|
||||
else if (rsnd_is_rzg3e(priv))
|
||||
return rsnd_rzg3e_dma_addr(io, mod, is_play, is_from);
|
||||
else
|
||||
return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
|
||||
}
|
||||
|
|
@ -659,11 +794,11 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
|
|||
int nr, i, idx;
|
||||
|
||||
/*
|
||||
* It should use "rcar_sound,ssiu" on DT.
|
||||
* But, we need to keep compatibility for old version.
|
||||
* It should use "rcar_sound,ssiu" (R-Car) or "ssiu" (RZ/G3E) on DT.
|
||||
* We need to keep compatibility for old version.
|
||||
*
|
||||
* If it has "rcar_sound.ssiu", it will be used.
|
||||
* If not, "rcar_sound.ssi" will be used.
|
||||
* If it has "rcar_sound.ssiu" or "ssiu", it will be used.
|
||||
* If not, "rcar_sound.ssi" or "ssi" will be used.
|
||||
* see
|
||||
* rsnd_ssiu_dma_req()
|
||||
* rsnd_ssi_dma_req()
|
||||
|
|
@ -803,7 +938,7 @@ static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
|
|||
|
||||
*dma_mod = rsnd_mod_get(dma);
|
||||
|
||||
ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
|
||||
ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, NULL,
|
||||
type, dma_id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -870,6 +1005,25 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
|
|||
return 0; /* it will be PIO mode */
|
||||
}
|
||||
|
||||
/*
|
||||
* Audio DMAC peri-peri clock and reset for RZ/G3E.
|
||||
* These use optional APIs, so they gracefully return NULL
|
||||
* (no error) on platforms whose DT does not provide them.
|
||||
*
|
||||
* Enable the clock first so the block sees a stable clock on
|
||||
* the way out of reset, then deassert the reset line.
|
||||
*/
|
||||
dmac->audmapp_clk = devm_clk_get_optional_enabled(dev, "audmapp");
|
||||
if (IS_ERR(dmac->audmapp_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(dmac->audmapp_clk),
|
||||
"failed to get audmapp clock\n");
|
||||
|
||||
dmac->audmapp_rstc =
|
||||
devm_reset_control_get_optional_exclusive_deasserted(dev, "audmapp");
|
||||
if (IS_ERR(dmac->audmapp_rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(dmac->audmapp_rstc),
|
||||
"failed to get audmapp reset\n");
|
||||
|
||||
dmac->dmapp_num = 0;
|
||||
dmac->ppres = res->start;
|
||||
dmac->ppbase = devm_ioremap_resource(dev, res);
|
||||
|
|
@ -879,5 +1033,27 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
|
|||
priv->dma = dmac;
|
||||
|
||||
/* dummy mem mod for debug */
|
||||
return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0);
|
||||
return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
|
||||
}
|
||||
|
||||
void rsnd_dma_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
|
||||
|
||||
if (dmac) {
|
||||
/* Mirror probe (which enables clk before deasserting reset) */
|
||||
rsnd_suspend_clk_reset(NULL, dmac->audmapp_rstc);
|
||||
clk_disable_unprepare(dmac->audmapp_clk);
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_dma_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
|
||||
|
||||
if (dmac) {
|
||||
/* Clock must be stable before reset is deasserted */
|
||||
clk_prepare_enable(dmac->audmapp_clk);
|
||||
rsnd_resume_clk_reset(NULL, dmac->audmapp_rstc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "rsnd.h"
|
||||
|
||||
#define RSND_DVC_NAME_SIZE 16
|
||||
|
||||
#define DVC_NAME "dvc"
|
||||
|
||||
|
|
@ -327,7 +326,6 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
|
|||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_dvc *dvc;
|
||||
struct clk *clk;
|
||||
char name[RSND_DVC_NAME_SIZE];
|
||||
int i, nr, ret;
|
||||
|
||||
node = rsnd_dvc_of_node(priv);
|
||||
|
|
@ -354,17 +352,14 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
|
|||
for_each_child_of_node_scoped(node, np) {
|
||||
dvc = rsnd_dvc_get(priv, i);
|
||||
|
||||
snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
|
||||
DVC_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
clk = rsnd_devm_clk_get_indexed(dev, DVC_NAME, i);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_dvc_probe_done;
|
||||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
|
||||
clk, RSND_MOD_DVC, i);
|
||||
clk, NULL, RSND_MOD_DVC, i);
|
||||
if (ret)
|
||||
goto rsnd_dvc_probe_done;
|
||||
|
||||
|
|
@ -386,3 +381,23 @@ void rsnd_dvc_remove(struct rsnd_priv *priv)
|
|||
rsnd_mod_quit(rsnd_mod_get(dvc));
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_dvc_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dvc *dvc;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_dvc(dvc, priv, i)
|
||||
rsnd_suspend_clk_reset(rsnd_mod_get(dvc)->clk,
|
||||
rsnd_mod_get(dvc)->rstc);
|
||||
}
|
||||
|
||||
void rsnd_dvc_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_dvc *dvc;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_dvc(dvc, priv, i)
|
||||
rsnd_resume_clk_reset(rsnd_mod_get(dvc)->clk,
|
||||
rsnd_mod_get(dvc)->rstc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -464,6 +464,184 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv)
|
|||
return ret_adg | ret_ssi;
|
||||
}
|
||||
|
||||
/*
|
||||
* RZ/G3E Generation
|
||||
*/
|
||||
static int rsnd_rzg3e_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
static const struct rsnd_regmap_field_conf conf_ssiu[] = {
|
||||
RSND_GEN_S_REG(SSI_MODE1, 0x804),
|
||||
RSND_GEN_S_REG(SSI_MODE2, 0x808),
|
||||
RSND_GEN_S_REG(SSI_MODE3, 0x80c),
|
||||
RSND_GEN_S_REG(SSI_CONTROL, 0x810),
|
||||
RSND_GEN_S_REG(SSI_CONTROL2, 0x814),
|
||||
RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
|
||||
RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
|
||||
RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
|
||||
RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
|
||||
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
|
||||
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854),
|
||||
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
|
||||
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c),
|
||||
RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80),
|
||||
RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80),
|
||||
RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
|
||||
RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
|
||||
RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x480),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4),
|
||||
RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8),
|
||||
};
|
||||
static const struct rsnd_regmap_field_conf conf_scu[] = {
|
||||
RSND_GEN_M_REG(SRC_I_BUSIF_MODE, 0x0, 0x20),
|
||||
RSND_GEN_M_REG(SRC_O_BUSIF_MODE, 0x4, 0x20),
|
||||
RSND_GEN_M_REG(SRC_BUSIF_DALIGN, 0x8, 0x20),
|
||||
RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
|
||||
RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
|
||||
RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
|
||||
RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20),
|
||||
RSND_GEN_M_REG(CMD_BUSIF_DALIGN, 0x188, 0x20),
|
||||
RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
|
||||
RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
|
||||
RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
|
||||
RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
|
||||
RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
|
||||
RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
|
||||
RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
|
||||
RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
|
||||
RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
|
||||
RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
|
||||
RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
|
||||
RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
|
||||
RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
|
||||
RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
|
||||
RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100),
|
||||
RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
|
||||
RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
|
||||
RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100),
|
||||
RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100),
|
||||
RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
|
||||
RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40),
|
||||
RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40),
|
||||
RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100),
|
||||
RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100),
|
||||
RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
|
||||
RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
|
||||
RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100),
|
||||
RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100),
|
||||
RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
|
||||
};
|
||||
static const struct rsnd_regmap_field_conf conf_adg[] = {
|
||||
RSND_GEN_S_REG(BRRA, 0x00),
|
||||
RSND_GEN_S_REG(BRRB, 0x04),
|
||||
RSND_GEN_S_REG(BRGCKR, 0x08),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
|
||||
RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18),
|
||||
RSND_GEN_S_REG(DIV_EN, 0x30),
|
||||
RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34),
|
||||
RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38),
|
||||
RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c),
|
||||
RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40),
|
||||
RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44),
|
||||
RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48),
|
||||
RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c),
|
||||
RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50),
|
||||
RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54),
|
||||
RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58),
|
||||
RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c),
|
||||
};
|
||||
static const struct rsnd_regmap_field_conf conf_ssi[] = {
|
||||
RSND_GEN_M_REG(SSICR, 0x00, 0x40),
|
||||
RSND_GEN_M_REG(SSISR, 0x04, 0x40),
|
||||
RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SCU, "scu", conf_scu);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_adg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSIU, "ssiu", conf_ssiu);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSI, "ssi", conf_ssi);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gen
|
||||
*/
|
||||
|
|
@ -487,6 +665,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
|
|||
ret = rsnd_gen2_probe(priv);
|
||||
else if (rsnd_is_gen4(priv))
|
||||
ret = rsnd_gen4_probe(priv);
|
||||
else if (rsnd_is_rzg3e(priv))
|
||||
ret = rsnd_rzg3e_probe(priv);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(dev, "unknown generation R-Car sound device\n");
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
#include "rsnd.h"
|
||||
|
||||
#define MIX_NAME_SIZE 16
|
||||
#define MIX_NAME "mix"
|
||||
|
||||
struct rsnd_mix {
|
||||
|
|
@ -291,7 +290,6 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
|
|||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_mix *mix;
|
||||
struct clk *clk;
|
||||
char name[MIX_NAME_SIZE];
|
||||
int i, nr, ret;
|
||||
|
||||
node = rsnd_mix_of_node(priv);
|
||||
|
|
@ -318,17 +316,14 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
|
|||
for_each_child_of_node_scoped(node, np) {
|
||||
mix = rsnd_mix_get(priv, i);
|
||||
|
||||
snprintf(name, MIX_NAME_SIZE, "%s.%d",
|
||||
MIX_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
clk = rsnd_devm_clk_get_indexed(dev, MIX_NAME, i);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_mix_probe_done;
|
||||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
|
||||
clk, RSND_MOD_MIX, i);
|
||||
clk, NULL, RSND_MOD_MIX, i);
|
||||
if (ret)
|
||||
goto rsnd_mix_probe_done;
|
||||
|
||||
|
|
@ -350,3 +345,23 @@ void rsnd_mix_remove(struct rsnd_priv *priv)
|
|||
rsnd_mod_quit(rsnd_mod_get(mix));
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_mix_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_mix *mix;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_mix(mix, priv, i)
|
||||
rsnd_suspend_clk_reset(rsnd_mod_get(mix)->clk,
|
||||
rsnd_mod_get(mix)->rstc);
|
||||
}
|
||||
|
||||
void rsnd_mix_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_mix *mix;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_mix(mix, priv, i)
|
||||
rsnd_resume_clk_reset(rsnd_mod_get(mix)->clk,
|
||||
rsnd_mod_get(mix)->rstc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/soc.h>
|
||||
|
|
@ -142,13 +143,16 @@ enum rsnd_reg {
|
|||
AUDIO_CLK_SEL0,
|
||||
AUDIO_CLK_SEL1,
|
||||
AUDIO_CLK_SEL2,
|
||||
AUDIO_CLK_SEL3,
|
||||
|
||||
/* SSIU */
|
||||
SSI_MODE,
|
||||
SSI_MODE0,
|
||||
SSI_MODE1,
|
||||
SSI_MODE2,
|
||||
SSI_MODE3,
|
||||
SSI_CONTROL,
|
||||
SSI_CONTROL2,
|
||||
SSI_CTRL,
|
||||
SSI_BUSIF0_MODE,
|
||||
SSI_BUSIF1_MODE,
|
||||
|
|
@ -263,6 +267,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
|
|||
int rsnd_dma_attach(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
|
||||
int rsnd_dma_probe(struct rsnd_priv *priv);
|
||||
void rsnd_dma_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_dma_resume(struct rsnd_priv *priv);
|
||||
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
|
||||
struct rsnd_mod *mod, char *x);
|
||||
|
||||
|
|
@ -353,6 +359,7 @@ struct rsnd_mod {
|
|||
struct rsnd_mod_ops *ops;
|
||||
struct rsnd_priv *priv;
|
||||
struct clk *clk;
|
||||
struct reset_control *rstc;
|
||||
u32 status;
|
||||
};
|
||||
/*
|
||||
|
|
@ -420,9 +427,12 @@ int rsnd_mod_init(struct rsnd_priv *priv,
|
|||
struct rsnd_mod *mod,
|
||||
struct rsnd_mod_ops *ops,
|
||||
struct clk *clk,
|
||||
struct reset_control *rstc,
|
||||
enum rsnd_mod_type type,
|
||||
int id);
|
||||
void rsnd_mod_quit(struct rsnd_mod *mod);
|
||||
void rsnd_suspend_clk_reset(struct clk *clk, struct reset_control *rstc);
|
||||
void rsnd_resume_clk_reset(struct clk *clk, struct reset_control *rstc);
|
||||
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
|
||||
struct rsnd_mod *mod);
|
||||
void rsnd_mod_interrupt(struct rsnd_mod *mod,
|
||||
|
|
@ -473,11 +483,30 @@ int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io);
|
|||
int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io);
|
||||
int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io);
|
||||
|
||||
/*
|
||||
* Indexed clock and reset name helpers.
|
||||
*
|
||||
* Historically the rsnd driver has looked up per-instance clocks and
|
||||
* resets using dot-separated names (e.g. "ssi.0", "src.0", "adg.ssi.0").
|
||||
* Newer Renesas SoC bindings (RZ/G3E and later) use hyphen-separated
|
||||
* names ("ssi-0", "src-0", ...) to follow the standard Device Tree
|
||||
* naming convention. These helpers look up the hyphenated name first
|
||||
* and transparently fall back to the dotted name, so a single driver
|
||||
* build supports both conventions.
|
||||
*/
|
||||
struct clk *rsnd_devm_clk_get_indexed(struct device *dev,
|
||||
const char *base, int index);
|
||||
struct clk *rsnd_devm_clk_get_optional_indexed(struct device *dev,
|
||||
const char *base, int index);
|
||||
struct reset_control *
|
||||
rsnd_devm_reset_control_get_optional_indexed(struct device *dev,
|
||||
const char *base, int index);
|
||||
|
||||
/*
|
||||
* DT
|
||||
*/
|
||||
#define rsnd_parse_of_node(priv, node) \
|
||||
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
|
||||
struct device_node *rsnd_parse_of_node(struct rsnd_priv *priv, const char *name);
|
||||
|
||||
#define RSND_NODE_DAI "rcar_sound,dai"
|
||||
#define RSND_NODE_SSI "rcar_sound,ssi"
|
||||
#define RSND_NODE_SSIU "rcar_sound,ssiu"
|
||||
|
|
@ -600,6 +629,8 @@ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod);
|
|||
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate);
|
||||
int rsnd_adg_probe(struct rsnd_priv *priv);
|
||||
void rsnd_adg_remove(struct rsnd_priv *priv);
|
||||
void rsnd_adg_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_adg_resume(struct rsnd_priv *priv);
|
||||
int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
unsigned int in_rate,
|
||||
|
|
@ -619,14 +650,29 @@ struct rsnd_priv {
|
|||
struct platform_device *pdev;
|
||||
spinlock_t lock;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Flags layout: 0xDCBA
|
||||
*
|
||||
* A: R-Car generation (Gen1/Gen2/Gen3/Gen4)
|
||||
* B: R-Car SoC variant (e.g. SOC_E for E1/E2/E3)
|
||||
* C: RZ series generation
|
||||
* D: RZ series SoC identifier (e.g. RZG3E)
|
||||
*
|
||||
* Bits 16+ are used for capability flags.
|
||||
*/
|
||||
#define RSND_GEN_MASK (0xF << 0)
|
||||
#define RSND_GEN1 (1 << 0)
|
||||
#define RSND_GEN2 (2 << 0)
|
||||
#define RSND_GEN3 (3 << 0)
|
||||
#define RSND_GEN4 (4 << 0)
|
||||
#define RSND_SOC_MASK (0xFF << 4)
|
||||
#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */
|
||||
|
||||
#define RSND_SOC_MASK (0xF << 4) /* nibble B */
|
||||
#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */
|
||||
#define RSND_RZ_MASK (0xF << 8) /* nibble C */
|
||||
#define RSND_RZ3 (3 << 8)
|
||||
#define RSND_RZ_ID_MASK (0xF << 12) /* nibble D */
|
||||
#define RSND_RZG3E (1 << 12)
|
||||
#define RSND_SSIU_BUSIF_STATUS_COUNT_2 BIT(16) /* Only 2 BUSIF error-status register pairs */
|
||||
/*
|
||||
* below value will be filled on rsnd_gen_probe()
|
||||
*/
|
||||
|
|
@ -651,12 +697,14 @@ struct rsnd_priv {
|
|||
/*
|
||||
* below value will be filled on rsnd_ssiu_probe()
|
||||
*/
|
||||
void *ssiu_ctrl;
|
||||
void *ssiu;
|
||||
int ssiu_nr;
|
||||
|
||||
/*
|
||||
* below value will be filled on rsnd_src_probe()
|
||||
*/
|
||||
void *src_ctrl;
|
||||
void *src;
|
||||
int src_nr;
|
||||
|
||||
|
|
@ -705,6 +753,9 @@ struct rsnd_priv {
|
|||
#define rsnd_is_gen3_e3(priv) (((priv)->flags & \
|
||||
(RSND_GEN_MASK | RSND_SOC_MASK)) == \
|
||||
(RSND_GEN3 | RSND_SOC_E))
|
||||
#define rsnd_is_rzg3e(priv) (((priv)->flags & \
|
||||
(RSND_RZ_MASK | RSND_RZ_ID_MASK)) == \
|
||||
(RSND_RZ3 | RSND_RZG3E))
|
||||
|
||||
#define rsnd_flags_has(p, f) ((p)->flags & (f))
|
||||
#define rsnd_flags_set(p, f) ((p)->flags |= (f))
|
||||
|
|
@ -777,6 +828,8 @@ extern const char * const volume_ramp_rate[];
|
|||
*/
|
||||
int rsnd_ssi_probe(struct rsnd_priv *priv);
|
||||
void rsnd_ssi_remove(struct rsnd_priv *priv);
|
||||
void rsnd_ssi_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_ssi_resume(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
|
||||
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
|
||||
u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io);
|
||||
|
|
@ -800,6 +853,8 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
|
|||
struct rsnd_mod *mod);
|
||||
int rsnd_ssiu_probe(struct rsnd_priv *priv);
|
||||
void rsnd_ssiu_remove(struct rsnd_priv *priv);
|
||||
void rsnd_ssiu_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_ssiu_resume(struct rsnd_priv *priv);
|
||||
void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
|
||||
struct device_node *playback,
|
||||
struct device_node *capture);
|
||||
|
|
@ -811,6 +866,8 @@ bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod);
|
|||
*/
|
||||
int rsnd_src_probe(struct rsnd_priv *priv);
|
||||
void rsnd_src_remove(struct rsnd_priv *priv);
|
||||
void rsnd_src_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_src_resume(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
|
||||
|
||||
#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1)
|
||||
|
|
@ -830,6 +887,8 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
|
|||
*/
|
||||
int rsnd_ctu_probe(struct rsnd_priv *priv);
|
||||
void rsnd_ctu_remove(struct rsnd_priv *priv);
|
||||
void rsnd_ctu_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_ctu_resume(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
|
||||
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
|
||||
#define rsnd_parse_connect_ctu(rdai, playback, capture) \
|
||||
|
|
@ -842,6 +901,8 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
|
|||
*/
|
||||
int rsnd_mix_probe(struct rsnd_priv *priv);
|
||||
void rsnd_mix_remove(struct rsnd_priv *priv);
|
||||
void rsnd_mix_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_mix_resume(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
|
||||
#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
|
||||
#define rsnd_parse_connect_mix(rdai, playback, capture) \
|
||||
|
|
@ -854,6 +915,8 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
|
|||
*/
|
||||
int rsnd_dvc_probe(struct rsnd_priv *priv);
|
||||
void rsnd_dvc_remove(struct rsnd_priv *priv);
|
||||
void rsnd_dvc_suspend(struct rsnd_priv *priv);
|
||||
void rsnd_dvc_resume(struct rsnd_priv *priv);
|
||||
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
|
||||
#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
|
||||
#define rsnd_parse_connect_dvc(rdai, playback, capture) \
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ struct rsnd_src {
|
|||
int irq;
|
||||
};
|
||||
|
||||
#define RSND_SRC_NAME_SIZE 16
|
||||
|
||||
#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
|
||||
#define rsnd_src_nr(priv) ((priv)->src_nr)
|
||||
|
|
@ -54,6 +53,14 @@ struct rsnd_src {
|
|||
((pos) = (struct rsnd_src *)(priv)->src + i); \
|
||||
i++)
|
||||
|
||||
struct rsnd_src_ctrl {
|
||||
struct clk *scu;
|
||||
struct clk *scu_x2;
|
||||
struct clk *scu_supply;
|
||||
};
|
||||
|
||||
#define rsnd_priv_to_src_ctrl(priv) \
|
||||
((struct rsnd_src_ctrl *)(priv)->src_ctrl)
|
||||
|
||||
/*
|
||||
* image of SRC (Sampling Rate Converter)
|
||||
|
|
@ -713,9 +720,10 @@ int rsnd_src_probe(struct rsnd_priv *priv)
|
|||
{
|
||||
struct device_node *node;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct reset_control *rstc;
|
||||
struct rsnd_src_ctrl *src_ctrl;
|
||||
struct rsnd_src *src;
|
||||
struct clk *clk;
|
||||
char name[RSND_SRC_NAME_SIZE];
|
||||
int i, nr, ret;
|
||||
|
||||
node = rsnd_src_of_node(priv);
|
||||
|
|
@ -728,6 +736,12 @@ int rsnd_src_probe(struct rsnd_priv *priv)
|
|||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
src_ctrl = devm_kzalloc(dev, sizeof(*src_ctrl), GFP_KERNEL);
|
||||
if (!src_ctrl) {
|
||||
ret = -ENOMEM;
|
||||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
src = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL);
|
||||
if (!src) {
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -736,6 +750,38 @@ int rsnd_src_probe(struct rsnd_priv *priv)
|
|||
|
||||
priv->src_nr = nr;
|
||||
priv->src = src;
|
||||
priv->src_ctrl = src_ctrl;
|
||||
|
||||
src_ctrl->scu = devm_clk_get_optional_enabled(dev, "scu");
|
||||
if (IS_ERR(src_ctrl->scu)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(src_ctrl->scu),
|
||||
"failed to get scu clock\n");
|
||||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
src_ctrl->scu_x2 = devm_clk_get_optional_enabled(dev, "scu_x2");
|
||||
if (IS_ERR(src_ctrl->scu_x2)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(src_ctrl->scu_x2),
|
||||
"failed to get scu_x2 clock\n");
|
||||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
src_ctrl->scu_supply = devm_clk_get_optional_enabled(dev, "scu_supply");
|
||||
if (IS_ERR(src_ctrl->scu_supply)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(src_ctrl->scu_supply),
|
||||
"failed to get scu_supply clock\n");
|
||||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shared SCU reset for every SRC module; acquire once.
|
||||
* R-Car platforms typically don't have SRC reset controls.
|
||||
*/
|
||||
rstc = devm_reset_control_get_optional_shared(dev, "scu");
|
||||
if (IS_ERR(rstc)) {
|
||||
ret = PTR_ERR(rstc);
|
||||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node_scoped(node, np) {
|
||||
|
|
@ -750,23 +796,20 @@ int rsnd_src_probe(struct rsnd_priv *priv)
|
|||
|
||||
src = rsnd_src_get(priv, i);
|
||||
|
||||
snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
|
||||
SRC_NAME, i);
|
||||
|
||||
src->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!src->irq) {
|
||||
ret = -EINVAL;
|
||||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
clk = rsnd_devm_clk_get_indexed(dev, SRC_NAME, i);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_src_probe_done;
|
||||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(src),
|
||||
&rsnd_src_ops, clk, RSND_MOD_SRC, i);
|
||||
&rsnd_src_ops, clk, rstc, RSND_MOD_SRC, i);
|
||||
if (ret)
|
||||
goto rsnd_src_probe_done;
|
||||
|
||||
|
|
@ -791,3 +834,37 @@ void rsnd_src_remove(struct rsnd_priv *priv)
|
|||
rsnd_mod_quit(rsnd_mod_get(src));
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_src_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_src_ctrl *src_ctrl = rsnd_priv_to_src_ctrl(priv);
|
||||
struct rsnd_src *src;
|
||||
int i;
|
||||
|
||||
if (!src_ctrl)
|
||||
return;
|
||||
|
||||
for_each_rsnd_src(src, priv, i)
|
||||
rsnd_suspend_clk_reset(rsnd_mod_get(src)->clk,
|
||||
rsnd_mod_get(src)->rstc);
|
||||
|
||||
clk_disable_unprepare(src_ctrl->scu_x2);
|
||||
clk_disable_unprepare(src_ctrl->scu);
|
||||
}
|
||||
|
||||
void rsnd_src_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_src_ctrl *src_ctrl = rsnd_priv_to_src_ctrl(priv);
|
||||
struct rsnd_src *src;
|
||||
int i;
|
||||
|
||||
if (!src_ctrl)
|
||||
return;
|
||||
|
||||
clk_prepare_enable(src_ctrl->scu);
|
||||
clk_prepare_enable(src_ctrl->scu_x2);
|
||||
|
||||
for_each_rsnd_src(src, priv, i)
|
||||
rsnd_resume_clk_reset(rsnd_mod_get(src)->clk,
|
||||
rsnd_mod_get(src)->rstc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include "rsnd.h"
|
||||
#define RSND_SSI_NAME_SIZE 16
|
||||
|
||||
/*
|
||||
* SSICR
|
||||
|
|
@ -1010,11 +1009,11 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
|
|||
char *name;
|
||||
|
||||
/*
|
||||
* It should use "rcar_sound,ssiu" on DT.
|
||||
* But, we need to keep compatibility for old version.
|
||||
* It should use "rcar_sound,ssiu" (R-Car) or "ssiu" (RZ/G3E) on DT.
|
||||
* We need to keep compatibility for old version.
|
||||
*
|
||||
* If it has "rcar_sound.ssiu", it will be used.
|
||||
* If not, "rcar_sound.ssi" will be used.
|
||||
* If it has "rcar_sound.ssiu" or "ssiu", it will be used.
|
||||
* If not, "rcar_sound.ssi" or "ssi" will be used.
|
||||
* see
|
||||
* rsnd_ssiu_dma_req()
|
||||
* rsnd_dma_of_path()
|
||||
|
|
@ -1158,12 +1157,12 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
|
|||
|
||||
int rsnd_ssi_probe(struct rsnd_priv *priv)
|
||||
{
|
||||
struct reset_control *rstc;
|
||||
struct device_node *node;
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_mod_ops *ops;
|
||||
struct clk *clk;
|
||||
struct rsnd_ssi *ssi;
|
||||
char name[RSND_SSI_NAME_SIZE];
|
||||
int i, nr, ret;
|
||||
|
||||
node = rsnd_ssi_of_node(priv);
|
||||
|
|
@ -1198,15 +1197,23 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
|
|||
|
||||
ssi = rsnd_ssi_get(priv, i);
|
||||
|
||||
snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
|
||||
SSI_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
clk = rsnd_devm_clk_get_indexed(dev, SSI_NAME, i);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto rsnd_ssi_probe_done;
|
||||
}
|
||||
|
||||
/*
|
||||
* RZ/G3E uses per-SSI reset controllers.
|
||||
* R-Car platforms typically don't have SSI reset controls.
|
||||
*/
|
||||
rstc = rsnd_devm_reset_control_get_optional_indexed(dev,
|
||||
SSI_NAME, i);
|
||||
if (IS_ERR(rstc)) {
|
||||
ret = PTR_ERR(rstc);
|
||||
goto rsnd_ssi_probe_done;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "shared-pin"))
|
||||
rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
|
||||
|
||||
|
|
@ -1225,7 +1232,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
|
|||
ops = &rsnd_ssi_dma_ops;
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
|
||||
RSND_MOD_SSI, i);
|
||||
rstc, RSND_MOD_SSI, i);
|
||||
if (ret)
|
||||
goto rsnd_ssi_probe_done;
|
||||
|
||||
|
|
@ -1250,3 +1257,23 @@ void rsnd_ssi_remove(struct rsnd_priv *priv)
|
|||
rsnd_mod_quit(rsnd_mod_get(ssi));
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_ssi_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssi *ssi;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_ssi(ssi, priv, i)
|
||||
rsnd_suspend_clk_reset(rsnd_mod_get(ssi)->clk,
|
||||
rsnd_mod_get(ssi)->rstc);
|
||||
}
|
||||
|
||||
void rsnd_ssi_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssi *ssi;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_ssi(ssi, priv, i)
|
||||
rsnd_resume_clk_reset(rsnd_mod_get(ssi)->clk,
|
||||
rsnd_mod_get(ssi)->rstc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,31 +29,39 @@ struct rsnd_ssiu {
|
|||
i++)
|
||||
|
||||
/*
|
||||
* SSI Gen2 Gen3 Gen4
|
||||
* 0 BUSIF0-3 BUSIF0-7 BUSIF0-7
|
||||
* 1 BUSIF0-3 BUSIF0-7
|
||||
* 2 BUSIF0-3 BUSIF0-7
|
||||
* 3 BUSIF0 BUSIF0-7
|
||||
* 4 BUSIF0 BUSIF0-7
|
||||
* 5 BUSIF0 BUSIF0
|
||||
* 6 BUSIF0 BUSIF0
|
||||
* 7 BUSIF0 BUSIF0
|
||||
* 8 BUSIF0 BUSIF0
|
||||
* 9 BUSIF0-3 BUSIF0-7
|
||||
* total 22 52 8
|
||||
* SSI Gen2 Gen3 Gen4 RZ/G3E
|
||||
* 0 BUSIF0-3 BUSIF0-7 BUSIF0-7 BUSIF0-3
|
||||
* 1 BUSIF0-3 BUSIF0-7 BUSIF0-3
|
||||
* 2 BUSIF0-3 BUSIF0-7 BUSIF0-3
|
||||
* 3 BUSIF0 BUSIF0-7 BUSIF0-3
|
||||
* 4 BUSIF0 BUSIF0-7 BUSIF0-3
|
||||
* 5 BUSIF0 BUSIF0 BUSIF0
|
||||
* 6 BUSIF0 BUSIF0 BUSIF0
|
||||
* 7 BUSIF0 BUSIF0 BUSIF0
|
||||
* 8 BUSIF0 BUSIF0 BUSIF0
|
||||
* 9 BUSIF0-3 BUSIF0-7 BUSIF0-3
|
||||
* total 22 52 8 28
|
||||
*/
|
||||
static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 };
|
||||
static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
|
||||
static const int gen4_id[] = { 0 };
|
||||
static const int rzg3e_id[] = { 0, 4, 8, 12, 16, 20, 21, 22, 23, 24 };
|
||||
|
||||
struct rsnd_ssiu_ctrl {
|
||||
unsigned int busif_status_count;
|
||||
};
|
||||
|
||||
#define rsnd_priv_to_ssiu_ctrl(priv) \
|
||||
((struct rsnd_ssiu_ctrl *)(priv)->ssiu_ctrl)
|
||||
|
||||
/* enable busif buffer over/under run interrupt. */
|
||||
#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
|
||||
#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0)
|
||||
static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
int id = rsnd_mod_id(mod);
|
||||
int shift, offset;
|
||||
int i;
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
|
|
@ -72,7 +80,7 @@ static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (unsigned int i = 0; i < rsnd_priv_to_ssiu_ctrl(priv)->busif_status_count; i++) {
|
||||
enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset);
|
||||
u32 val = 0xf << (shift * 4);
|
||||
u32 sys_int_enable = rsnd_mod_read(mod, reg);
|
||||
|
|
@ -87,10 +95,10 @@ static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
|
|||
|
||||
bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
bool error = false;
|
||||
int id = rsnd_mod_id(mod);
|
||||
int shift, offset;
|
||||
int i;
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
|
|
@ -109,14 +117,13 @@ bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
|
|||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (unsigned int i = 0; i < rsnd_priv_to_ssiu_ctrl(priv)->busif_status_count; i++) {
|
||||
u32 reg = SSI_SYS_STATUS(i * 2) + offset;
|
||||
u32 status = rsnd_mod_read(mod, reg);
|
||||
u32 val = 0xf << (shift * 4);
|
||||
|
||||
status &= val;
|
||||
if (status) {
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
|
||||
rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
|
||||
|
|
@ -160,7 +167,8 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
|
|||
/*
|
||||
* SSI_MODE0
|
||||
*/
|
||||
rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
|
||||
if (!rsnd_is_rzg3e(priv))
|
||||
rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
|
||||
|
||||
/*
|
||||
* SSI_MODE1 / SSI_MODE2
|
||||
|
|
@ -392,11 +400,11 @@ static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
|
|||
char *name;
|
||||
|
||||
/*
|
||||
* It should use "rcar_sound,ssiu" on DT.
|
||||
* But, we need to keep compatibility for old version.
|
||||
* It should use "rcar_sound,ssiu" (R-Car) or "ssiu" (RZ/G3E) on DT.
|
||||
* We need to keep compatibility for old versions.
|
||||
*
|
||||
* If it has "rcar_sound.ssiu", it will be used.
|
||||
* If not, "rcar_sound.ssi" will be used.
|
||||
* If it has "rcar_sound.ssiu" or "ssiu", it will be used.
|
||||
* If not, "rcar_sound.ssi" or "ssi" will be used.
|
||||
* see
|
||||
* rsnd_ssi_dma_req()
|
||||
* rsnd_dma_of_path()
|
||||
|
|
@ -510,6 +518,8 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
|
|||
{
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct device_node *node __free(device_node) = rsnd_ssiu_of_node(priv);
|
||||
struct reset_control *rstc;
|
||||
struct rsnd_ssiu_ctrl *ctrl;
|
||||
struct rsnd_ssiu *ssiu;
|
||||
struct rsnd_mod_ops *ops;
|
||||
const int *list = NULL;
|
||||
|
|
@ -534,8 +544,15 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
|
|||
if (!ssiu)
|
||||
return -ENOMEM;
|
||||
|
||||
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
ctrl->busif_status_count = rsnd_flags_has(priv, RSND_SSIU_BUSIF_STATUS_COUNT_2) ? 2 : 4;
|
||||
|
||||
priv->ssiu = ssiu;
|
||||
priv->ssiu_nr = nr;
|
||||
priv->ssiu_ctrl = ctrl;
|
||||
|
||||
if (rsnd_is_gen1(priv))
|
||||
ops = &rsnd_ssiu_ops_gen1;
|
||||
|
|
@ -558,12 +575,21 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
|
|||
} else if (rsnd_is_gen4(priv)) {
|
||||
list = gen4_id;
|
||||
nr = ARRAY_SIZE(gen4_id);
|
||||
} else if (rsnd_is_rzg3e(priv)) {
|
||||
list = rzg3e_id;
|
||||
nr = ARRAY_SIZE(rzg3e_id);
|
||||
} else {
|
||||
dev_err(dev, "unknown SSIU\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Acquire shared reset once for all SSIU modules */
|
||||
rstc = devm_reset_control_get_optional_shared(dev, "ssi-all");
|
||||
if (IS_ERR(rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(rstc),
|
||||
"failed to get ssi-all reset\n");
|
||||
|
||||
for_each_rsnd_ssiu(ssiu, priv, i) {
|
||||
int ret;
|
||||
|
||||
|
|
@ -586,7 +612,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
|
|||
}
|
||||
|
||||
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
|
||||
ops, NULL, RSND_MOD_SSIU, i);
|
||||
ops, NULL, rstc, RSND_MOD_SSIU, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -603,3 +629,23 @@ void rsnd_ssiu_remove(struct rsnd_priv *priv)
|
|||
rsnd_mod_quit(rsnd_mod_get(ssiu));
|
||||
}
|
||||
}
|
||||
|
||||
void rsnd_ssiu_suspend(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssiu *ssiu;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_ssiu(ssiu, priv, i)
|
||||
rsnd_suspend_clk_reset(rsnd_mod_get(ssiu)->clk,
|
||||
rsnd_mod_get(ssiu)->rstc);
|
||||
}
|
||||
|
||||
void rsnd_ssiu_resume(struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssiu *ssiu;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_ssiu(ssiu, priv, i)
|
||||
rsnd_resume_clk_reset(rsnd_mod_get(ssiu)->clk,
|
||||
rsnd_mod_get(ssiu)->rstc);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user