summaryrefslogtreecommitdiffstats
path: root/sound/soc/generic
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/generic')
-rw-r--r--sound/soc/generic/audio-graph-card.c1
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample.dtsi380
-rw-r--r--sound/soc/generic/audio-graph-card2.c284
-rw-r--r--sound/soc/generic/simple-card-utils.c20
4 files changed, 594 insertions, 91 deletions
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 76a9f1e8c..83e3ba773 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -9,7 +9,6 @@
#include <linux/clk.h>
#include <linux/device.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
index 8acaa2ddb..9efd31206 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
@@ -58,12 +58,32 @@
* | |-> codec13
* +-+
*
- * [Multi-CPU/Codec]
+ * [Multi-CPU/Codec-0]
* +-+ +-+
* cpu1 <--| |<-@--------->| |-> codec1
* cpu2 <--| | | |-> codec2
* +-+ +-+
*
+ * [Multi-CPU/Codec-1]
+ *
+ * +-+ +-+
+ * | |<-@--------->| |
+ * | | | |
+ * cpu8 <--| |<----------->| |-> codec14
+ * cpu9 <--| |<---+------->| |-> codec15
+ * +-+ \------>| |-> codec16
+ * +-+
+ *
+ * [Multi-CPU/Codec-2]
+ *
+ * +-+ +-+
+ * | |<-@--------->| |
+ * | | | |
+ * cpu10 <-| |<----------->| |-> codec17
+ * cpu11 <-| |<-----+----->| |-> codec18
+ * cpu12 <-| |<----/ +-+
+ * +-+
+ *
* [DPCM]
*
* CPU3/CPU4 are converting rate to 44100
@@ -144,16 +164,39 @@
*/
&cpu0
- /* [Semi-Multi] */
+ /*
+ * [Semi-Multi]
+ * cpu7/codec12/codec13
+ */
&sm0
/*
- * [Multi-CPU/Codec]: cpu side only
+ * [Multi-CPU/Codec-0]: cpu side only
* cpu1/cpu2/codec1/codec2
*/
&mcpu0
/*
+ * [Multi-CPU/Codec-1]: cpu side only
+ * cpu8/cpu9/codec14/codec15/codec16
+ *
+ * Because it will reach to the maximum of sound minor number,
+ * disable it so far.
+ * If you want to try it, please disable some other one instead.
+ */
+ //&mcpu1
+
+ /*
+ * [Multi-CPU/Codec-2]: cpu side only
+ * cpu10/cpu11/cpu12/codec17/codec18
+ *
+ * Because it will reach to the maximum of sound minor number,
+ * disable it so far.
+ * If you want to try it, please disable some other one instead.
+ */
+ //&mcpu2
+
+ /*
* [DPCM]: both FE / BE
* cpu3/cpu4/codec3
*/
@@ -182,64 +225,259 @@
#address-cells = <1>;
#size-cells = <0>;
+ /*
+ * [Multi-CPU-0]
+ *
+ * +---+ +---+
+ * cpu1 <--|A X|<-@------->|x a|-> codec1
+ * cpu2 <--|B | | b|-> codec2
+ * +---+ +---+
+ */
ports@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
- /* [Multi-CPU] */
- mcpu0: port@0 { reg = <0>; mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
- port@1 { reg = <1>; mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
- port@2 { reg = <2>; mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
+ mcpu0: port@0 { reg = <0>; mcpu00_ep: endpoint { remote-endpoint = <&mcodec00_ep>; };};/* (X) to pair */
+ port@1 { reg = <1>; mcpu01_ep: endpoint { remote-endpoint = <&cpu1_ep>; };};/* (A) Multi Element */
+ port@2 { reg = <2>; mcpu02_ep: endpoint { remote-endpoint = <&cpu2_ep>; };};/* (B) Multi Element */
};
- /* [Multi-Codec] */
+ /*
+ * [Multi-Codec-0]
+ *
+ * +---+ +---+
+ * cpu1 <--|A X|<-@------->|x a|-> codec1
+ * cpu2 <--|B | | b|-> codec2
+ * +---+ +---+
+ */
ports@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
- port@0 { reg = <0>; mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; };
- port@1 { reg = <1>; mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
- port@2 { reg = <2>; mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
+ port@0 { reg = <0>; mcodec00_ep: endpoint { remote-endpoint = <&mcpu00_ep>; };};/* (x) to pair */
+ port@1 { reg = <1>; mcodec01_ep: endpoint { remote-endpoint = <&codec1_ep>; };};/* (a) Multi Element */
+ port@2 { reg = <2>; mcodec02_ep: endpoint { remote-endpoint = <&codec2_ep>; };};/* (b) Multi Element */
};
- /* [DPCM-Multi]::BE */
+ /*
+ * [DPCM-Multi]::BE
+ *
+ * FE BE
+ * **** +---+
+ * cpu5 <-@--* *-----@--->|x a|-> codec4
+ * cpu6 <-@--* * | b|-> codec5
+ * **** +---+
+ */
ports@2 {
reg = <2>;
#address-cells = <1>;
#size-cells = <0>;
- port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; }; };
- port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; }; };
- port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; }; };
+ port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; };};/* (x) to pair */
+ port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; };};/* (a) Multi Element */
+ port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; };};/* (b) Multi Element */
};
- /* [Codec2Codec-Multi]::CPU */
+ /*
+ * [Codec2Codec-Multi]::CPU
+ *
+ * +---+
+ * +-@->|X A|-> codec8
+ * | | B|-> codec9
+ * | +---+
+ * | +---+
+ * +--->|x a|-> codec10
+ * | b|-> codec11
+ * +---+
+ */
ports@3 {
reg = <3>;
#address-cells = <1>;
#size-cells = <0>;
- port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; }; };
- port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; }; };
- port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; }; };
+ port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */
+ port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; };};/* (A) Multi Element */
+ port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; };};/* (B) Multi Element */
};
- /* [Codec2Codec-Multi]::Codec */
+ /*
+ * [Codec2Codec-Multi]::Codec
+ *
+ * +---+
+ * +-@->|X A|-> codec8
+ * | | B|-> codec9
+ * | +---+
+ * | +---+
+ * +--->|x a|-> codec10
+ * | b|-> codec11
+ * +---+
+ */
ports@4 {
reg = <4>;
#address-cells = <1>;
#size-cells = <0>;
- port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; }; };
- port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; }; };
- port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; }; };
+ port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */
+ port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; };};/* (a) Multi Element */
+ port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; };};/* (b) Multi Element */
};
- /* [Semi-Multi] */
+ /*
+ * [Semi-Multi]
+ *
+ * +---+
+ * cpu7 <-@------->|X A|-> codec12
+ * | B|-> codec13
+ * +---+
+ */
ports@5 {
reg = <5>;
#address-cells = <1>;
#size-cells = <0>;
- port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; }; };
- port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; }; };
- port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; }; };
+ port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; };};/* (X) to pair */
+ port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; };};/* (A) Multi Element */
+ port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; };};/* (B) Multi Element */
+ };
+
+ /*
+ * [Multi-CPU-1]
+ *
+ * +---+ +---+
+ * | X|<-@------->|x |
+ * | | | |
+ * cpu8 <--|A 1|<--------->|3 a|-> codec14
+ * cpu9 <--|B 2|<---+----->|4 b|-> codec15
+ * +---+ \---->|5 c|-> codec16
+ * +---+
+ */
+ ports@6 {
+ reg = <6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mcpu1: port@0 { reg = <0>; mcpu10_ep: endpoint { remote-endpoint = <&mcodec10_ep>; };}; /* (X) to pair */
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcpu11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu8_ep>; }; /* (A) Multi Element */
+ mcpu11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec11_ep_0>; }; /* (1) connected Codec */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcpu12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu9_ep>; }; /* (B) Multi Element */
+ mcpu12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec12_ep_0>; }; /* (2) connected Codec */
+ mcpu12_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec13_ep_0>; }; /* (2) connected Codec */
+ };
+ };
+
+ /*
+ * [Multi-Codec-1]
+ *
+ * +---+ +---+
+ * | X|<-@------->|x |
+ * | | | |
+ * cpu8 <--|A 1|<--------->|3 a|-> codec14
+ * cpu9 <--|B 2|<---+----->|4 b|-> codec15
+ * +---+ \---->|5 c|-> codec16
+ * +---+
+ */
+ ports@7 {
+ reg = <7>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 { reg = <0>; mcodec10_ep: endpoint { remote-endpoint = <&mcpu10_ep>; };}; /* (x) to pair */
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcodec11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec14_ep>; }; /* (a) Multi Element */
+ mcodec11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu11_ep_0>; }; /* (3) connected CPU */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcodec12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec15_ep>; }; /* (b) Multi Element */
+ mcodec12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_0>; }; /* (4) connected CPU */
+ };
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ mcodec13_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec16_ep>; }; /* (c) Multi Element */
+ mcodec13_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_1>; }; /* (5) connected CPU */
+ };
+ };
+
+ /*
+ * [Multi-CPU-2]
+ *
+ * +---+ +---+
+ * | X|<-@------->|x |
+ * | | | |
+ * cpu10 <-|A 1|<--------->|4 a|-> codec17
+ * cpu11 <-|B 2|<-----+--->|5 b|-> codec18
+ * cpu12 <-|C 3|<----/ +---+
+ * +---+
+ */
+ ports@8 {
+ reg = <8>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mcpu2: port@0 { reg = <0>; mcpu20_ep: endpoint { remote-endpoint = <&mcodec20_ep>; };}; /* (X) to pair */
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcpu21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu10_ep>; }; /* (A) Multi Element */
+ mcpu21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec21_ep_0>; }; /* (1) connected Codec */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcpu22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu11_ep>; }; /* (B) Multi Element */
+ mcpu22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_0>; }; /* (2) connected Codec */
+ };
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ mcpu23_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu12_ep>; }; /* (C) Multi Element */
+ mcpu23_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_1>; }; /* (3) connected Codec */
+ };
+ };
+
+ /*
+ * [Multi-Codec-2]
+ *
+ * +---+ +---+
+ * | X|<-@------->|x |
+ * | | | |
+ * cpu10 <-|A 1|<--------->|4 a|-> codec17
+ * cpu11 <-|B 2|<-----+--->|5 b|-> codec18
+ * cpu12 <-|C 3|<----/ +---+
+ * +---+
+ */
+ ports@9 {
+ reg = <9>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 { reg = <0>; mcodec20_ep: endpoint { remote-endpoint = <&mcpu20_ep>; };}; /* (x) to pair */
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcodec21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec17_ep>; }; /* (a) Multi Element */
+ mcodec21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu21_ep_0>; }; /* (4) connected CPU */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcodec22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec18_ep>; }; /* (b) Multi Element */
+ mcodec22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu22_ep_0>; }; /* (5) connected CPU */
+ mcodec22_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu23_ep_0>; }; /* (5) connected CPU */
+ };
};
};
@@ -252,11 +490,27 @@
#address-cells = <1>;
#size-cells = <0>;
- /* [DPCM]::FE */
+ /*
+ * [DPCM]::FE
+ *
+ * FE BE
+ * ****
+ * cpu3 <-@(fe00)--* *--(be0)@--> codec3
+ * cpu4 <-@(fe01)--* * (44.1kHz)
+ * ****
+ */
fe00: port@0 { reg = <0>; fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; };
fe01: port@1 { reg = <1>; fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; };
- /* [DPCM-Multi]::FE */
+ /*
+ * [DPCM-Multi]::FE
+ *
+ * FE BE
+ * **** +-+
+ * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4
+ * cpu6 <-@(fe11)--* * | |-> codec5
+ * **** +-+
+ */
fe10: port@2 { reg = <2>; fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; };
fe11: port@3 { reg = <3>; fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; };
};
@@ -266,10 +520,26 @@
#address-cells = <1>;
#size-cells = <0>;
- /* [DPCM]::BE */
+ /*
+ * [DPCM]::BE
+ *
+ * FE BE
+ * ****
+ * cpu3 <-@(fe00)--* *--(be0)@--> codec3
+ * cpu4 <-@(fe01)--* * (44.1kHz)
+ * ****
+ */
be0: port@0 { reg = <0>; be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; };
- /* [DPCM-Multi]::BE */
+ /*
+ * [DPCM-Multi]::BE
+ *
+ * FE BE
+ * **** +-+
+ * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4
+ * cpu6 <-@(fe11)--* * | |-> codec5
+ * **** +-+
+ */
be1: port@1 { reg = <1>; be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; };
};
};
@@ -277,7 +547,13 @@
codec2codec {
#address-cells = <1>;
#size-cells = <0>;
- /* [Codec2Codec] */
+ /*
+ * [Codec2Codec]
+ *
+ * +-@(c2c)-> codec6
+ * |
+ * +--------> codec7
+ */
ports@0 {
reg = <0>;
@@ -289,7 +565,18 @@
port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; };
};
- /* [Codec2Codec-Multi] */
+ /*
+ * [Codec2Codec-Multi]
+ *
+ * +-+
+ * +-@(c2c_m)-->| |-> codec8
+ * | | |-> codec9
+ * | +-+
+ * | +-+
+ * +----------->| |-> codec10
+ * | |-> codec11
+ * +-+
+ */
ports@1 {
reg = <1>;
@@ -323,9 +610,9 @@
/* [Normal] */
cpu0: port@0 { reg = <0>; cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; };
- /* [Multi-CPU] */
- port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; };
- port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; };
+ /* [Multi-CPU-0] */
+ port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu01_ep>; }; };
+ port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu02_ep>; }; };
/* [DPCM]::FE */
port@3 { reg = <3>; cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; };
@@ -337,6 +624,14 @@
/* [Semi-Multi] */
sm0: port@7 { reg = <7>; cpu7_ep: endpoint { remote-endpoint = <&smcodec0_ep>; }; };
+
+ /* [Multi-CPU-1] */
+ port@8 { reg = <8>; cpu8_ep: endpoint { remote-endpoint = <&mcpu11_ep>; }; };
+ port@9 { reg = <9>; cpu9_ep: endpoint { remote-endpoint = <&mcpu12_ep>; }; };
+ /* [Multi-CPU-2] */
+ port@a { reg = <10>; cpu10_ep: endpoint { remote-endpoint = <&mcpu21_ep>; }; };
+ port@b { reg = <11>; cpu11_ep: endpoint { remote-endpoint = <&mcpu22_ep>; }; };
+ port@c { reg = <12>; cpu12_ep: endpoint { remote-endpoint = <&mcpu23_ep>; }; };
};
};
@@ -363,9 +658,9 @@
/* [Normal] */
port@0 { reg = <0>; codec0_ep: endpoint { remote-endpoint = <&cpu0_ep>; }; };
- /* [Multi-Codec] */
- port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; };
- port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; };
+ /* [Multi-Codec-0] */
+ port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec01_ep>; }; };
+ port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec02_ep>; }; };
/* [DPCM]::BE */
port@3 {
@@ -395,6 +690,13 @@
port@c { reg = <12>; codec12_ep: endpoint { remote-endpoint = <&smcodec1_ep>; }; };
port@d { reg = <13>; codec13_ep: endpoint { remote-endpoint = <&smcodec2_ep>; }; };
+ /* [Multi-Codec-1] */
+ port@e { reg = <14>; codec14_ep: endpoint { remote-endpoint = <&mcodec11_ep>; }; };
+ port@f { reg = <15>; codec15_ep: endpoint { remote-endpoint = <&mcodec12_ep>; }; };
+ port@10 { reg = <16>; codec16_ep: endpoint { remote-endpoint = <&mcodec13_ep>; }; };
+ /* [Multi-Codec-2] */
+ port@11 { reg = <17>; codec17_ep: endpoint { remote-endpoint = <&mcodec21_ep>; }; };
+ port@12 { reg = <18>; codec18_ep: endpoint { remote-endpoint = <&mcodec22_ep>; }; };
};
};
};
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 7146611df..62606e20b 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -8,7 +8,6 @@
// based on ${LINUX}/sound/soc/generic/audio-graph-card.c
#include <linux/clk.h>
#include <linux/device.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -83,32 +82,32 @@
Multi-CPU/Codec
************************************
-It has connection part (= X) and list part (= y).
-links indicates connection part of CPU side (= A).
+It has link connection part (= X,x) and list part (= A,B,a,b).
+"links" is connection part of CPU side (= @).
- +-+ (A) +-+
- CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1
- CPU2 --(y) | | | | (y)-- Codec2
- +-+ +-+
+ +----+ +---+
+ CPU1 --|A X| <-@----> |x a|-- Codec1
+ CPU2 --|B | | b|-- Codec2
+ +----+ +---+
- sound {
- compatible = "audio-graph-card2";
+ sound {
+ compatible = "audio-graph-card2";
-(A) links = <&mcpu>;
+(@) links = <&mcpu>;
- multi {
- ports@0 {
-(X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
-(y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
-(y) port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
- };
- ports@1 {
-(X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; };
-(y) port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
-(y) port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
- };
+ multi {
+ ports@0 {
+(@) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; // (X) to pair
+ port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; // (A) Multi Element
+ port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; // (B) Multi Element
+ };
+ ports@1 {
+ port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; // (x) to pair
+ port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; // (a) Multi Element
+ port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; // (b) Multi Element
};
};
+ };
CPU {
ports {
@@ -328,9 +327,9 @@ static struct device_node *graph_get_next_multi_ep(struct device_node **port)
/*
* multi {
* ports {
- * => lnk: port@0 { ... };
- * port@1 { ep { ... = rep0 } };
- * port@2 { ep { ... = rep1 } };
+ * => lnk: port@0 { ... }; // to pair
+ * port@1 { ep { ... = rep0 } }; // Multi Element
+ * port@2 { ep { ... = rep1 } }; // Multi Element
* ...
* };
* };
@@ -504,40 +503,203 @@ static int __graph_parse_node(struct simple_util_priv *priv,
return 0;
}
-static int graph_parse_node(struct simple_util_priv *priv,
- enum graph_type gtype,
- struct device_node *port,
- struct link_info *li, int is_cpu)
+static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
+ int *nm_idx, int cpu_idx,
+ struct device_node *mcpu_port)
{
- struct device_node *ep;
- int ret = 0;
+ /*
+ * +---+ +---+
+ * | X|<-@------->|x |
+ * | | | |
+ * cpu0 <--|A 1|<--------->|4 a|-> codec0
+ * cpu1 <--|B 2|<-----+--->|5 b|-> codec1
+ * cpu2 <--|C 3|<----/ +---+
+ * +---+
+ *
+ * multi {
+ * ports {
+ * port@0 { mcpu_top_ep {... = mcodec_ep; }; }; // (X) to pair
+ * <mcpu_port> port@1 { mcpu0_ep { ... = cpu0_ep; }; // (A) Multi Element
+ * mcpu0_ep_0 { ... = mcodec0_ep_0; }; }; // (1) connected Codec
+ * port@2 { mcpu1_ep { ... = cpu1_ep; }; // (B) Multi Element
+ * mcpu1_ep_0 { ... = mcodec1_ep_0; }; }; // (2) connected Codec
+ * port@3 { mcpu2_ep { ... = cpu2_ep; }; // (C) Multi Element
+ * mcpu2_ep_0 { ... = mcodec1_ep_1; }; }; // (3) connected Codec
+ * };
+ *
+ * ports {
+ * port@0 { mcodec_top_ep {... = mcpu_ep; }; }; // (x) to pair
+ * <mcodec_port>port@1 { mcodec0_ep { ... = codec0_ep; }; // (a) Multi Element
+ * mcodec0_ep_0 { ... = mcpu0_ep_0; }; }; // (4) connected CPU
+ * port@2 { mcodec1_ep { ... = codec1_ep; }; // (b) Multi Element
+ * mcodec1_ep_0 { ... = mcpu1_ep_0; }; // (5) connected CPU
+ * mcodec1_ep_1 { ... = mcpu2_ep_0; }; }; // (5) connected CPU
+ * };
+ * };
+ */
+ struct device_node *mcpu_ep = port_to_endpoint(mcpu_port);
+ struct device_node *mcpu_ep_n = mcpu_ep;
+ struct device_node *mcpu_port_top = of_get_next_child(of_get_parent(mcpu_port), NULL);
+ struct device_node *mcpu_ep_top = port_to_endpoint(mcpu_port_top);
+ struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top);
+ struct device_node *mcodec_port_top = of_get_parent(mcodec_ep_top);
+ struct device_node *mcodec_ports = of_get_parent(mcodec_port_top);
+ int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
+ int ret = -EINVAL;
- if (graph_lnk_is_multi(port)) {
- int idx;
+ if (cpu_idx > dai_link->num_cpus)
+ goto mcpu_err;
- of_node_get(port);
+ while (1) {
+ struct device_node *mcodec_ep_n;
+ struct device_node *mcodec_port_i;
+ struct device_node *mcodec_port;
+ int codec_idx;
- for (idx = 0;; idx++) {
- ep = graph_get_next_multi_ep(&port);
- if (!ep)
- break;
+ if (*nm_idx > nm_max)
+ break;
- ret = __graph_parse_node(priv, gtype, ep,
- li, is_cpu, idx);
- of_node_put(ep);
- if (ret < 0)
+ mcpu_ep_n = of_get_next_child(mcpu_port, mcpu_ep_n);
+ if (!mcpu_ep_n) {
+ ret = 0;
+ break;
+ }
+
+ mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n);
+ mcodec_port = of_get_parent(mcodec_ep_n);
+
+ if (mcodec_ports != of_get_parent(mcodec_port))
+ goto mcpu_err;
+
+ codec_idx = 0;
+ mcodec_port_i = of_get_next_child(mcodec_ports, NULL);
+ while (1) {
+ if (codec_idx > dai_link->num_codecs)
+ goto mcodec_err;
+
+ mcodec_port_i = of_get_next_child(mcodec_ports, mcodec_port_i);
+
+ if (!mcodec_port_i)
+ goto mcodec_err;
+
+ if (mcodec_port_i == mcodec_port)
break;
+
+ codec_idx++;
}
- } else {
- /* Single CPU / Codec */
- ep = port_to_endpoint(port);
- ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0);
+
+ dai_link->ch_maps[*nm_idx].cpu = cpu_idx;
+ dai_link->ch_maps[*nm_idx].codec = codec_idx;
+
+ (*nm_idx)++;
+
+ of_node_put(mcodec_port_i);
+mcodec_err:
+ of_node_put(mcodec_port);
+ of_node_put(mcpu_ep_n);
+ of_node_put(mcodec_ep_n);
+ }
+mcpu_err:
+ of_node_put(mcpu_ep);
+ of_node_put(mcpu_port_top);
+ of_node_put(mcpu_ep_top);
+ of_node_put(mcodec_ep_top);
+ of_node_put(mcodec_port_top);
+ of_node_put(mcodec_ports);
+
+ return ret;
+}
+
+static int graph_parse_node_multi(struct simple_util_priv *priv,
+ enum graph_type gtype,
+ struct device_node *port,
+ struct link_info *li, int is_cpu)
+{
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
+ struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *ep;
+ int ret = -ENOMEM;
+ int nm_idx = 0;
+ int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
+
+ /*
+ * create ch_maps if CPU:Codec = N:M
+ * DPCM is out of scope
+ */
+ if (gtype != GRAPH_DPCM && !dai_link->ch_maps &&
+ dai_link->num_cpus > 1 && dai_link->num_codecs > 1 &&
+ dai_link->num_cpus != dai_link->num_codecs) {
+
+ dai_link->ch_maps = devm_kcalloc(dev, nm_max,
+ sizeof(struct snd_soc_dai_link_ch_map), GFP_KERNEL);
+ if (!dai_link->ch_maps)
+ goto multi_err;
+ }
+
+ for (int idx = 0;; idx++) {
+ /*
+ * multi {
+ * ports {
+ * <port> port@0 { ... }; // to pair
+ * port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element
+ * port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element
+ * };
+ * };
+ *
+ * cpu {
+ * ports {
+ * <ep> port@0 { cpu1_ep { ... = mcpu1_ep };};
+ * };
+ * };
+ */
+ ep = graph_get_next_multi_ep(&port);
+ if (!ep)
+ break;
+
+ ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, idx);
of_node_put(ep);
+ if (ret < 0)
+ goto multi_err;
+
+ /* CPU:Codec = N:M */
+ if (is_cpu && dai_link->ch_maps) {
+ ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port);
+ if (ret < 0)
+ goto multi_err;
+ }
}
+ if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max))
+ ret = -EINVAL;
+
+multi_err:
return ret;
}
+static int graph_parse_node_single(struct simple_util_priv *priv,
+ enum graph_type gtype,
+ struct device_node *port,
+ struct link_info *li, int is_cpu)
+{
+ struct device_node *ep = port_to_endpoint(port);
+ int ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0);
+
+ of_node_put(ep);
+
+ return ret;
+}
+
+static int graph_parse_node(struct simple_util_priv *priv,
+ enum graph_type gtype,
+ struct device_node *port,
+ struct link_info *li, int is_cpu)
+{
+ if (graph_lnk_is_multi(port))
+ return graph_parse_node_multi(priv, gtype, port, li, is_cpu);
+ else
+ return graph_parse_node_single(priv, gtype, port, li, is_cpu);
+}
+
static void graph_parse_daifmt(struct device_node *node,
unsigned int *daifmt, unsigned int *bit_frame)
{
@@ -597,6 +759,7 @@ static void graph_link_init(struct simple_util_priv *priv,
struct device_node *ep;
struct device_node *ports;
unsigned int daifmt = 0, daiclk = 0;
+ bool playback_only = 0, capture_only = 0;
unsigned int bit_frame = 0;
if (graph_lnk_is_multi(port)) {
@@ -635,6 +798,11 @@ static void graph_link_init(struct simple_util_priv *priv,
if (is_cpu_node)
daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk);
+ graph_util_parse_link_direction(port, &playback_only, &capture_only);
+
+ dai_link->playback_only = playback_only;
+ dai_link->capture_only = capture_only;
+
dai_link->dai_fmt = daifmt | daiclk;
dai_link->init = simple_util_dai_init;
dai_link->ops = &graph_ops;
@@ -920,17 +1088,33 @@ static int graph_counter(struct device_node *lnk)
*
* multi {
* ports {
- * => lnk: port@0 { ... };
- * port@1 { ... };
- * port@2 { ... };
+ * => lnk: port@0 { ... }; // to pair
+ * port@1 { ... }; // Multi Element
+ * port@2 { ... }; // Multi Element
* ...
* };
* };
*
* ignore first lnk part
*/
- if (graph_lnk_is_multi(lnk))
- return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1;
+ if (graph_lnk_is_multi(lnk)) {
+ struct device_node *ports = of_get_parent(lnk);
+ struct device_node *port = NULL;
+ int cnt = 0;
+
+ /*
+ * CPU/Codec = N:M case has many endpoints.
+ * We can't use of_graph_get_endpoint_count() here
+ */
+ while(1) {
+ port = of_get_next_child(ports, port);
+ if (!port)
+ break;
+ cnt++;
+ }
+
+ return cnt - 1;
+ }
/*
* Single CPU / Codec
*/
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index cfa70a56f..81077d16d 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -5,7 +5,6 @@
// Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -1129,6 +1128,25 @@ parse_dai_end:
}
EXPORT_SYMBOL_GPL(graph_util_parse_dai);
+int graph_util_parse_link_direction(struct device_node *np,
+ bool *playback_only, bool *capture_only)
+{
+ bool is_playback_only = false;
+ bool is_capture_only = false;
+
+ is_playback_only = of_property_read_bool(np, "playback-only");
+ is_capture_only = of_property_read_bool(np, "capture-only");
+
+ if (is_playback_only && is_capture_only)
+ return -EINVAL;
+
+ *playback_only = is_playback_only;
+ *capture_only = is_capture_only;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(graph_util_parse_link_direction);
+
/* Module information */
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");