aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/audio-graph-card.txt124
-rw-r--r--Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt117
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt37
-rw-r--r--Documentation/devicetree/bindings/sound/simple-scu-card.txt67
-rw-r--r--drivers/of/base.c62
-rw-r--r--include/linux/of_graph.h21
-rw-r--r--include/sound/simple_card_utils.h19
-rw-r--r--include/sound/soc.h3
-rw-r--r--sound/soc/generic/Kconfig17
-rw-r--r--sound/soc/generic/Makefile4
-rw-r--r--sound/soc/generic/audio-graph-card.c301
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c411
-rw-r--r--sound/soc/generic/simple-card-utils.c96
-rw-r--r--sound/soc/generic/simple-card.c15
-rw-r--r--sound/soc/generic/simple-scu-card.c19
-rw-r--r--sound/soc/sh/Kconfig2
-rw-r--r--sound/soc/sh/rcar/adg.c8
-rw-r--r--sound/soc/sh/rcar/cmd.c3
-rw-r--r--sound/soc/sh/rcar/core.c208
-rw-r--r--sound/soc/sh/rcar/dma.c26
-rw-r--r--sound/soc/sh/rcar/gen.c2
-rw-r--r--sound/soc/sh/rcar/rsnd.h19
-rw-r--r--sound/soc/sh/rcar/src.c18
-rw-r--r--sound/soc/sh/rcar/ssi.c78
-rw-r--r--sound/soc/sh/rcar/ssiu.c37
-rw-r--r--sound/soc/soc-core.c47
26 files changed, 1546 insertions, 215 deletions
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-card.txt
new file mode 100644
index 000000000000..bac4b1b1060f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/audio-graph-card.txt
@@ -0,0 +1,124 @@
1Audio Graph Card:
2
3Audio Graph Card specifies audio DAI connections of SoC <-> codec.
4It is based on common bindings for device graphs.
5see ${LINUX}/Documentation/devicetree/bindings/graph.txt
6
7Basically, Audio Graph Card property is same as Simple Card.
8see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
9
10Below are same as Simple-Card.
11
12- label
13- dai-format
14- frame-master
15- bitclock-master
16- bitclock-inversion
17- frame-inversion
18- dai-tdm-slot-num
19- dai-tdm-slot-width
20- clocks / system-clock-frequency
21
22Required properties:
23
24- compatible : "audio-graph-card";
25- dais : list of CPU DAI port{s}
26
27Example: Single DAI case
28
29 sound_card {
30 compatible = "audio-graph-card";
31
32 dais = <&cpu_port>;
33 };
34
35 dai-controller {
36 ...
37 cpu_port: port {
38 cpu_endpoint: endpoint {
39 remote-endpoint = <&codec_endpoint>;
40
41 dai-format = "left_j";
42 ...
43 };
44 };
45 };
46
47 audio-codec {
48 ...
49 port {
50 codec_endpoint: endpoint {
51 remote-endpoint = <&cpu_endpoint>;
52 };
53 };
54 };
55
56Example: Multi DAI case
57
58 sound-card {
59 compatible = "audio-graph-card";
60
61 label = "sound-card";
62
63 dais = <&cpu_port0
64 &cpu_port1
65 &cpu_port2>;
66 };
67
68 audio-codec@0 {
69 ...
70 port {
71 codec0_endpoint: endpoint {
72 remote-endpoint = <&cpu_endpoint0>;
73 };
74 };
75 };
76
77 audio-codec@1 {
78 ...
79 port {
80 codec1_endpoint: endpoint {
81 remote-endpoint = <&cpu_endpoint1>;
82 };
83 };
84 };
85
86 audio-codec@2 {
87 ...
88 port {
89 codec2_endpoint: endpoint {
90 remote-endpoint = <&cpu_endpoint2>;
91 };
92 };
93 };
94
95 dai-controller {
96 ...
97 ports {
98 cpu_port0: port@0 {
99 cpu_endpoint0: endpoint {
100 remote-endpoint = <&codec0_endpoint>;
101
102 dai-format = "left_j";
103 ...
104 };
105 };
106 cpu_port1: port@1 {
107 cpu_endpoint1: endpoint {
108 remote-endpoint = <&codec1_endpoint>;
109
110 dai-format = "i2s";
111 ...
112 };
113 };
114 cpu_port2: port@2 {
115 cpu_endpoint2: endpoint {
116 remote-endpoint = <&codec2_endpoint>;
117
118 dai-format = "i2s";
119 ...
120 };
121 };
122 };
123 };
124
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
new file mode 100644
index 000000000000..b63c5594bbb3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
@@ -0,0 +1,117 @@
1Audio-Graph-SCU-Card:
2
3Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM".
4
5It is based on common bindings for device graphs.
6see ${LINUX}/Documentation/devicetree/bindings/graph.txt
7
8Basically, Audio-Graph-SCU-Card property is same as
9Simple-Card / Simple-SCU-Card / Audio-Graph-Card.
10see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
11 ${LINUX}/Documentation/devicetree/bindings/sound/simple-scu-card.txt
12 ${LINUX}/Documentation/devicetree/bindings/sound/audio-graph-card.txt
13
14Below are same as Simple-Card / Audio-Graph-Card.
15
16- label
17- dai-format
18- frame-master
19- bitclock-master
20- bitclock-inversion
21- frame-inversion
22- dai-tdm-slot-num
23- dai-tdm-slot-width
24- clocks / system-clock-frequency
25
26Below are same as Simple-SCU-Card.
27
28- convert-rate
29- convert-channels
30- prefix
31- routing
32
33Required properties:
34
35- compatible : "audio-graph-scu-card";
36- dais : list of CPU DAI port{s}
37
38Example 1. Sampling Rate Conversion
39
40 sound_card {
41 compatible = "audio-graph-scu-card";
42
43 label = "sound-card";
44 prefix = "codec";
45 routing = "codec Playback", "DAI0 Playback",
46 "codec Playback", "DAI1 Playback";
47 convert-rate = <48000>;
48
49 dais = <&cpu_port>;
50 };
51
52 audio-codec {
53 ...
54
55 port {
56 codec_endpoint: endpoint {
57 remote-endpoint = <&cpu_endpoint>;
58 };
59 };
60 };
61
62 dai-controller {
63 ...
64 cpu_port: port {
65 cpu_endpoint: endpoint {
66 remote-endpoint = <&codec_endpoint>;
67
68 dai-format = "left_j";
69 ...
70 };
71 };
72 };
73
74Example 2. 2 CPU 1 Codec (Mixing)
75
76 sound_card {
77 compatible = "audio-graph-scu-card";
78
79 label = "sound-card";
80 prefix = "codec";
81 routing = "codec Playback", "DAI0 Playback",
82 "codec Playback", "DAI1 Playback";
83 convert-rate = <48000>;
84
85 dais = <&cpu_port0
86 &cpu_port1>;
87 };
88
89 audio-codec {
90 ...
91
92 port {
93 codec_endpoint: endpoint {
94 remote-endpoint = <&cpu_endpoint0>;
95 };
96 };
97 };
98
99 dai-controller {
100 ...
101 ports {
102 cpu_port0: port {
103 cpu_endpoint0: endpoint {
104 remote-endpoint = <&codec_endpoint>;
105
106 dai-format = "left_j";
107 ...
108 };
109 };
110 cpu_port1: port {
111 cpu_endpoint1: endpoint {
112 dai-format = "left_j";
113 ...
114 };
115 };
116 };
117 };
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index 15a7316e4c91..7246bb268bf9 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -83,11 +83,11 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
83** Asynchronous mode 83** Asynchronous mode
84------------------ 84------------------
85 85
86You need to use "renesas,rsrc-card" sound card for it. 86You need to use "simple-scu-audio-card" sound card for it.
87example) 87example)
88 88
89 sound { 89 sound {
90 compatible = "renesas,rsrc-card"; 90 compatible = "simple-scu-audio-card";
91 ... 91 ...
92 /* 92 /*
93 * SRC Asynchronous mode setting 93 * SRC Asynchronous mode setting
@@ -97,12 +97,12 @@ example)
97 * Inputed 48kHz data will be converted to 97 * Inputed 48kHz data will be converted to
98 * system specified Hz 98 * system specified Hz
99 */ 99 */
100 convert-rate = <48000>; 100 simple-audio-card,convert-rate = <48000>;
101 ... 101 ...
102 cpu { 102 simple-audio-card,cpu {
103 sound-dai = <&rcar_sound>; 103 sound-dai = <&rcar_sound>;
104 }; 104 };
105 codec { 105 simple-audio-card,codec {
106 ... 106 ...
107 }; 107 };
108 }; 108 };
@@ -141,23 +141,23 @@ For more detail information, see below
141 ${LINUX}/sound/soc/sh/rcar/ctu.c 141 ${LINUX}/sound/soc/sh/rcar/ctu.c
142 - comment of header 142 - comment of header
143 143
144You need to use "renesas,rsrc-card" sound card for it. 144You need to use "simple-scu-audio-card" sound card for it.
145example) 145example)
146 146
147 sound { 147 sound {
148 compatible = "renesas,rsrc-card"; 148 compatible = "simple-scu-audio-card";
149 ... 149 ...
150 /* 150 /*
151 * CTU setting 151 * CTU setting
152 * All input data will be converted to 2ch 152 * All input data will be converted to 2ch
153 * as output data 153 * as output data
154 */ 154 */
155 convert-channels = <2>; 155 simple-audio-card,convert-channels = <2>;
156 ... 156 ...
157 cpu { 157 simple-audio-card,cpu {
158 sound-dai = <&rcar_sound>; 158 sound-dai = <&rcar_sound>;
159 }; 159 };
160 codec { 160 simple-audio-card,codec {
161 ... 161 ...
162 }; 162 };
163 }; 163 };
@@ -190,22 +190,22 @@ and these sounds will be merged by MIX.
190 aplay -D plughw:0,0 xxxx.wav & 190 aplay -D plughw:0,0 xxxx.wav &
191 aplay -D plughw:0,1 yyyy.wav 191 aplay -D plughw:0,1 yyyy.wav
192 192
193You need to use "renesas,rsrc-card" sound card for it. 193You need to use "simple-scu-audio-card" sound card for it.
194Ex) 194Ex)
195 [MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0] 195 [MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
196 | 196 |
197 [MEM] -> [SRC2] -> [CTU03] -+ 197 [MEM] -> [SRC2] -> [CTU03] -+
198 198
199 sound { 199 sound {
200 compatible = "renesas,rsrc-card"; 200 compatible = "simple-scu-audio-card";
201 ... 201 ...
202 cpu@0 { 202 simple-audio-card,cpu@0 {
203 sound-dai = <&rcar_sound 0>; 203 sound-dai = <&rcar_sound 0>;
204 }; 204 };
205 cpu@1 { 205 simple-audio-card,cpu@1 {
206 sound-dai = <&rcar_sound 1>; 206 sound-dai = <&rcar_sound 1>;
207 }; 207 };
208 codec { 208 simple-audio-card,codec {
209 ... 209 ...
210 }; 210 };
211 }; 211 };
@@ -368,6 +368,10 @@ Required properties:
368 see below for detail. 368 see below for detail.
369- #sound-dai-cells : it must be 0 if your system is using single DAI 369- #sound-dai-cells : it must be 0 if your system is using single DAI
370 it must be 1 if your system is using multi DAI 370 it must be 1 if your system is using multi DAI
371- clocks : References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks.
372- clock-names : List of necessary clock names.
373 "ssi-all", "ssi.X", "src.X", "mix.X", "ctu.X",
374 "dvc.X", "clk_a", "clk_b", "clk_c", "clk_i"
371 375
372Optional properties: 376Optional properties:
373- #clock-cells : it must be 0 if your system has audio_clkout 377- #clock-cells : it must be 0 if your system has audio_clkout
@@ -375,6 +379,9 @@ Optional properties:
375- clock-frequency : for all audio_clkout0/1/2/3 379- clock-frequency : for all audio_clkout0/1/2/3
376- clkout-lr-asynchronous : boolean property. it indicates that audio_clkoutn 380- clkout-lr-asynchronous : boolean property. it indicates that audio_clkoutn
377 is asynchronizes with lr-clock. 381 is asynchronizes with lr-clock.
382- resets : References to SSI resets.
383- reset-names : List of valid reset names.
384 "ssi-all", "ssi.X"
378 385
379SSI subnode properties: 386SSI subnode properties:
380- interrupts : Should contain SSI interrupt for PIO transfer 387- interrupts : Should contain SSI interrupt for PIO transfer
diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
index d6fe47ed09af..327d229a51b2 100644
--- a/Documentation/devicetree/bindings/sound/simple-scu-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
@@ -1,35 +1,29 @@
1ASoC simple SCU Sound Card 1ASoC Simple SCU Sound Card
2 2
3Simple-Card specifies audio DAI connections of SoC <-> codec. 3Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM".
4For example, you can use this driver if you want to exchange sampling rate convert,
5Mixing, etc...
4 6
5Required properties: 7Required properties:
6 8
7- compatible : "simple-scu-audio-card" 9- compatible : "simple-scu-audio-card"
8 "renesas,rsrc-card" 10 "renesas,rsrc-card"
9
10Optional properties: 11Optional properties:
11 12
12- simple-audio-card,name : User specified audio sound card name, one string 13- simple-audio-card,name : see simple-audio-card.txt
13 property. 14- simple-audio-card,cpu : see simple-audio-card.txt
14- simple-audio-card,cpu : CPU sub-node 15- simple-audio-card,codec : see simple-audio-card.txt
15- simple-audio-card,codec : CODEC sub-node
16 16
17Optional subnode properties: 17Optional subnode properties:
18 18
19- simple-audio-card,format : CPU/CODEC common audio format. 19- simple-audio-card,format : see simple-audio-card.txt
20 "i2s", "right_j", "left_j" , "dsp_a" 20- simple-audio-card,frame-master : see simple-audio-card.txt
21 "dsp_b", "ac97", "pdm", "msb", "lsb" 21- simple-audio-card,bitclock-master : see simple-audio-card.txt
22- simple-audio-card,frame-master : Indicates dai-link frame master. 22- simple-audio-card,bitclock-inversion : see simple-audio-card.txt
23 phandle to a cpu or codec subnode. 23- simple-audio-card,frame-inversion : see simple-audio-card.txt
24- simple-audio-card,bitclock-master : Indicates dai-link bit clock master.
25 phandle to a cpu or codec subnode.
26- simple-audio-card,bitclock-inversion : bool property. Add this if the
27 dai-link uses bit clock inversion.
28- simple-audio-card,frame-inversion : bool property. Add this if the
29 dai-link uses frame clock inversion.
30- simple-audio-card,convert-rate : platform specified sampling rate convert 24- simple-audio-card,convert-rate : platform specified sampling rate convert
31- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch) 25- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch)
32- simple-audio-card,prefix : see audio-routing 26- simple-audio-card,prefix : see routing
33- simple-audio-card,routing : A list of the connections between audio components. 27- simple-audio-card,routing : A list of the connections between audio components.
34 Each entry is a pair of strings, the first being the connection's sink, 28 Each entry is a pair of strings, the first being the connection's sink,
35 the second being the connection's source. Valid names for sources. 29 the second being the connection's source. Valid names for sources.
@@ -38,32 +32,23 @@ Optional subnode properties:
38 32
39Required CPU/CODEC subnodes properties: 33Required CPU/CODEC subnodes properties:
40 34
41- sound-dai : phandle and port of CPU/CODEC 35- sound-dai : see simple-audio-card.txt
42 36
43Optional CPU/CODEC subnodes properties: 37Optional CPU/CODEC subnodes properties:
44 38
45- clocks / system-clock-frequency : specify subnode's clock if needed. 39- clocks / system-clock-frequency : see simple-audio-card.txt
46 it can be specified via "clocks" if system has
47 clock node (= common clock), or "system-clock-frequency"
48 (if system doens't support common clock)
49 If a clock is specified, it is
50 enabled with clk_prepare_enable()
51 in dai startup() and disabled with
52 clk_disable_unprepare() in dai
53 shutdown().
54 40
55Example 1. Sampling Rate Covert 41Example 1. Sampling Rate Conversion
56 42
57sound { 43sound {
58 compatible = "simple-scu-audio-card"; 44 compatible = "simple-scu-audio-card";
59 45
60 simple-audio-card,name = "rsnd-ak4643"; 46 simple-audio-card,name = "rsnd-ak4643";
61 simple-audio-card,format = "left_j"; 47 simple-audio-card,format = "left_j";
62 simple-audio-card,format = "left_j";
63 simple-audio-card,bitclock-master = <&sndcodec>; 48 simple-audio-card,bitclock-master = <&sndcodec>;
64 simple-audio-card,frame-master = <&sndcodec>; 49 simple-audio-card,frame-master = <&sndcodec>;
65 50
66 simple-audio-card,convert-rate = <48000>; /* see audio_clk_a */ 51 simple-audio-card,convert-rate = <48000>;
67 52
68 simple-audio-card,prefix = "ak4642"; 53 simple-audio-card,prefix = "ak4642";
69 simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", 54 simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
@@ -79,20 +64,18 @@ sound {
79 }; 64 };
80}; 65};
81 66
82Example 2. 2 CPU 1 Codec 67Example 2. 2 CPU 1 Codec (Mixing)
83 68
84sound { 69sound {
85 compatible = "renesas,rsrc-card"; 70 compatible = "simple-scu-audio-card";
86
87 card-name = "rsnd-ak4643";
88 format = "left_j";
89 bitclock-master = <&dpcmcpu>;
90 frame-master = <&dpcmcpu>;
91 71
92 convert-rate = <48000>; /* see audio_clk_a */ 72 simple-audio-card,name = "rsnd-ak4643";
73 simple-audio-card,format = "left_j";
74 simple-audio-card,bitclock-master = <&dpcmcpu>;
75 simple-audio-card,frame-master = <&dpcmcpu>;
93 76
94 audio-prefix = "ak4642"; 77 simple-audio-card,prefix = "ak4642";
95 audio-routing = "ak4642 Playback", "DAI0 Playback", 78 simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
96 "ak4642 Playback", "DAI1 Playback"; 79 "ak4642 Playback", "DAI1 Playback";
97 80
98 dpcmcpu: cpu@0 { 81 dpcmcpu: cpu@0 {
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 28d5f53bc631..cb1c49ae3b88 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1601,6 +1601,7 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
1601 1601
1602 return 0; 1602 return 0;
1603} 1603}
1604EXPORT_SYMBOL_GPL(of_phandle_iterator_init);
1604 1605
1605int of_phandle_iterator_next(struct of_phandle_iterator *it) 1606int of_phandle_iterator_next(struct of_phandle_iterator *it)
1606{ 1607{
@@ -1670,6 +1671,7 @@ err:
1670 1671
1671 return -EINVAL; 1672 return -EINVAL;
1672} 1673}
1674EXPORT_SYMBOL_GPL(of_phandle_iterator_next);
1673 1675
1674int of_phandle_iterator_args(struct of_phandle_iterator *it, 1676int of_phandle_iterator_args(struct of_phandle_iterator *it,
1675 uint32_t *args, 1677 uint32_t *args,
@@ -2485,6 +2487,41 @@ struct device_node *of_graph_get_endpoint_by_regs(
2485EXPORT_SYMBOL(of_graph_get_endpoint_by_regs); 2487EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
2486 2488
2487/** 2489/**
2490 * of_graph_get_remote_endpoint() - get remote endpoint node
2491 * @node: pointer to a local endpoint device_node
2492 *
2493 * Return: Remote endpoint node associated with remote endpoint node linked
2494 * to @node. Use of_node_put() on it when done.
2495 */
2496struct device_node *of_graph_get_remote_endpoint(const struct device_node *node)
2497{
2498 /* Get remote endpoint node. */
2499 return of_parse_phandle(node, "remote-endpoint", 0);
2500}
2501EXPORT_SYMBOL(of_graph_get_remote_endpoint);
2502
2503/**
2504 * of_graph_get_port_parent() - get port's parent node
2505 * @node: pointer to a local endpoint device_node
2506 *
2507 * Return: device node associated with endpoint node linked
2508 * to @node. Use of_node_put() on it when done.
2509 */
2510struct device_node *of_graph_get_port_parent(struct device_node *node)
2511{
2512 unsigned int depth;
2513
2514 /* Walk 3 levels up only if there is 'ports' node. */
2515 for (depth = 3; depth && node; depth--) {
2516 node = of_get_next_parent(node);
2517 if (depth == 2 && of_node_cmp(node->name, "ports"))
2518 break;
2519 }
2520 return node;
2521}
2522EXPORT_SYMBOL(of_graph_get_port_parent);
2523
2524/**
2488 * of_graph_get_remote_port_parent() - get remote port's parent node 2525 * of_graph_get_remote_port_parent() - get remote port's parent node
2489 * @node: pointer to a local endpoint device_node 2526 * @node: pointer to a local endpoint device_node
2490 * 2527 *
@@ -2495,18 +2532,11 @@ struct device_node *of_graph_get_remote_port_parent(
2495 const struct device_node *node) 2532 const struct device_node *node)
2496{ 2533{
2497 struct device_node *np; 2534 struct device_node *np;
2498 unsigned int depth;
2499 2535
2500 /* Get remote endpoint node. */ 2536 /* Get remote endpoint node. */
2501 np = of_parse_phandle(node, "remote-endpoint", 0); 2537 np = of_graph_get_remote_endpoint(node);
2502 2538
2503 /* Walk 3 levels up only if there is 'ports' node. */ 2539 return of_graph_get_port_parent(np);
2504 for (depth = 3; depth && np; depth--) {
2505 np = of_get_next_parent(np);
2506 if (depth == 2 && of_node_cmp(np->name, "ports"))
2507 break;
2508 }
2509 return np;
2510} 2540}
2511EXPORT_SYMBOL(of_graph_get_remote_port_parent); 2541EXPORT_SYMBOL(of_graph_get_remote_port_parent);
2512 2542
@@ -2522,13 +2552,25 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node)
2522 struct device_node *np; 2552 struct device_node *np;
2523 2553
2524 /* Get remote endpoint node. */ 2554 /* Get remote endpoint node. */
2525 np = of_parse_phandle(node, "remote-endpoint", 0); 2555 np = of_graph_get_remote_endpoint(node);
2526 if (!np) 2556 if (!np)
2527 return NULL; 2557 return NULL;
2528 return of_get_next_parent(np); 2558 return of_get_next_parent(np);
2529} 2559}
2530EXPORT_SYMBOL(of_graph_get_remote_port); 2560EXPORT_SYMBOL(of_graph_get_remote_port);
2531 2561
2562int of_graph_get_endpoint_count(const struct device_node *np)
2563{
2564 struct device_node *endpoint;
2565 int num = 0;
2566
2567 for_each_endpoint_of_node(np, endpoint)
2568 num++;
2569
2570 return num;
2571}
2572EXPORT_SYMBOL(of_graph_get_endpoint_count);
2573
2532/** 2574/**
2533 * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint 2575 * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
2534 * @node: pointer to parent device_node containing graph port/endpoint 2576 * @node: pointer to parent device_node containing graph port/endpoint
diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h
index abdb02eaef06..3e058f05ab04 100644
--- a/include/linux/of_graph.h
+++ b/include/linux/of_graph.h
@@ -43,11 +43,15 @@ struct of_endpoint {
43#ifdef CONFIG_OF 43#ifdef CONFIG_OF
44int of_graph_parse_endpoint(const struct device_node *node, 44int of_graph_parse_endpoint(const struct device_node *node,
45 struct of_endpoint *endpoint); 45 struct of_endpoint *endpoint);
46int of_graph_get_endpoint_count(const struct device_node *np);
46struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); 47struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
47struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, 48struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
48 struct device_node *previous); 49 struct device_node *previous);
49struct device_node *of_graph_get_endpoint_by_regs( 50struct device_node *of_graph_get_endpoint_by_regs(
50 const struct device_node *parent, int port_reg, int reg); 51 const struct device_node *parent, int port_reg, int reg);
52struct device_node *of_graph_get_remote_endpoint(
53 const struct device_node *node);
54struct device_node *of_graph_get_port_parent(struct device_node *node);
51struct device_node *of_graph_get_remote_port_parent( 55struct device_node *of_graph_get_remote_port_parent(
52 const struct device_node *node); 56 const struct device_node *node);
53struct device_node *of_graph_get_remote_port(const struct device_node *node); 57struct device_node *of_graph_get_remote_port(const struct device_node *node);
@@ -61,6 +65,11 @@ static inline int of_graph_parse_endpoint(const struct device_node *node,
61 return -ENOSYS; 65 return -ENOSYS;
62} 66}
63 67
68static inline int of_graph_get_endpoint_count(const struct device_node *np)
69{
70 return 0;
71}
72
64static inline struct device_node *of_graph_get_port_by_id( 73static inline struct device_node *of_graph_get_port_by_id(
65 struct device_node *node, u32 id) 74 struct device_node *node, u32 id)
66{ 75{
@@ -80,6 +89,18 @@ static inline struct device_node *of_graph_get_endpoint_by_regs(
80 return NULL; 89 return NULL;
81} 90}
82 91
92static inline struct device_node *of_graph_get_remote_endpoint(
93 const struct device_node *node)
94{
95 return NULL;
96}
97
98static inline struct device_node *of_graph_get_port_parent(
99 struct device_node *node)
100{
101 return NULL;
102}
103
83static inline struct device_node *of_graph_get_remote_port_parent( 104static inline struct device_node *of_graph_get_remote_port_parent(
84 const struct device_node *node) 105 const struct device_node *node)
85{ 106{
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index af58d2362975..108cae459ed0 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -35,13 +35,16 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
35 char *prefix); 35 char *prefix);
36 36
37#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \ 37#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
38 asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai) 38 asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
39 dai_link->cpu_dai_name)
39#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \ 40#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
40 asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai) 41 asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
42 dai_link->codec_dai_name)
41int asoc_simple_card_parse_clk(struct device *dev, 43int asoc_simple_card_parse_clk(struct device *dev,
42 struct device_node *node, 44 struct device_node *node,
43 struct device_node *dai_of_node, 45 struct device_node *dai_of_node,
44 struct asoc_simple_dai *simple_dai); 46 struct asoc_simple_dai *simple_dai,
47 const char *name);
45 48
46#define asoc_simple_card_parse_cpu(node, dai_link, \ 49#define asoc_simple_card_parse_cpu(node, dai_link, \
47 list_name, cells_name, is_single_link) \ 50 list_name, cells_name, is_single_link) \
@@ -60,6 +63,16 @@ int asoc_simple_card_parse_dai(struct device_node *node,
60 const char *cells_name, 63 const char *cells_name,
61 int *is_single_links); 64 int *is_single_links);
62 65
66#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \
67 asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \
68 &dai_link->cpu_dai_name)
69#define asoc_simple_card_parse_graph_codec(ep, dai_link) \
70 asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \
71 &dai_link->codec_dai_name)
72int asoc_simple_card_parse_graph_dai(struct device_node *ep,
73 struct device_node **endpoint_np,
74 const char **dai_name);
75
63int asoc_simple_card_init_dai(struct snd_soc_dai *dai, 76int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
64 struct asoc_simple_dai *simple_dai); 77 struct asoc_simple_dai *simple_dai);
65 78
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 5170fd81e1fd..9c94b97c17f8 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -803,6 +803,8 @@ struct snd_soc_component_driver {
803 int (*of_xlate_dai_name)(struct snd_soc_component *component, 803 int (*of_xlate_dai_name)(struct snd_soc_component *component,
804 struct of_phandle_args *args, 804 struct of_phandle_args *args,
805 const char **dai_name); 805 const char **dai_name);
806 int (*of_xlate_dai_id)(struct snd_soc_component *comment,
807 struct device_node *endpoint);
806 void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, 808 void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type,
807 int subseq); 809 int subseq);
808 int (*stream_event)(struct snd_soc_component *, int event); 810 int (*stream_event)(struct snd_soc_component *, int event);
@@ -1676,6 +1678,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
1676 const char *prefix, 1678 const char *prefix,
1677 struct device_node **bitclkmaster, 1679 struct device_node **bitclkmaster,
1678 struct device_node **framemaster); 1680 struct device_node **framemaster);
1681int snd_soc_get_dai_id(struct device_node *ep);
1679int snd_soc_get_dai_name(struct of_phandle_args *args, 1682int snd_soc_get_dai_name(struct of_phandle_args *args,
1680 const char **dai_name); 1683 const char **dai_name);
1681int snd_soc_of_get_dai_name(struct device_node *of_node, 1684int snd_soc_of_get_dai_name(struct device_node *of_node,
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index d023959b8cd6..c954be0a0f96 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -14,3 +14,20 @@ config SND_SIMPLE_SCU_CARD
14 help 14 help
15 This option enables generic simple SCU sound card support. 15 This option enables generic simple SCU sound card support.
16 It supports DPCM of multi CPU single Codec system. 16 It supports DPCM of multi CPU single Codec system.
17
18config SND_AUDIO_GRAPH_CARD
19 tristate "ASoC Audio Graph sound card support"
20 depends on OF
21 select SND_SIMPLE_CARD_UTILS
22 help
23 This option enables generic simple simple sound card support
24 with OF-graph DT bindings.
25
26config SND_AUDIO_GRAPH_SCU_CARD
27 tristate "ASoC Audio Graph SCU sound card support"
28 depends on OF
29 select SND_SIMPLE_CARD_UTILS
30 help
31 This option enables generic simple SCU sound card support
32 with OF-graph DT bindings.
33 It supports DPCM of multi CPU single Codec ststem.
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
index ee750f3023ba..9e000523a3b4 100644
--- a/sound/soc/generic/Makefile
+++ b/sound/soc/generic/Makefile
@@ -1,7 +1,11 @@
1snd-soc-simple-card-utils-objs := simple-card-utils.o 1snd-soc-simple-card-utils-objs := simple-card-utils.o
2snd-soc-simple-card-objs := simple-card.o 2snd-soc-simple-card-objs := simple-card.o
3snd-soc-simple-scu-card-objs := simple-scu-card.o 3snd-soc-simple-scu-card-objs := simple-scu-card.o
4snd-soc-audio-graph-card-objs := audio-graph-card.o
5snd-soc-audio-graph-scu-card-objs := audio-graph-scu-card.o
4 6
5obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o 7obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o
6obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o 8obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o
7obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o 9obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o
10obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o
11obj-$(CONFIG_SND_AUDIO_GRAPH_SCU_CARD) += snd-soc-audio-graph-scu-card.o
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
new file mode 100644
index 000000000000..0180b286bee3
--- /dev/null
+++ b/sound/soc/generic/audio-graph-card.c
@@ -0,0 +1,301 @@
1/*
2 * ASoC audio graph sound card support
3 *
4 * Copyright (C) 2016 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * based on ${LINUX}/sound/soc/generic/simple-card.c
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/clk.h>
14#include <linux/device.h>
15#include <linux/gpio.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/of_device.h>
19#include <linux/of_gpio.h>
20#include <linux/of_graph.h>
21#include <linux/platform_device.h>
22#include <linux/string.h>
23#include <sound/jack.h>
24#include <sound/simple_card_utils.h>
25
26struct graph_card_data {
27 struct snd_soc_card snd_card;
28 struct graph_dai_props {
29 struct asoc_simple_dai cpu_dai;
30 struct asoc_simple_dai codec_dai;
31 } *dai_props;
32 struct snd_soc_dai_link *dai_link;
33};
34
35#define graph_priv_to_card(priv) (&(priv)->snd_card)
36#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
37#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
38#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
39
40static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
41{
42 struct snd_soc_pcm_runtime *rtd = substream->private_data;
43 struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
44 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
45 int ret;
46
47 ret = clk_prepare_enable(dai_props->cpu_dai.clk);
48 if (ret)
49 return ret;
50
51 ret = clk_prepare_enable(dai_props->codec_dai.clk);
52 if (ret)
53 clk_disable_unprepare(dai_props->cpu_dai.clk);
54
55 return ret;
56}
57
58static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
59{
60 struct snd_soc_pcm_runtime *rtd = substream->private_data;
61 struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
62 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
63
64 clk_disable_unprepare(dai_props->cpu_dai.clk);
65
66 clk_disable_unprepare(dai_props->codec_dai.clk);
67}
68
69static struct snd_soc_ops asoc_graph_card_ops = {
70 .startup = asoc_graph_card_startup,
71 .shutdown = asoc_graph_card_shutdown,
72};
73
74static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
75{
76 struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
77 struct snd_soc_dai *codec = rtd->codec_dai;
78 struct snd_soc_dai *cpu = rtd->cpu_dai;
79 struct graph_dai_props *dai_props =
80 graph_priv_to_props(priv, rtd->num);
81 int ret;
82
83 ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
84 if (ret < 0)
85 return ret;
86
87 ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
88 if (ret < 0)
89 return ret;
90
91 return 0;
92}
93
94static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
95 struct graph_card_data *priv,
96 int idx)
97{
98 struct device *dev = graph_priv_to_dev(priv);
99 struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
100 struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
101 struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
102 struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
103 struct snd_soc_card *card = graph_priv_to_card(priv);
104 struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
105 struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
106 struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
107 int ret;
108
109 if (rcpu_ep != cpu_ep) {
110 dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n",
111 cpu_ep->name, codec_ep->name, rcpu_ep->name);
112 ret = -EINVAL;
113 goto dai_link_of_err;
114 }
115
116 ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
117 NULL, &dai_link->dai_fmt);
118 if (ret < 0)
119 goto dai_link_of_err;
120
121 /*
122 * we need to consider "mclk-fs" around here
123 * see simple-card
124 */
125
126 ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
127 if (ret < 0)
128 goto dai_link_of_err;
129
130 ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
131 if (ret < 0)
132 goto dai_link_of_err;
133
134 ret = snd_soc_of_parse_tdm_slot(cpu_ep,
135 &cpu_dai->tx_slot_mask,
136 &cpu_dai->rx_slot_mask,
137 &cpu_dai->slots,
138 &cpu_dai->slot_width);
139 if (ret < 0)
140 goto dai_link_of_err;
141
142 ret = snd_soc_of_parse_tdm_slot(codec_ep,
143 &codec_dai->tx_slot_mask,
144 &codec_dai->rx_slot_mask,
145 &codec_dai->slots,
146 &codec_dai->slot_width);
147 if (ret < 0)
148 goto dai_link_of_err;
149
150 ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
151 if (ret < 0)
152 goto dai_link_of_err;
153
154 ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
155 if (ret < 0)
156 goto dai_link_of_err;
157
158 ret = asoc_simple_card_canonicalize_dailink(dai_link);
159 if (ret < 0)
160 goto dai_link_of_err;
161
162 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
163 "%s-%s",
164 dai_link->cpu_dai_name,
165 dai_link->codec_dai_name);
166 if (ret < 0)
167 goto dai_link_of_err;
168
169 dai_link->ops = &asoc_graph_card_ops;
170 dai_link->init = asoc_graph_card_dai_init;
171
172 asoc_simple_card_canonicalize_cpu(dai_link,
173 card->num_links == 1);
174
175dai_link_of_err:
176 of_node_put(cpu_ep);
177 of_node_put(rcpu_ep);
178 of_node_put(codec_ep);
179
180 return ret;
181}
182
183static int asoc_graph_card_parse_of(struct graph_card_data *priv)
184{
185 struct of_phandle_iterator it;
186 struct device *dev = graph_priv_to_dev(priv);
187 struct snd_soc_card *card = graph_priv_to_card(priv);
188 struct device_node *node = dev->of_node;
189 int rc, idx = 0;
190 int ret;
191
192 /*
193 * we need to consider "widgets", "routing", "mclk-fs" around here
194 * see simple-card
195 */
196
197 of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
198 ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
199 of_node_put(it.node);
200 if (ret < 0)
201 return ret;
202 }
203
204 return asoc_simple_card_parse_card_name(card, NULL);
205}
206
207static int asoc_graph_get_dais_count(struct device *dev)
208{
209 struct of_phandle_iterator it;
210 struct device_node *node = dev->of_node;
211 int count = 0;
212 int rc;
213
214 of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
215 count++;
216 of_node_put(it.node);
217 }
218
219 return count;
220}
221
222static int asoc_graph_card_probe(struct platform_device *pdev)
223{
224 struct graph_card_data *priv;
225 struct snd_soc_dai_link *dai_link;
226 struct graph_dai_props *dai_props;
227 struct device *dev = &pdev->dev;
228 struct snd_soc_card *card;
229 int num, ret;
230
231 /* Allocate the private data and the DAI link array */
232 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
233 if (!priv)
234 return -ENOMEM;
235
236 num = asoc_graph_get_dais_count(dev);
237 if (num == 0)
238 return -EINVAL;
239
240 dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
241 dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
242 if (!dai_props || !dai_link)
243 return -ENOMEM;
244
245 priv->dai_props = dai_props;
246 priv->dai_link = dai_link;
247
248 /* Init snd_soc_card */
249 card = graph_priv_to_card(priv);
250 card->owner = THIS_MODULE;
251 card->dev = dev;
252 card->dai_link = dai_link;
253 card->num_links = num;
254
255 ret = asoc_graph_card_parse_of(priv);
256 if (ret < 0) {
257 if (ret != -EPROBE_DEFER)
258 dev_err(dev, "parse error %d\n", ret);
259 goto err;
260 }
261
262 snd_soc_card_set_drvdata(card, priv);
263
264 ret = devm_snd_soc_register_card(dev, card);
265 if (ret < 0)
266 goto err;
267
268 return 0;
269err:
270 asoc_simple_card_clean_reference(card);
271
272 return ret;
273}
274
275static int asoc_graph_card_remove(struct platform_device *pdev)
276{
277 struct snd_soc_card *card = platform_get_drvdata(pdev);
278
279 return asoc_simple_card_clean_reference(card);
280}
281
282static const struct of_device_id asoc_graph_of_match[] = {
283 { .compatible = "audio-graph-card", },
284 {},
285};
286MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
287
288static struct platform_driver asoc_graph_card = {
289 .driver = {
290 .name = "asoc-audio-graph-card",
291 .of_match_table = asoc_graph_of_match,
292 },
293 .probe = asoc_graph_card_probe,
294 .remove = asoc_graph_card_remove,
295};
296module_platform_driver(asoc_graph_card);
297
298MODULE_ALIAS("platform:asoc-audio-graph-card");
299MODULE_LICENSE("GPL v2");
300MODULE_DESCRIPTION("ASoC Audio Graph Sound Card");
301MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
new file mode 100644
index 000000000000..0066102f5bc4
--- /dev/null
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -0,0 +1,411 @@
1/*
2 * ASoC audio graph SCU sound card support
3 *
4 * Copyright (C) 2017 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * based on
8 * ${LINUX}/sound/soc/generic/simple-scu-card.c
9 * ${LINUX}/sound/soc/generic/audio-graph-card.c
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15#include <linux/clk.h>
16#include <linux/device.h>
17#include <linux/gpio.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/of_device.h>
21#include <linux/of_gpio.h>
22#include <linux/of_graph.h>
23#include <linux/platform_device.h>
24#include <linux/string.h>
25#include <sound/jack.h>
26#include <sound/simple_card_utils.h>
27
28struct graph_card_data {
29 struct snd_soc_card snd_card;
30 struct snd_soc_codec_conf codec_conf;
31 struct asoc_simple_dai *dai_props;
32 struct snd_soc_dai_link *dai_link;
33 u32 convert_rate;
34 u32 convert_channels;
35};
36
37#define graph_priv_to_card(priv) (&(priv)->snd_card)
38#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
39#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
40#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
41
42static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
43{
44 struct snd_soc_pcm_runtime *rtd = substream->private_data;
45 struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
46 struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
47
48 return clk_prepare_enable(dai_props->clk);
49}
50
51static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
52{
53 struct snd_soc_pcm_runtime *rtd = substream->private_data;
54 struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
55 struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
56
57 clk_disable_unprepare(dai_props->clk);
58}
59
60static struct snd_soc_ops asoc_graph_card_ops = {
61 .startup = asoc_graph_card_startup,
62 .shutdown = asoc_graph_card_shutdown,
63};
64
65static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
66{
67 struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
68 struct snd_soc_dai *dai;
69 struct snd_soc_dai_link *dai_link;
70 struct asoc_simple_dai *dai_props;
71 int num = rtd->num;
72
73 dai_link = graph_priv_to_link(priv, num);
74 dai_props = graph_priv_to_props(priv, num);
75 dai = dai_link->dynamic ?
76 rtd->cpu_dai :
77 rtd->codec_dai;
78
79 return asoc_simple_card_init_dai(dai, dai_props);
80}
81
82static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
83 struct snd_pcm_hw_params *params)
84{
85 struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
86 struct snd_interval *rate = hw_param_interval(params,
87 SNDRV_PCM_HW_PARAM_RATE);
88 struct snd_interval *channels = hw_param_interval(params,
89 SNDRV_PCM_HW_PARAM_CHANNELS);
90
91 if (priv->convert_rate)
92 rate->min =
93 rate->max = priv->convert_rate;
94
95 if (priv->convert_channels)
96 channels->min =
97 channels->max = priv->convert_channels;
98
99 return 0;
100}
101
102static int asoc_graph_card_dai_link_of(struct device_node *ep,
103 struct graph_card_data *priv,
104 unsigned int daifmt,
105 int idx, int is_fe)
106{
107 struct device *dev = graph_priv_to_dev(priv);
108 struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
109 struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, idx);
110 struct snd_soc_card *card = graph_priv_to_card(priv);
111 int ret;
112
113 if (is_fe) {
114 /* BE is dummy */
115 dai_link->codec_of_node = NULL;
116 dai_link->codec_dai_name = "snd-soc-dummy-dai";
117 dai_link->codec_name = "snd-soc-dummy";
118
119 /* FE settings */
120 dai_link->dynamic = 1;
121 dai_link->dpcm_merged_format = 1;
122
123 ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
124 if (ret)
125 return ret;
126
127 ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai_props);
128 if (ret < 0)
129 return ret;
130
131 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
132 "fe.%s",
133 dai_link->cpu_dai_name);
134 if (ret < 0)
135 return ret;
136
137 /* card->num_links includes Codec */
138 asoc_simple_card_canonicalize_cpu(dai_link,
139 (card->num_links - 1) == 1);
140 } else {
141 /* FE is dummy */
142 dai_link->cpu_of_node = NULL;
143 dai_link->cpu_dai_name = "snd-soc-dummy-dai";
144 dai_link->cpu_name = "snd-soc-dummy";
145
146 /* BE settings */
147 dai_link->no_pcm = 1;
148 dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
149
150 ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
151 if (ret < 0)
152 return ret;
153
154 ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai_props);
155 if (ret < 0)
156 return ret;
157
158 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
159 "be.%s",
160 dai_link->codec_dai_name);
161 if (ret < 0)
162 return ret;
163
164 snd_soc_of_parse_audio_prefix(card,
165 &priv->codec_conf,
166 dai_link->codec_of_node,
167 "prefix");
168 }
169
170 ret = snd_soc_of_parse_tdm_slot(ep,
171 &dai_props->tx_slot_mask,
172 &dai_props->rx_slot_mask,
173 &dai_props->slots,
174 &dai_props->slot_width);
175 if (ret)
176 return ret;
177
178 ret = asoc_simple_card_canonicalize_dailink(dai_link);
179 if (ret < 0)
180 return ret;
181
182 dai_link->dai_fmt = daifmt;
183 dai_link->dpcm_playback = 1;
184 dai_link->dpcm_capture = 1;
185 dai_link->ops = &asoc_graph_card_ops;
186 dai_link->init = asoc_graph_card_dai_init;
187
188 return 0;
189}
190
191static int asoc_graph_card_parse_of(struct graph_card_data *priv)
192{
193 struct of_phandle_iterator it;
194 struct device *dev = graph_priv_to_dev(priv);
195 struct snd_soc_card *card = graph_priv_to_card(priv);
196 struct device_node *node = dev->of_node;
197 struct device_node *cpu_port;
198 struct device_node *cpu_ep;
199 struct device_node *codec_ep;
200 struct device_node *rcpu_ep;
201 unsigned int daifmt = 0;
202 int dai_idx, ret;
203 int rc, codec;
204
205 if (!node)
206 return -EINVAL;
207
208 /*
209 * we need to consider "widgets", "mclk-fs" around here
210 * see simple-card
211 */
212
213 ret = snd_soc_of_parse_audio_routing(card, "routing");
214 if (ret)
215 return ret;
216
217 /* sampling rate convert */
218 of_property_read_u32(node, "convert-rate", &priv->convert_rate);
219
220 /* channels transfer */
221 of_property_read_u32(node, "convert-channels", &priv->convert_channels);
222
223 /*
224 * it supports multi CPU, single CODEC only here
225 * see asoc_graph_get_dais_count
226 */
227
228 /* find 1st codec */
229 of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
230 cpu_port = it.node;
231 cpu_ep = of_get_next_child(cpu_port, NULL);
232 codec_ep = of_graph_get_remote_endpoint(cpu_ep);
233 rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
234
235 of_node_put(cpu_port);
236 of_node_put(cpu_ep);
237 of_node_put(codec_ep);
238 of_node_put(rcpu_ep);
239
240 if (!codec_ep)
241 continue;
242
243 if (rcpu_ep != cpu_ep) {
244 dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n",
245 cpu_ep->name, codec_ep->name, rcpu_ep->name);
246 ret = -EINVAL;
247 goto parse_of_err;
248 }
249
250 ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
251 NULL, &daifmt);
252 if (ret < 0)
253 goto parse_of_err;
254 }
255
256 dai_idx = 0;
257 for (codec = 0; codec < 2; codec++) {
258 /*
259 * To listup valid sounds continuously,
260 * detect all CPU-dummy first, and
261 * detect all dummy-Codec second
262 */
263 of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
264 cpu_port = it.node;
265 cpu_ep = of_get_next_child(cpu_port, NULL);
266 codec_ep = of_graph_get_remote_endpoint(cpu_ep);
267
268 of_node_put(cpu_port);
269 of_node_put(cpu_ep);
270 of_node_put(codec_ep);
271
272 if (codec) {
273 if (!codec_ep)
274 continue;
275
276 /* Back-End (= Codec) */
277 ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
278 if (ret < 0)
279 goto parse_of_err;
280 } else {
281 /* Front-End (= CPU) */
282 ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
283 if (ret < 0)
284 goto parse_of_err;
285 }
286 }
287 }
288
289 ret = asoc_simple_card_parse_card_name(card, NULL);
290 if (ret)
291 goto parse_of_err;
292
293 dev_dbg(dev, "convert_rate %d\n", priv->convert_rate);
294 dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
295
296 ret = 0;
297
298parse_of_err:
299 return ret;
300}
301
302static int asoc_graph_get_dais_count(struct device *dev)
303{
304 struct of_phandle_iterator it;
305 struct device_node *node = dev->of_node;
306 struct device_node *cpu_port;
307 struct device_node *cpu_ep;
308 struct device_node *codec_ep;
309 int count = 0;
310 int rc;
311
312 of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
313 cpu_port = it.node;
314 cpu_ep = of_get_next_child(cpu_port, NULL);
315 codec_ep = of_graph_get_remote_endpoint(cpu_ep);
316
317 of_node_put(cpu_port);
318 of_node_put(cpu_ep);
319 of_node_put(codec_ep);
320
321 if (cpu_ep)
322 count++;
323 if (codec_ep)
324 count++;
325 }
326
327 return count;
328}
329
330static int asoc_graph_card_probe(struct platform_device *pdev)
331{
332 struct graph_card_data *priv;
333 struct snd_soc_dai_link *dai_link;
334 struct asoc_simple_dai *dai_props;
335 struct device *dev = &pdev->dev;
336 struct snd_soc_card *card;
337 int num, ret;
338
339 /* Allocate the private data and the DAI link array */
340 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
341 if (!priv)
342 return -ENOMEM;
343
344 num = asoc_graph_get_dais_count(dev);
345 if (num == 0)
346 return -EINVAL;
347
348 dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
349 dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
350 if (!dai_props || !dai_link)
351 return -ENOMEM;
352
353 priv->dai_props = dai_props;
354 priv->dai_link = dai_link;
355
356 /* Init snd_soc_card */
357 card = graph_priv_to_card(priv);
358 card->owner = THIS_MODULE;
359 card->dev = dev;
360 card->dai_link = priv->dai_link;
361 card->num_links = num;
362 card->codec_conf = &priv->codec_conf;
363 card->num_configs = 1;
364
365 ret = asoc_graph_card_parse_of(priv);
366 if (ret < 0) {
367 if (ret != -EPROBE_DEFER)
368 dev_err(dev, "parse error %d\n", ret);
369 goto err;
370 }
371
372 snd_soc_card_set_drvdata(card, priv);
373
374 ret = devm_snd_soc_register_card(dev, card);
375 if (ret < 0)
376 goto err;
377
378 return 0;
379err:
380 asoc_simple_card_clean_reference(card);
381
382 return ret;
383}
384
385static int asoc_graph_card_remove(struct platform_device *pdev)
386{
387 struct snd_soc_card *card = platform_get_drvdata(pdev);
388
389 return asoc_simple_card_clean_reference(card);
390}
391
392static const struct of_device_id asoc_graph_of_match[] = {
393 { .compatible = "audio-graph-scu-card", },
394 {},
395};
396MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
397
398static struct platform_driver asoc_graph_card = {
399 .driver = {
400 .name = "asoc-audio-graph-scu-card",
401 .of_match_table = asoc_graph_of_match,
402 },
403 .probe = asoc_graph_card_probe,
404 .remove = asoc_graph_card_remove,
405};
406module_platform_driver(asoc_graph_card);
407
408MODULE_ALIAS("platform:asoc-audio-graph-scu-card");
409MODULE_LICENSE("GPL v2");
410MODULE_DESCRIPTION("ASoC Audio Graph SCU Sound Card");
411MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 343b291fc372..d9d8b8a58348 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -10,6 +10,7 @@
10#include <linux/clk.h> 10#include <linux/clk.h>
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/of.h> 12#include <linux/of.h>
13#include <linux/of_graph.h>
13#include <sound/simple_card_utils.h> 14#include <sound/simple_card_utils.h>
14 15
15int asoc_simple_card_parse_daifmt(struct device *dev, 16int asoc_simple_card_parse_daifmt(struct device *dev,
@@ -20,14 +21,13 @@ int asoc_simple_card_parse_daifmt(struct device *dev,
20{ 21{
21 struct device_node *bitclkmaster = NULL; 22 struct device_node *bitclkmaster = NULL;
22 struct device_node *framemaster = NULL; 23 struct device_node *framemaster = NULL;
23 int prefix_len = prefix ? strlen(prefix) : 0;
24 unsigned int daifmt; 24 unsigned int daifmt;
25 25
26 daifmt = snd_soc_of_parse_daifmt(node, prefix, 26 daifmt = snd_soc_of_parse_daifmt(node, prefix,
27 &bitclkmaster, &framemaster); 27 &bitclkmaster, &framemaster);
28 daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; 28 daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
29 29
30 if (prefix_len && !bitclkmaster && !framemaster) { 30 if (!bitclkmaster && !framemaster) {
31 /* 31 /*
32 * No dai-link level and master setting was not found from 32 * No dai-link level and master setting was not found from
33 * sound node level, revert back to legacy DT parsing and 33 * sound node level, revert back to legacy DT parsing and
@@ -51,6 +51,8 @@ int asoc_simple_card_parse_daifmt(struct device *dev,
51 51
52 *retfmt = daifmt; 52 *retfmt = daifmt;
53 53
54 dev_dbg(dev, "format : %04x\n", daifmt);
55
54 return 0; 56 return 0;
55} 57}
56EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt); 58EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt);
@@ -72,6 +74,8 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
72 74
73 dai_link->name = name; 75 dai_link->name = name;
74 dai_link->stream_name = name; 76 dai_link->stream_name = name;
77
78 dev_dbg(dev, "name : %s\n", name);
75 } 79 }
76 80
77 return ret; 81 return ret;
@@ -81,19 +85,27 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name);
81int asoc_simple_card_parse_card_name(struct snd_soc_card *card, 85int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
82 char *prefix) 86 char *prefix)
83{ 87{
84 char prop[128];
85 int ret; 88 int ret;
86 89
87 snprintf(prop, sizeof(prop), "%sname", prefix); 90 if (!prefix)
91 prefix = "";
88 92
89 /* Parse the card name from DT */ 93 /* Parse the card name from DT */
90 ret = snd_soc_of_parse_card_name(card, prop); 94 ret = snd_soc_of_parse_card_name(card, "label");
91 if (ret < 0) 95 if (ret < 0) {
92 return ret; 96 char prop[128];
97
98 snprintf(prop, sizeof(prop), "%sname", prefix);
99 ret = snd_soc_of_parse_card_name(card, prop);
100 if (ret < 0)
101 return ret;
102 }
93 103
94 if (!card->name && card->dai_link) 104 if (!card->name && card->dai_link)
95 card->name = card->dai_link->name; 105 card->name = card->dai_link->name;
96 106
107 dev_dbg(card->dev, "Card Name: %s\n", card->name ? card->name : "");
108
97 return 0; 109 return 0;
98} 110}
99EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); 111EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
@@ -101,7 +113,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
101int asoc_simple_card_parse_clk(struct device *dev, 113int asoc_simple_card_parse_clk(struct device *dev,
102 struct device_node *node, 114 struct device_node *node,
103 struct device_node *dai_of_node, 115 struct device_node *dai_of_node,
104 struct asoc_simple_dai *simple_dai) 116 struct asoc_simple_dai *simple_dai,
117 const char *name)
105{ 118{
106 struct clk *clk; 119 struct clk *clk;
107 u32 val; 120 u32 val;
@@ -124,6 +137,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
124 simple_dai->sysclk = clk_get_rate(clk); 137 simple_dai->sysclk = clk_get_rate(clk);
125 } 138 }
126 139
140 dev_dbg(dev, "%s : sysclk = %d\n", name, simple_dai->sysclk);
141
127 return 0; 142 return 0;
128} 143}
129EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); 144EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk);
@@ -165,6 +180,71 @@ int asoc_simple_card_parse_dai(struct device_node *node,
165} 180}
166EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); 181EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai);
167 182
183static int asoc_simple_card_get_dai_id(struct device_node *ep)
184{
185 struct device_node *node;
186 struct device_node *endpoint;
187 int i, id;
188 int ret;
189
190 ret = snd_soc_get_dai_id(ep);
191 if (ret != -ENOTSUPP)
192 return ret;
193
194 node = of_graph_get_port_parent(ep);
195
196 /*
197 * Non HDMI sound case, counting port/endpoint on its DT
198 * is enough. Let's count it.
199 */
200 i = 0;
201 id = -1;
202 for_each_endpoint_of_node(node, endpoint) {
203 if (endpoint == ep)
204 id = i;
205 i++;
206 }
207 if (id < 0)
208 return -ENODEV;
209
210 return id;
211}
212
213int asoc_simple_card_parse_graph_dai(struct device_node *ep,
214 struct device_node **dai_of_node,
215 const char **dai_name)
216{
217 struct device_node *node;
218 struct of_phandle_args args;
219 int ret;
220
221 if (!ep)
222 return 0;
223 if (!dai_name)
224 return 0;
225
226 /*
227 * of_graph_get_port_parent() will call
228 * of_node_put(). So, call of_node_get() here
229 */
230 of_node_get(ep);
231 node = of_graph_get_port_parent(ep);
232
233 /* Get dai->name */
234 args.np = node;
235 args.args[0] = asoc_simple_card_get_dai_id(ep);
236 args.args_count = (of_graph_get_endpoint_count(node) > 1);
237
238 ret = snd_soc_get_dai_name(&args, dai_name);
239 if (ret < 0)
240 return ret;
241
242 *dai_of_node = node;
243
244 return 0;
245}
246EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai);
247
168int asoc_simple_card_init_dai(struct snd_soc_dai *dai, 248int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
169 struct asoc_simple_dai *simple_dai) 249 struct asoc_simple_dai *simple_dai)
170{ 250{
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 2c9dedab5184..e86c6e16146b 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -301,15 +301,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
301 dai_link->ops = &asoc_simple_card_ops; 301 dai_link->ops = &asoc_simple_card_ops;
302 dai_link->init = asoc_simple_card_dai_init; 302 dai_link->init = asoc_simple_card_dai_init;
303 303
304 dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
305 dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
306 dev_dbg(dev, "\tcpu : %s / %d\n",
307 dai_link->cpu_dai_name,
308 dai_props->cpu_dai.sysclk);
309 dev_dbg(dev, "\tcodec : %s / %d\n",
310 dai_link->codec_dai_name,
311 dai_props->codec_dai.sysclk);
312
313 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); 304 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
314 305
315dai_link_of_err: 306dai_link_of_err:
@@ -497,8 +488,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
497 snd_soc_card_set_drvdata(card, priv); 488 snd_soc_card_set_drvdata(card, priv);
498 489
499 ret = devm_snd_soc_register_card(dev, card); 490 ret = devm_snd_soc_register_card(dev, card);
500 if (ret >= 0) 491 if (ret < 0)
501 return ret; 492 goto err;
493
494 return 0;
502err: 495err:
503 asoc_simple_card_clean_reference(card); 496 asoc_simple_card_clean_reference(card);
504 497
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index dcbcab230d1b..5faf5d6c48a2 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -189,21 +189,16 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
189 dai_link->ops = &asoc_simple_card_ops; 189 dai_link->ops = &asoc_simple_card_ops;
190 dai_link->init = asoc_simple_card_dai_init; 190 dai_link->init = asoc_simple_card_dai_init;
191 191
192 dev_dbg(dev, "\t%s / %04x / %d\n",
193 dai_link->name,
194 dai_link->dai_fmt,
195 dai_props->sysclk);
196
197 return 0; 192 return 0;
198} 193}
199 194
200static int asoc_simple_card_parse_of(struct device_node *node, 195static int asoc_simple_card_parse_of(struct simple_card_data *priv)
201 struct simple_card_data *priv)
202 196
203{ 197{
204 struct device *dev = simple_priv_to_dev(priv); 198 struct device *dev = simple_priv_to_dev(priv);
205 struct device_node *np; 199 struct device_node *np;
206 struct snd_soc_card *card = simple_priv_to_card(priv); 200 struct snd_soc_card *card = simple_priv_to_card(priv);
201 struct device_node *node = dev->of_node;
207 unsigned int daifmt = 0; 202 unsigned int daifmt = 0;
208 bool is_fe; 203 bool is_fe;
209 int ret, i; 204 int ret, i;
@@ -246,8 +241,6 @@ static int asoc_simple_card_parse_of(struct device_node *node,
246 if (ret < 0) 241 if (ret < 0)
247 return ret; 242 return ret;
248 243
249 dev_dbg(dev, "New card: %s\n",
250 card->name ? card->name : "");
251 dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); 244 dev_dbg(dev, "convert_rate %d\n", priv->convert_rate);
252 dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); 245 dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
253 246
@@ -288,7 +281,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
288 card->codec_conf = &priv->codec_conf; 281 card->codec_conf = &priv->codec_conf;
289 card->num_configs = 1; 282 card->num_configs = 1;
290 283
291 ret = asoc_simple_card_parse_of(np, priv); 284 ret = asoc_simple_card_parse_of(priv);
292 if (ret < 0) { 285 if (ret < 0) {
293 if (ret != -EPROBE_DEFER) 286 if (ret != -EPROBE_DEFER)
294 dev_err(dev, "parse error %d\n", ret); 287 dev_err(dev, "parse error %d\n", ret);
@@ -298,8 +291,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
298 snd_soc_card_set_drvdata(card, priv); 291 snd_soc_card_set_drvdata(card, priv);
299 292
300 ret = devm_snd_soc_register_card(dev, card); 293 ret = devm_snd_soc_register_card(dev, card);
301 if (ret >= 0) 294 if (ret < 0)
302 return ret; 295 goto err;
296
297 return 0;
303err: 298err:
304 asoc_simple_card_clean_reference(card); 299 asoc_simple_card_clean_reference(card);
305 300
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 147ebecfed94..1aa5cd77ca24 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -38,7 +38,7 @@ config SND_SOC_RCAR
38 tristate "R-Car series SRU/SCU/SSIU/SSI support" 38 tristate "R-Car series SRU/SCU/SSIU/SSI support"
39 depends on COMMON_CLK 39 depends on COMMON_CLK
40 depends on OF || COMPILE_TEST 40 depends on OF || COMPILE_TEST
41 select SND_SIMPLE_CARD 41 select SND_SIMPLE_CARD_UTILS
42 select REGMAP_MMIO 42 select REGMAP_MMIO
43 help 43 help
44 This option enables R-Car SRU/SCU/SSIU/SSI sound support 44 This option enables R-Car SRU/SCU/SSIU/SSI sound support
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index d3b0dc145a56..4a72fd74ddc2 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -480,6 +480,9 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
480 if (req_rate[0] % 48000 == 0) 480 if (req_rate[0] % 48000 == 0)
481 adg->flags = AUDIO_OUT_48; 481 adg->flags = AUDIO_OUT_48;
482 482
483 if (of_get_property(np, "clkout-lr-asynchronous", NULL))
484 adg->flags = LRCLK_ASYNC;
485
483 /* 486 /*
484 * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC 487 * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
485 * have 44.1kHz or 48kHz base clocks for now. 488 * have 44.1kHz or 48kHz base clocks for now.
@@ -555,7 +558,6 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
555 clk = clk_register_fixed_rate(dev, clkout_name[i], 558 clk = clk_register_fixed_rate(dev, clkout_name[i],
556 parent_clk_name, 0, 559 parent_clk_name, 0,
557 req_rate[0]); 560 req_rate[0]);
558 adg->clkout[i] = ERR_PTR(-ENOENT);
559 if (!IS_ERR(clk)) 561 if (!IS_ERR(clk))
560 adg->clkout[i] = clk; 562 adg->clkout[i] = clk;
561 } 563 }
@@ -580,7 +582,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
580{ 582{
581 struct rsnd_adg *adg; 583 struct rsnd_adg *adg;
582 struct device *dev = rsnd_priv_to_dev(priv); 584 struct device *dev = rsnd_priv_to_dev(priv);
583 struct device_node *np = dev->of_node;
584 int ret; 585 int ret;
585 586
586 adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); 587 adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
@@ -597,9 +598,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
597 rsnd_adg_get_clkin(priv, adg); 598 rsnd_adg_get_clkin(priv, adg);
598 rsnd_adg_get_clkout(priv, adg); 599 rsnd_adg_get_clkout(priv, adg);
599 600
600 if (of_get_property(np, "clkout-lr-asynchronous", NULL))
601 adg->flags = LRCLK_ASYNC;
602
603 priv->adg = adg; 601 priv->adg = adg;
604 602
605 rsnd_adg_clk_enable(priv); 603 rsnd_adg_clk_enable(priv);
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index d879c010cf03..9a136d86e2a9 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -82,6 +82,9 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
82 [9] = 0x2, 82 [9] = 0x2,
83 }; 83 };
84 84
85 if (unlikely(!src))
86 return -EIO;
87
85 data = path[rsnd_mod_id(src)] | 88 data = path[rsnd_mod_id(src)] |
86 cmd_case[rsnd_mod_id(src)] << 16; 89 cmd_case[rsnd_mod_id(src)] << 16;
87 } 90 }
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 8c1f4e2e0c4f..7a8c08933503 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -766,11 +766,16 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
766{ 766{
767 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); 767 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
768 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); 768 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
769 int ret;
769 770
770 /* 771 /*
771 * call rsnd_dai_call without spinlock 772 * call rsnd_dai_call without spinlock
772 */ 773 */
773 return rsnd_dai_call(nolock_start, io, priv); 774 ret = rsnd_dai_call(nolock_start, io, priv);
775 if (ret < 0)
776 rsnd_dai_call(nolock_stop, io, priv);
777
778 return ret;
774} 779}
775 780
776static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, 781static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
@@ -820,32 +825,131 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
820 of_node_put(node); 825 of_node_put(node);
821} 826}
822 827
823static int rsnd_dai_probe(struct rsnd_priv *priv) 828static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
829 int *is_graph)
824{ 830{
831 struct device *dev = rsnd_priv_to_dev(priv);
832 struct device_node *np = dev->of_node;
825 struct device_node *dai_node; 833 struct device_node *dai_node;
826 struct device_node *dai_np; 834 struct device_node *ret;
835
836 *is_graph = 0;
837
838 /*
839 * parse both previous dai (= rcar_sound,dai), and
840 * graph dai (= ports/port)
841 */
842 dai_node = of_get_child_by_name(np, RSND_NODE_DAI);
843 if (dai_node) {
844 ret = dai_node;
845 goto of_node_compatible;
846 }
847
848 ret = np;
849
850 dai_node = of_graph_get_next_endpoint(np, NULL);
851 if (dai_node)
852 goto of_node_graph;
853
854 return NULL;
855
856of_node_graph:
857 *is_graph = 1;
858of_node_compatible:
859 of_node_put(dai_node);
860
861 return ret;
862}
863
864static void __rsnd_dai_probe(struct rsnd_priv *priv,
865 struct device_node *dai_np,
866 int dai_i, int is_graph)
867{
827 struct device_node *playback, *capture; 868 struct device_node *playback, *capture;
828 struct rsnd_dai_stream *io_playback; 869 struct rsnd_dai_stream *io_playback;
829 struct rsnd_dai_stream *io_capture; 870 struct rsnd_dai_stream *io_capture;
830 struct snd_soc_dai_driver *rdrv, *drv; 871 struct snd_soc_dai_driver *drv;
831 struct rsnd_dai *rdai; 872 struct rsnd_dai *rdai;
832 struct device *dev = rsnd_priv_to_dev(priv); 873 struct device *dev = rsnd_priv_to_dev(priv);
833 int nr, dai_i, io_i; 874 int io_i;
834 int ret; 875
876 rdai = rsnd_rdai_get(priv, dai_i);
877 drv = priv->daidrv + dai_i;
878 io_playback = &rdai->playback;
879 io_capture = &rdai->capture;
880
881 snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
882
883 rdai->priv = priv;
884 drv->name = rdai->name;
885 drv->ops = &rsnd_soc_dai_ops;
886
887 snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
888 "DAI%d Playback", dai_i);
889 drv->playback.rates = RSND_RATES;
890 drv->playback.formats = RSND_FMTS;
891 drv->playback.channels_min = 2;
892 drv->playback.channels_max = 6;
893 drv->playback.stream_name = rdai->playback.name;
894
895 snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
896 "DAI%d Capture", dai_i);
897 drv->capture.rates = RSND_RATES;
898 drv->capture.formats = RSND_FMTS;
899 drv->capture.channels_min = 2;
900 drv->capture.channels_max = 6;
901 drv->capture.stream_name = rdai->capture.name;
902
903 rdai->playback.rdai = rdai;
904 rdai->capture.rdai = rdai;
905 rsnd_set_slot(rdai, 2, 1); /* default */
906
907 for (io_i = 0;; io_i++) {
908 playback = of_parse_phandle(dai_np, "playback", io_i);
909 capture = of_parse_phandle(dai_np, "capture", io_i);
910
911 if (!playback && !capture)
912 break;
835 913
836 dai_node = rsnd_dai_of_node(priv); 914 rsnd_parse_connect_ssi(rdai, playback, capture);
837 nr = of_get_child_count(dai_node); 915 rsnd_parse_connect_src(rdai, playback, capture);
838 if (!nr) { 916 rsnd_parse_connect_ctu(rdai, playback, capture);
839 ret = -EINVAL; 917 rsnd_parse_connect_mix(rdai, playback, capture);
840 goto rsnd_dai_probe_done; 918 rsnd_parse_connect_dvc(rdai, playback, capture);
919
920 of_node_put(playback);
921 of_node_put(capture);
841 } 922 }
842 923
924 dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
925 rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ",
926 rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- ");
927}
928
929static int rsnd_dai_probe(struct rsnd_priv *priv)
930{
931 struct device_node *dai_node;
932 struct device_node *dai_np;
933 struct snd_soc_dai_driver *rdrv;
934 struct device *dev = rsnd_priv_to_dev(priv);
935 struct rsnd_dai *rdai;
936 int nr;
937 int is_graph;
938 int dai_i;
939
940 dai_node = rsnd_dai_of_node(priv, &is_graph);
941 if (is_graph)
942 nr = of_graph_get_endpoint_count(dai_node);
943 else
944 nr = of_get_child_count(dai_node);
945
946 if (!nr)
947 return -EINVAL;
948
843 rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL); 949 rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL);
844 rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); 950 rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL);
845 if (!rdrv || !rdai) { 951 if (!rdrv || !rdai)
846 ret = -ENOMEM; 952 return -ENOMEM;
847 goto rsnd_dai_probe_done;
848 }
849 953
850 priv->rdai_nr = nr; 954 priv->rdai_nr = nr;
851 priv->daidrv = rdrv; 955 priv->daidrv = rdrv;
@@ -855,68 +959,18 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
855 * parse all dai 959 * parse all dai
856 */ 960 */
857 dai_i = 0; 961 dai_i = 0;
858 for_each_child_of_node(dai_node, dai_np) { 962 if (is_graph) {
859 rdai = rsnd_rdai_get(priv, dai_i); 963 for_each_endpoint_of_node(dai_node, dai_np) {
860 drv = rdrv + dai_i; 964 __rsnd_dai_probe(priv, dai_np, dai_i, is_graph);
861 io_playback = &rdai->playback; 965 rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
862 io_capture = &rdai->capture; 966 dai_i++;
863
864 snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
865
866 rdai->priv = priv;
867 drv->name = rdai->name;
868 drv->ops = &rsnd_soc_dai_ops;
869
870 snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
871 "DAI%d Playback", dai_i);
872 drv->playback.rates = RSND_RATES;
873 drv->playback.formats = RSND_FMTS;
874 drv->playback.channels_min = 2;
875 drv->playback.channels_max = 6;
876 drv->playback.stream_name = rdai->playback.name;
877
878 snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
879 "DAI%d Capture", dai_i);
880 drv->capture.rates = RSND_RATES;
881 drv->capture.formats = RSND_FMTS;
882 drv->capture.channels_min = 2;
883 drv->capture.channels_max = 6;
884 drv->capture.stream_name = rdai->capture.name;
885
886 rdai->playback.rdai = rdai;
887 rdai->capture.rdai = rdai;
888 rsnd_set_slot(rdai, 2, 1); /* default */
889
890 for (io_i = 0;; io_i++) {
891 playback = of_parse_phandle(dai_np, "playback", io_i);
892 capture = of_parse_phandle(dai_np, "capture", io_i);
893
894 if (!playback && !capture)
895 break;
896
897 rsnd_parse_connect_ssi(rdai, playback, capture);
898 rsnd_parse_connect_src(rdai, playback, capture);
899 rsnd_parse_connect_ctu(rdai, playback, capture);
900 rsnd_parse_connect_mix(rdai, playback, capture);
901 rsnd_parse_connect_dvc(rdai, playback, capture);
902
903 of_node_put(playback);
904 of_node_put(capture);
905 } 967 }
906 968 } else {
907 dai_i++; 969 for_each_child_of_node(dai_node, dai_np)
908 970 __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
909 dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
910 rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ",
911 rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- ");
912 } 971 }
913 972
914 ret = 0; 973 return 0;
915
916rsnd_dai_probe_done:
917 of_node_put(dai_node);
918
919 return ret;
920} 974}
921 975
922/* 976/*
@@ -965,12 +1019,14 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream,
965 1019
966static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) 1020static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
967{ 1021{
968 struct snd_pcm_runtime *runtime = substream->runtime;
969 struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); 1022 struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
970 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); 1023 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
971 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); 1024 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
1025 snd_pcm_uframes_t pointer = 0;
1026
1027 rsnd_dai_call(pointer, io, &pointer);
972 1028
973 return bytes_to_frames(runtime, io->byte_pos); 1029 return pointer;
974} 1030}
975 1031
976static struct snd_pcm_ops rsnd_pcm_ops = { 1032static struct snd_pcm_ops rsnd_pcm_ops = {
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 241cb3b08a07..05e538f4c8d5 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -25,6 +25,7 @@
25 25
26struct rsnd_dmaen { 26struct rsnd_dmaen {
27 struct dma_chan *chan; 27 struct dma_chan *chan;
28 dma_cookie_t cookie;
28 dma_addr_t dma_buf; 29 dma_addr_t dma_buf;
29 unsigned int dma_len; 30 unsigned int dma_len;
30 unsigned int dma_period; 31 unsigned int dma_period;
@@ -292,7 +293,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
292 for (i = 0; i < 2; i++) 293 for (i = 0; i < 2; i++)
293 rsnd_dmaen_sync(dmaen, io, i); 294 rsnd_dmaen_sync(dmaen, io, i);
294 295
295 if (dmaengine_submit(desc) < 0) { 296 dmaen->cookie = dmaengine_submit(desc);
297 if (dmaen->cookie < 0) {
296 dev_err(dev, "dmaengine_submit() fail\n"); 298 dev_err(dev, "dmaengine_submit() fail\n");
297 return -EIO; 299 return -EIO;
298 } 300 }
@@ -348,12 +350,34 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
348 return 0; 350 return 0;
349} 351}
350 352
353static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
354 struct rsnd_dai_stream *io,
355 snd_pcm_uframes_t *pointer)
356{
357 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
358 struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
359 struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
360 struct dma_tx_state state;
361 enum dma_status status;
362 unsigned int pos = 0;
363
364 status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state);
365 if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
366 if (state.residue > 0 && state.residue <= dmaen->dma_len)
367 pos = dmaen->dma_len - state.residue;
368 }
369 *pointer = bytes_to_frames(runtime, pos);
370
371 return 0;
372}
373
351static struct rsnd_mod_ops rsnd_dmaen_ops = { 374static struct rsnd_mod_ops rsnd_dmaen_ops = {
352 .name = "audmac", 375 .name = "audmac",
353 .nolock_start = rsnd_dmaen_nolock_start, 376 .nolock_start = rsnd_dmaen_nolock_start,
354 .nolock_stop = rsnd_dmaen_nolock_stop, 377 .nolock_stop = rsnd_dmaen_nolock_stop,
355 .start = rsnd_dmaen_start, 378 .start = rsnd_dmaen_start,
356 .stop = rsnd_dmaen_stop, 379 .stop = rsnd_dmaen_stop,
380 .pointer= rsnd_dmaen_pointer,
357}; 381};
358 382
359/* 383/*
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 4b0980728e13..ee00e3516911 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -219,6 +219,8 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
219 RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), 219 RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
220 RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), 220 RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
221 RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), 221 RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
222 RSND_GEN_S_REG(HDMI0_SEL, 0x9e0),
223 RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),
222 224
223 /* FIXME: it needs SSI_MODE2/3 in the future */ 225 /* FIXME: it needs SSI_MODE2/3 in the future */
224 RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), 226 RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 323af41ecfcb..bd8def0bc212 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -18,6 +18,7 @@
18#include <linux/list.h> 18#include <linux/list.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/of_device.h> 20#include <linux/of_device.h>
21#include <linux/of_graph.h>
21#include <linux/of_irq.h> 22#include <linux/of_irq.h>
22#include <linux/sh_dma.h> 23#include <linux/sh_dma.h>
23#include <linux/workqueue.h> 24#include <linux/workqueue.h>
@@ -170,6 +171,8 @@ enum rsnd_reg {
170 RSND_REG_SSI_SYS_STATUS5, 171 RSND_REG_SSI_SYS_STATUS5,
171 RSND_REG_SSI_SYS_STATUS6, 172 RSND_REG_SSI_SYS_STATUS6,
172 RSND_REG_SSI_SYS_STATUS7, 173 RSND_REG_SSI_SYS_STATUS7,
174 RSND_REG_HDMI0_SEL,
175 RSND_REG_HDMI1_SEL,
173 176
174 /* SSI */ 177 /* SSI */
175 RSND_REG_SSICR, 178 RSND_REG_SSICR,
@@ -268,6 +271,9 @@ struct rsnd_mod_ops {
268 struct rsnd_dai_stream *io, 271 struct rsnd_dai_stream *io,
269 struct snd_pcm_substream *substream, 272 struct snd_pcm_substream *substream,
270 struct snd_pcm_hw_params *hw_params); 273 struct snd_pcm_hw_params *hw_params);
274 int (*pointer)(struct rsnd_mod *mod,
275 struct rsnd_dai_stream *io,
276 snd_pcm_uframes_t *pointer);
271 int (*fallback)(struct rsnd_mod *mod, 277 int (*fallback)(struct rsnd_mod *mod,
272 struct rsnd_dai_stream *io, 278 struct rsnd_dai_stream *io,
273 struct rsnd_priv *priv); 279 struct rsnd_priv *priv);
@@ -305,6 +311,7 @@ struct rsnd_mod {
305 * H 0: pcm_new 311 * H 0: pcm_new
306 * H 0: fallback 312 * H 0: fallback
307 * H 0: hw_params 313 * H 0: hw_params
314 * H 0: pointer
308 */ 315 */
309#define __rsnd_mod_shift_nolock_start 0 316#define __rsnd_mod_shift_nolock_start 0
310#define __rsnd_mod_shift_nolock_stop 0 317#define __rsnd_mod_shift_nolock_stop 0
@@ -318,6 +325,7 @@ struct rsnd_mod {
318#define __rsnd_mod_shift_pcm_new 28 /* always called */ 325#define __rsnd_mod_shift_pcm_new 28 /* always called */
319#define __rsnd_mod_shift_fallback 28 /* always called */ 326#define __rsnd_mod_shift_fallback 28 /* always called */
320#define __rsnd_mod_shift_hw_params 28 /* always called */ 327#define __rsnd_mod_shift_hw_params 28 /* always called */
328#define __rsnd_mod_shift_pointer 28 /* always called */
321 329
322#define __rsnd_mod_add_probe 0 330#define __rsnd_mod_add_probe 0
323#define __rsnd_mod_add_remove 0 331#define __rsnd_mod_add_remove 0
@@ -331,6 +339,7 @@ struct rsnd_mod {
331#define __rsnd_mod_add_pcm_new 0 339#define __rsnd_mod_add_pcm_new 0
332#define __rsnd_mod_add_fallback 0 340#define __rsnd_mod_add_fallback 0
333#define __rsnd_mod_add_hw_params 0 341#define __rsnd_mod_add_hw_params 0
342#define __rsnd_mod_add_pointer 0
334 343
335#define __rsnd_mod_call_probe 0 344#define __rsnd_mod_call_probe 0
336#define __rsnd_mod_call_remove 0 345#define __rsnd_mod_call_remove 0
@@ -342,6 +351,7 @@ struct rsnd_mod {
342#define __rsnd_mod_call_pcm_new 0 351#define __rsnd_mod_call_pcm_new 0
343#define __rsnd_mod_call_fallback 0 352#define __rsnd_mod_call_fallback 0
344#define __rsnd_mod_call_hw_params 0 353#define __rsnd_mod_call_hw_params 0
354#define __rsnd_mod_call_pointer 0
345#define __rsnd_mod_call_nolock_start 0 355#define __rsnd_mod_call_nolock_start 0
346#define __rsnd_mod_call_nolock_stop 1 356#define __rsnd_mod_call_nolock_stop 1
347 357
@@ -420,7 +430,6 @@ struct rsnd_dai_stream {
420 char name[RSND_DAI_NAME_SIZE]; 430 char name[RSND_DAI_NAME_SIZE];
421 struct snd_pcm_substream *substream; 431 struct snd_pcm_substream *substream;
422 struct rsnd_mod *mod[RSND_MOD_MAX]; 432 struct rsnd_mod *mod[RSND_MOD_MAX];
423 struct rsnd_dai_path_info *info; /* rcar_snd.h */
424 struct rsnd_dai *rdai; 433 struct rsnd_dai *rdai;
425 u32 parent_ssi_status; 434 u32 parent_ssi_status;
426 int byte_pos; 435 int byte_pos;
@@ -477,7 +486,6 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
477int rsnd_dai_connect(struct rsnd_mod *mod, 486int rsnd_dai_connect(struct rsnd_mod *mod,
478 struct rsnd_dai_stream *io, 487 struct rsnd_dai_stream *io,
479 enum rsnd_mod_type type); 488 enum rsnd_mod_type type);
480#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
481 489
482/* 490/*
483 * R-Car Gen1/Gen2 491 * R-Car Gen1/Gen2
@@ -648,6 +656,13 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
648int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); 656int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
649u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); 657u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
650 658
659#define RSND_SSI_HDMI_PORT0 0xf0
660#define RSND_SSI_HDMI_PORT1 0xf1
661int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io);
662void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
663 struct device_node *endpoint,
664 int dai_i);
665
651#define rsnd_ssi_is_pin_sharing(io) \ 666#define rsnd_ssi_is_pin_sharing(io) \
652 __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) 667 __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
653int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); 668int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 76a477a3ccb5..8dbe9ebcbff1 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -12,10 +12,6 @@
12 12
13#define SRC_NAME "src" 13#define SRC_NAME "src"
14 14
15/* SRCx_STATUS */
16#define OUF_SRCO ((1 << 12) | (1 << 13))
17#define OUF_SRCI ((1 << 9) | (1 << 8))
18
19/* SCU_SYSTEM_STATUS0/1 */ 15/* SCU_SYSTEM_STATUS0/1 */
20#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) 16#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id))
21 17
@@ -55,20 +51,6 @@ struct rsnd_src {
55 * 51 *
56 */ 52 */
57 53
58/*
59 * src.c is caring...
60 *
61 * Gen1
62 *
63 * [mem] -> [SRU] -> [SSI]
64 * |--------|
65 *
66 * Gen2
67 *
68 * [mem] -> [SRC] -> [SSIU] -> [SSI]
69 * |-----------------|
70 */
71
72static void rsnd_src_activation(struct rsnd_mod *mod) 54static void rsnd_src_activation(struct rsnd_mod *mod)
73{ 55{
74 rsnd_mod_write(mod, SRC_SWRSR, 0); 56 rsnd_mod_write(mod, SRC_SWRSR, 0);
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 91e5c07911b4..59ca6e3f46bc 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -11,6 +11,7 @@
11 * it under the terms of the GNU General Public License version 2 as 11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
13 */ 13 */
14#include <sound/simple_card_utils.h>
14#include <linux/delay.h> 15#include <linux/delay.h>
15#include "rsnd.h" 16#include "rsnd.h"
16#define RSND_SSI_NAME_SIZE 16 17#define RSND_SSI_NAME_SIZE 16
@@ -81,6 +82,8 @@ struct rsnd_ssi {
81/* flags */ 82/* flags */
82#define RSND_SSI_CLK_PIN_SHARE (1 << 0) 83#define RSND_SSI_CLK_PIN_SHARE (1 << 0)
83#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ 84#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */
85#define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */
86#define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */
84 87
85#define for_each_rsnd_ssi(pos, priv, i) \ 88#define for_each_rsnd_ssi(pos, priv, i) \
86 for (i = 0; \ 89 for (i = 0; \
@@ -99,6 +102,20 @@ struct rsnd_ssi {
99#define rsnd_ssi_is_run_mods(mod, io) \ 102#define rsnd_ssi_is_run_mods(mod, io) \
100 (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) 103 (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
101 104
105int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
106{
107 struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
108 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
109
110 if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0)
111 return RSND_SSI_HDMI_PORT0;
112
113 if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1)
114 return RSND_SSI_HDMI_PORT1;
115
116 return 0;
117}
118
102int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) 119int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
103{ 120{
104 struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); 121 struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
@@ -675,6 +692,17 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
675 return ret; 692 return ret;
676} 693}
677 694
695static int rsnd_ssi_pointer(struct rsnd_mod *mod,
696 struct rsnd_dai_stream *io,
697 snd_pcm_uframes_t *pointer)
698{
699 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
700
701 *pointer = bytes_to_frames(runtime, io->byte_pos);
702
703 return 0;
704}
705
678static struct rsnd_mod_ops rsnd_ssi_pio_ops = { 706static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
679 .name = SSI_NAME, 707 .name = SSI_NAME,
680 .probe = rsnd_ssi_common_probe, 708 .probe = rsnd_ssi_common_probe,
@@ -683,6 +711,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
683 .start = rsnd_ssi_start, 711 .start = rsnd_ssi_start,
684 .stop = rsnd_ssi_stop, 712 .stop = rsnd_ssi_stop,
685 .irq = rsnd_ssi_irq, 713 .irq = rsnd_ssi_irq,
714 .pointer= rsnd_ssi_pointer,
686 .pcm_new = rsnd_ssi_pcm_new, 715 .pcm_new = rsnd_ssi_pcm_new,
687 .hw_params = rsnd_ssi_hw_params, 716 .hw_params = rsnd_ssi_hw_params,
688}; 717};
@@ -787,13 +816,6 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
787 816
788 817
789/* 818/*
790 * Non SSI
791 */
792static struct rsnd_mod_ops rsnd_ssi_non_ops = {
793 .name = SSI_NAME,
794};
795
796/*
797 * ssi mod function 819 * ssi mod function
798 */ 820 */
799static void rsnd_ssi_connect(struct rsnd_mod *mod, 821static void rsnd_ssi_connect(struct rsnd_mod *mod,
@@ -847,6 +869,47 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
847 of_node_put(node); 869 of_node_put(node);
848} 870}
849 871
872static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
873 struct rsnd_dai_stream *io,
874 struct device_node *remote_ep)
875{
876 struct device *dev = rsnd_priv_to_dev(priv);
877 struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
878 struct rsnd_ssi *ssi;
879
880 if (!mod)
881 return;
882
883 ssi = rsnd_mod_to_ssi(mod);
884
885 if (strstr(remote_ep->full_name, "hdmi0")) {
886 ssi->flags |= RSND_SSI_HDMI0;
887 dev_dbg(dev, "%s[%d] connected to HDMI0\n",
888 rsnd_mod_name(mod), rsnd_mod_id(mod));
889 }
890
891 if (strstr(remote_ep->full_name, "hdmi1")) {
892 ssi->flags |= RSND_SSI_HDMI1;
893 dev_dbg(dev, "%s[%d] connected to HDMI1\n",
894 rsnd_mod_name(mod), rsnd_mod_id(mod));
895 }
896}
897
898void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
899 struct device_node *endpoint,
900 int dai_i)
901{
902 struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
903 struct device_node *remote_ep;
904
905 remote_ep = of_graph_get_remote_endpoint(endpoint);
906 if (!remote_ep)
907 return;
908
909 __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep);
910 __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep);
911}
912
850struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) 913struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
851{ 914{
852 if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) 915 if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
@@ -952,7 +1015,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
952 goto rsnd_ssi_probe_done; 1015 goto rsnd_ssi_probe_done;
953 } 1016 }
954 1017
955 ops = &rsnd_ssi_non_ops;
956 if (of_property_read_bool(np, "pio-transfer")) 1018 if (of_property_read_bool(np, "pio-transfer"))
957 ops = &rsnd_ssi_pio_ops; 1019 ops = &rsnd_ssi_pio_ops;
958 else 1020 else
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 512d238b79e2..bed2c9c0004b 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -123,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
123 struct rsnd_dai_stream *io, 123 struct rsnd_dai_stream *io,
124 struct rsnd_priv *priv) 124 struct rsnd_priv *priv)
125{ 125{
126 int hdmi = rsnd_ssi_hdmi_port(io);
126 int ret; 127 int ret;
127 128
128 ret = rsnd_ssiu_init(mod, io, priv); 129 ret = rsnd_ssiu_init(mod, io, priv);
@@ -150,6 +151,42 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
150 rsnd_get_dalign(mod, io)); 151 rsnd_get_dalign(mod, io));
151 } 152 }
152 153
154 if (hdmi) {
155 enum rsnd_mod_type rsnd_ssi_array[] = {
156 RSND_MOD_SSIM1,
157 RSND_MOD_SSIM2,
158 RSND_MOD_SSIM3,
159 };
160 struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
161 struct rsnd_mod *pos;
162 u32 val;
163 int i, shift;
164
165 i = rsnd_mod_id(ssi_mod);
166
167 /* output all same SSI as default */
168 val = i << 16 |
169 i << 20 |
170 i << 24 |
171 i << 28 |
172 i;
173
174 for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
175 shift = (i * 4) + 16;
176 val = (val & ~(0xF << shift)) |
177 rsnd_mod_id(pos) << shift;
178 }
179
180 switch (hdmi) {
181 case RSND_SSI_HDMI_PORT0:
182 rsnd_mod_write(mod, HDMI0_SEL, val);
183 break;
184 case RSND_SSI_HDMI_PORT1:
185 rsnd_mod_write(mod, HDMI1_SEL, val);
186 break;
187 }
188 }
189
153 return 0; 190 return 0;
154} 191}
155 192
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index aae099c0e502..9ba183781017 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -34,6 +34,7 @@
34#include <linux/ctype.h> 34#include <linux/ctype.h>
35#include <linux/slab.h> 35#include <linux/slab.h>
36#include <linux/of.h> 36#include <linux/of.h>
37#include <linux/of_graph.h>
37#include <linux/dmi.h> 38#include <linux/dmi.h>
38#include <sound/core.h> 39#include <sound/core.h>
39#include <sound/jack.h> 40#include <sound/jack.h>
@@ -3960,11 +3961,15 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
3960 prefix = ""; 3961 prefix = "";
3961 3962
3962 /* 3963 /*
3963 * check "[prefix]format = xxx" 3964 * check "dai-format = xxx"
3965 * or "[prefix]format = xxx"
3964 * SND_SOC_DAIFMT_FORMAT_MASK area 3966 * SND_SOC_DAIFMT_FORMAT_MASK area
3965 */ 3967 */
3966 snprintf(prop, sizeof(prop), "%sformat", prefix); 3968 ret = of_property_read_string(np, "dai-format", &str);
3967 ret = of_property_read_string(np, prop, &str); 3969 if (ret < 0) {
3970 snprintf(prop, sizeof(prop), "%sformat", prefix);
3971 ret = of_property_read_string(np, prop, &str);
3972 }
3968 if (ret == 0) { 3973 if (ret == 0) {
3969 for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { 3974 for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) {
3970 if (strcmp(str, of_fmt_table[i].name) == 0) { 3975 if (strcmp(str, of_fmt_table[i].name) == 0) {
@@ -4044,6 +4049,42 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
4044} 4049}
4045EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); 4050EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
4046 4051
4052int snd_soc_get_dai_id(struct device_node *ep)
4053{
4054 struct snd_soc_component *pos;
4055 struct device_node *node;
4056 int ret;
4057
4058 node = of_graph_get_port_parent(ep);
4059
4060 /*
4061 * For example HDMI case, HDMI has video/sound port,
4062 * but ALSA SoC needs sound port number only.
4063 * Thus counting HDMI DT port/endpoint doesn't work.
4064 * Then, it should have .of_xlate_dai_id
4065 */
4066 ret = -ENOTSUPP;
4067 mutex_lock(&client_mutex);
4068 list_for_each_entry(pos, &component_list, list) {
4069 struct device_node *component_of_node = pos->dev->of_node;
4070
4071 if (!component_of_node && pos->dev->parent)
4072 component_of_node = pos->dev->parent->of_node;
4073
4074 if (component_of_node != node)
4075 continue;
4076
4077 if (pos->driver->of_xlate_dai_id)
4078 ret = pos->driver->of_xlate_dai_id(pos, ep);
4079
4080 break;
4081 }
4082 mutex_unlock(&client_mutex);
4083
4084 return ret;
4085}
4086EXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
4087
4047int snd_soc_get_dai_name(struct of_phandle_args *args, 4088int snd_soc_get_dai_name(struct of_phandle_args *args,
4048 const char **dai_name) 4089 const char **dai_name)
4049{ 4090{