diff options
author | Mark Brown <broonie@kernel.org> | 2017-07-03 11:15:04 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-07-03 11:15:04 -0400 |
commit | 85ee1f42fa60693e5ed72e9453ef6352e72bb4c0 (patch) | |
tree | c3c524bd6316c4c70b4f93291683ee6fff95eda4 | |
parent | 51fa6a8f15ddaaf8ecb0fe75b365c012905341fe (diff) | |
parent | 8288591368fcb470024348a9b846f7b3f791be44 (diff) |
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
28 files changed, 1960 insertions, 382 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 @@ | |||
1 | Audio Graph Card: | ||
2 | |||
3 | Audio Graph Card specifies audio DAI connections of SoC <-> codec. | ||
4 | It is based on common bindings for device graphs. | ||
5 | see ${LINUX}/Documentation/devicetree/bindings/graph.txt | ||
6 | |||
7 | Basically, Audio Graph Card property is same as Simple Card. | ||
8 | see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt | ||
9 | |||
10 | Below 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 | |||
22 | Required properties: | ||
23 | |||
24 | - compatible : "audio-graph-card"; | ||
25 | - dais : list of CPU DAI port{s} | ||
26 | |||
27 | Example: 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 | |||
56 | Example: 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 @@ | |||
1 | Audio-Graph-SCU-Card: | ||
2 | |||
3 | Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM". | ||
4 | |||
5 | It is based on common bindings for device graphs. | ||
6 | see ${LINUX}/Documentation/devicetree/bindings/graph.txt | ||
7 | |||
8 | Basically, Audio-Graph-SCU-Card property is same as | ||
9 | Simple-Card / Simple-SCU-Card / Audio-Graph-Card. | ||
10 | see ${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 | |||
14 | Below 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 | |||
26 | Below are same as Simple-SCU-Card. | ||
27 | |||
28 | - convert-rate | ||
29 | - convert-channels | ||
30 | - prefix | ||
31 | - routing | ||
32 | |||
33 | Required properties: | ||
34 | |||
35 | - compatible : "audio-graph-scu-card"; | ||
36 | - dais : list of CPU DAI port{s} | ||
37 | |||
38 | Example 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 | |||
74 | Example 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 | ||
86 | You need to use "renesas,rsrc-card" sound card for it. | 86 | You need to use "simple-scu-audio-card" sound card for it. |
87 | example) | 87 | example) |
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 | ||
144 | You need to use "renesas,rsrc-card" sound card for it. | 144 | You need to use "simple-scu-audio-card" sound card for it. |
145 | example) | 145 | example) |
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 | ||
193 | You need to use "renesas,rsrc-card" sound card for it. | 193 | You need to use "simple-scu-audio-card" sound card for it. |
194 | Ex) | 194 | Ex) |
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 | ||
372 | Optional properties: | 376 | Optional 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 | ||
379 | SSI subnode properties: | 386 | SSI 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 @@ | |||
1 | ASoC simple SCU Sound Card | 1 | ASoC Simple SCU Sound Card |
2 | 2 | ||
3 | Simple-Card specifies audio DAI connections of SoC <-> codec. | 3 | Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM". |
4 | For example, you can use this driver if you want to exchange sampling rate convert, | ||
5 | Mixing, etc... | ||
4 | 6 | ||
5 | Required properties: | 7 | Required properties: |
6 | 8 | ||
7 | - compatible : "simple-scu-audio-card" | 9 | - compatible : "simple-scu-audio-card" |
8 | "renesas,rsrc-card" | 10 | "renesas,rsrc-card" |
9 | |||
10 | Optional properties: | 11 | Optional 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 | ||
17 | Optional subnode properties: | 17 | Optional 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 | ||
39 | Required CPU/CODEC subnodes properties: | 33 | Required 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 | ||
43 | Optional CPU/CODEC subnodes properties: | 37 | Optional 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 | ||
55 | Example 1. Sampling Rate Covert | 41 | Example 1. Sampling Rate Conversion |
56 | 42 | ||
57 | sound { | 43 | sound { |
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 | ||
82 | Example 2. 2 CPU 1 Codec | 67 | Example 2. 2 CPU 1 Codec (Mixing) |
83 | 68 | ||
84 | sound { | 69 | sound { |
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 | } |
1604 | EXPORT_SYMBOL_GPL(of_phandle_iterator_init); | ||
1604 | 1605 | ||
1605 | int of_phandle_iterator_next(struct of_phandle_iterator *it) | 1606 | int 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 | } |
1674 | EXPORT_SYMBOL_GPL(of_phandle_iterator_next); | ||
1673 | 1675 | ||
1674 | int of_phandle_iterator_args(struct of_phandle_iterator *it, | 1676 | int 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( | |||
2485 | EXPORT_SYMBOL(of_graph_get_endpoint_by_regs); | 2487 | EXPORT_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 | */ | ||
2496 | struct 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 | } | ||
2501 | EXPORT_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 | */ | ||
2510 | struct 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 | } | ||
2522 | EXPORT_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 | } |
2511 | EXPORT_SYMBOL(of_graph_get_remote_port_parent); | 2541 | EXPORT_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 | } |
2530 | EXPORT_SYMBOL(of_graph_get_remote_port); | 2560 | EXPORT_SYMBOL(of_graph_get_remote_port); |
2531 | 2561 | ||
2562 | int 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 | } | ||
2572 | EXPORT_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 |
44 | int of_graph_parse_endpoint(const struct device_node *node, | 44 | int of_graph_parse_endpoint(const struct device_node *node, |
45 | struct of_endpoint *endpoint); | 45 | struct of_endpoint *endpoint); |
46 | int of_graph_get_endpoint_count(const struct device_node *np); | ||
46 | struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); | 47 | struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); |
47 | struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, | 48 | struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, |
48 | struct device_node *previous); | 49 | struct device_node *previous); |
49 | struct device_node *of_graph_get_endpoint_by_regs( | 50 | struct 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); |
52 | struct device_node *of_graph_get_remote_endpoint( | ||
53 | const struct device_node *node); | ||
54 | struct device_node *of_graph_get_port_parent(struct device_node *node); | ||
51 | struct device_node *of_graph_get_remote_port_parent( | 55 | struct device_node *of_graph_get_remote_port_parent( |
52 | const struct device_node *node); | 56 | const struct device_node *node); |
53 | struct device_node *of_graph_get_remote_port(const struct device_node *node); | 57 | struct 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 | ||
68 | static inline int of_graph_get_endpoint_count(const struct device_node *np) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
64 | static inline struct device_node *of_graph_get_port_by_id( | 73 | static 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 | ||
92 | static inline struct device_node *of_graph_get_remote_endpoint( | ||
93 | const struct device_node *node) | ||
94 | { | ||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | static inline struct device_node *of_graph_get_port_parent( | ||
99 | struct device_node *node) | ||
100 | { | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
83 | static inline struct device_node *of_graph_get_remote_port_parent( | 104 | static 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) | ||
41 | int asoc_simple_card_parse_clk(struct device *dev, | 43 | int 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) | ||
72 | int asoc_simple_card_parse_graph_dai(struct device_node *ep, | ||
73 | struct device_node **endpoint_np, | ||
74 | const char **dai_name); | ||
75 | |||
63 | int asoc_simple_card_init_dai(struct snd_soc_dai *dai, | 76 | int 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); |
1681 | int snd_soc_get_dai_id(struct device_node *ep); | ||
1679 | int snd_soc_get_dai_name(struct of_phandle_args *args, | 1682 | int snd_soc_get_dai_name(struct of_phandle_args *args, |
1680 | const char **dai_name); | 1683 | const char **dai_name); |
1681 | int snd_soc_of_get_dai_name(struct device_node *of_node, | 1684 | int 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 | |||
18 | config 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 | |||
26 | config 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 @@ | |||
1 | snd-soc-simple-card-utils-objs := simple-card-utils.o | 1 | snd-soc-simple-card-utils-objs := simple-card-utils.o |
2 | snd-soc-simple-card-objs := simple-card.o | 2 | snd-soc-simple-card-objs := simple-card.o |
3 | snd-soc-simple-scu-card-objs := simple-scu-card.o | 3 | snd-soc-simple-scu-card-objs := simple-scu-card.o |
4 | snd-soc-audio-graph-card-objs := audio-graph-card.o | ||
5 | snd-soc-audio-graph-scu-card-objs := audio-graph-scu-card.o | ||
4 | 6 | ||
5 | obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o | 7 | obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o |
6 | obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o | 8 | obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o |
7 | obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o | 9 | obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o |
10 | obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o | ||
11 | obj-$(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 | |||
26 | struct 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 | |||
40 | static 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 | |||
58 | static 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 | |||
69 | static struct snd_soc_ops asoc_graph_card_ops = { | ||
70 | .startup = asoc_graph_card_startup, | ||
71 | .shutdown = asoc_graph_card_shutdown, | ||
72 | }; | ||
73 | |||
74 | static 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 | |||
94 | static 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 | |||
175 | dai_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 | |||
183 | static 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 | |||
207 | static 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 | |||
222 | static 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; | ||
269 | err: | ||
270 | asoc_simple_card_clean_reference(card); | ||
271 | |||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | static 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 | |||
282 | static const struct of_device_id asoc_graph_of_match[] = { | ||
283 | { .compatible = "audio-graph-card", }, | ||
284 | {}, | ||
285 | }; | ||
286 | MODULE_DEVICE_TABLE(of, asoc_graph_of_match); | ||
287 | |||
288 | static 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 | }; | ||
296 | module_platform_driver(asoc_graph_card); | ||
297 | |||
298 | MODULE_ALIAS("platform:asoc-audio-graph-card"); | ||
299 | MODULE_LICENSE("GPL v2"); | ||
300 | MODULE_DESCRIPTION("ASoC Audio Graph Sound Card"); | ||
301 | MODULE_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 | |||
28 | struct 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 | |||
42 | static 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 | |||
51 | static 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 | |||
60 | static struct snd_soc_ops asoc_graph_card_ops = { | ||
61 | .startup = asoc_graph_card_startup, | ||
62 | .shutdown = asoc_graph_card_shutdown, | ||
63 | }; | ||
64 | |||
65 | static 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 | |||
82 | static 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 | |||
102 | static 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 | |||
191 | static 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 | |||
298 | parse_of_err: | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | static 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 | |||
330 | static 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; | ||
379 | err: | ||
380 | asoc_simple_card_clean_reference(card); | ||
381 | |||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | static 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 | |||
392 | static const struct of_device_id asoc_graph_of_match[] = { | ||
393 | { .compatible = "audio-graph-scu-card", }, | ||
394 | {}, | ||
395 | }; | ||
396 | MODULE_DEVICE_TABLE(of, asoc_graph_of_match); | ||
397 | |||
398 | static 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 | }; | ||
406 | module_platform_driver(asoc_graph_card); | ||
407 | |||
408 | MODULE_ALIAS("platform:asoc-audio-graph-scu-card"); | ||
409 | MODULE_LICENSE("GPL v2"); | ||
410 | MODULE_DESCRIPTION("ASoC Audio Graph SCU Sound Card"); | ||
411 | MODULE_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 | ||
15 | int asoc_simple_card_parse_daifmt(struct device *dev, | 16 | int 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 | } |
56 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt); | 58 | EXPORT_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); | |||
81 | int asoc_simple_card_parse_card_name(struct snd_soc_card *card, | 85 | int 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 | } |
99 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); | 111 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); |
@@ -101,7 +113,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); | |||
101 | int asoc_simple_card_parse_clk(struct device *dev, | 113 | int 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 | } |
129 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); | 144 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); |
@@ -165,6 +180,71 @@ int asoc_simple_card_parse_dai(struct device_node *node, | |||
165 | } | 180 | } |
166 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); | 181 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); |
167 | 182 | ||
183 | static 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 | |||
213 | int 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 | } | ||
246 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai); | ||
247 | |||
168 | int asoc_simple_card_init_dai(struct snd_soc_dai *dai, | 248 | int 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 bc136d2bd7cd..1df69701eb12 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 | ||
315 | dai_link_of_err: | 306 | dai_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; | ||
502 | err: | 495 | err: |
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 | ||
200 | static int asoc_simple_card_parse_of(struct device_node *node, | 195 | static 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; | ||
303 | err: | 298 | err: |
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..197cb3ec075f 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -308,23 +308,12 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) | |||
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
311 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) | 311 | int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) |
312 | { | ||
313 | rsnd_adg_set_ssi_clk(ssi_mod, 0); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) | ||
319 | { | 312 | { |
320 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
321 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | 313 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); |
322 | struct device *dev = rsnd_priv_to_dev(priv); | 314 | struct device *dev = rsnd_priv_to_dev(priv); |
323 | struct rsnd_mod *adg_mod = rsnd_mod_get(adg); | ||
324 | struct clk *clk; | 315 | struct clk *clk; |
325 | int i; | 316 | int i; |
326 | u32 data; | ||
327 | u32 ckr = 0; | ||
328 | int sel_table[] = { | 317 | int sel_table[] = { |
329 | [CLKA] = 0x1, | 318 | [CLKA] = 0x1, |
330 | [CLKB] = 0x2, | 319 | [CLKB] = 0x2, |
@@ -338,30 +327,42 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) | |||
338 | * find suitable clock from | 327 | * find suitable clock from |
339 | * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. | 328 | * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. |
340 | */ | 329 | */ |
341 | data = 0; | ||
342 | for_each_rsnd_clk(clk, adg, i) { | 330 | for_each_rsnd_clk(clk, adg, i) { |
343 | if (rate == clk_get_rate(clk)) { | 331 | if (rate == clk_get_rate(clk)) |
344 | data = sel_table[i]; | 332 | return sel_table[i]; |
345 | goto found_clock; | ||
346 | } | ||
347 | } | 333 | } |
348 | 334 | ||
349 | /* | 335 | /* |
350 | * find divided clock from BRGA/BRGB | 336 | * find divided clock from BRGA/BRGB |
351 | */ | 337 | */ |
352 | if (rate == adg->rbga_rate_for_441khz) { | 338 | if (rate == adg->rbga_rate_for_441khz) |
353 | data = 0x10; | 339 | return 0x10; |
354 | goto found_clock; | ||
355 | } | ||
356 | 340 | ||
357 | if (rate == adg->rbgb_rate_for_48khz) { | 341 | if (rate == adg->rbgb_rate_for_48khz) |
358 | data = 0x20; | 342 | return 0x20; |
359 | goto found_clock; | ||
360 | } | ||
361 | 343 | ||
362 | return -EIO; | 344 | return -EIO; |
345 | } | ||
363 | 346 | ||
364 | found_clock: | 347 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) |
348 | { | ||
349 | rsnd_adg_set_ssi_clk(ssi_mod, 0); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) | ||
355 | { | ||
356 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
357 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | ||
358 | struct device *dev = rsnd_priv_to_dev(priv); | ||
359 | struct rsnd_mod *adg_mod = rsnd_mod_get(adg); | ||
360 | int data; | ||
361 | u32 ckr = 0; | ||
362 | |||
363 | data = rsnd_adg_clk_query(priv, rate); | ||
364 | if (data < 0) | ||
365 | return data; | ||
365 | 366 | ||
366 | rsnd_adg_set_ssi_clk(ssi_mod, data); | 367 | rsnd_adg_set_ssi_clk(ssi_mod, data); |
367 | 368 | ||
@@ -480,6 +481,9 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
480 | if (req_rate[0] % 48000 == 0) | 481 | if (req_rate[0] % 48000 == 0) |
481 | adg->flags = AUDIO_OUT_48; | 482 | adg->flags = AUDIO_OUT_48; |
482 | 483 | ||
484 | if (of_get_property(np, "clkout-lr-asynchronous", NULL)) | ||
485 | adg->flags = LRCLK_ASYNC; | ||
486 | |||
483 | /* | 487 | /* |
484 | * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC | 488 | * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC |
485 | * have 44.1kHz or 48kHz base clocks for now. | 489 | * have 44.1kHz or 48kHz base clocks for now. |
@@ -555,7 +559,6 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
555 | clk = clk_register_fixed_rate(dev, clkout_name[i], | 559 | clk = clk_register_fixed_rate(dev, clkout_name[i], |
556 | parent_clk_name, 0, | 560 | parent_clk_name, 0, |
557 | req_rate[0]); | 561 | req_rate[0]); |
558 | adg->clkout[i] = ERR_PTR(-ENOENT); | ||
559 | if (!IS_ERR(clk)) | 562 | if (!IS_ERR(clk)) |
560 | adg->clkout[i] = clk; | 563 | adg->clkout[i] = clk; |
561 | } | 564 | } |
@@ -580,7 +583,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv) | |||
580 | { | 583 | { |
581 | struct rsnd_adg *adg; | 584 | struct rsnd_adg *adg; |
582 | struct device *dev = rsnd_priv_to_dev(priv); | 585 | struct device *dev = rsnd_priv_to_dev(priv); |
583 | struct device_node *np = dev->of_node; | ||
584 | int ret; | 586 | int ret; |
585 | 587 | ||
586 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); | 588 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); |
@@ -597,9 +599,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv) | |||
597 | rsnd_adg_get_clkin(priv, adg); | 599 | rsnd_adg_get_clkin(priv, adg); |
598 | rsnd_adg_get_clkout(priv, adg); | 600 | rsnd_adg_get_clkout(priv, adg); |
599 | 601 | ||
600 | if (of_get_property(np, "clkout-lr-asynchronous", NULL)) | ||
601 | adg->flags = LRCLK_ASYNC; | ||
602 | |||
603 | priv->adg = adg; | 602 | priv->adg = adg; |
604 | 603 | ||
605 | rsnd_adg_clk_enable(priv); | 604 | rsnd_adg_clk_enable(priv); |
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index d879c010cf03..f1d4fb566892 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c | |||
@@ -31,7 +31,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, | |||
31 | struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); | 31 | struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); |
32 | struct device *dev = rsnd_priv_to_dev(priv); | 32 | struct device *dev = rsnd_priv_to_dev(priv); |
33 | u32 data; | 33 | u32 data; |
34 | u32 path[] = { | 34 | static const u32 path[] = { |
35 | [1] = 1 << 0, | 35 | [1] = 1 << 0, |
36 | [5] = 1 << 8, | 36 | [5] = 1 << 8, |
37 | [6] = 1 << 12, | 37 | [6] = 1 << 12, |
@@ -71,7 +71,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, | |||
71 | } else { | 71 | } else { |
72 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 72 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
73 | 73 | ||
74 | u8 cmd_case[] = { | 74 | static const u8 cmd_case[] = { |
75 | [0] = 0x3, | 75 | [0] = 0x3, |
76 | [1] = 0x3, | 76 | [1] = 0x3, |
77 | [2] = 0x4, | 77 | [2] = 0x4, |
@@ -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..3f2ced26ed37 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -203,27 +203,6 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) | |||
203 | return !!io->substream; | 203 | return !!io->substream; |
204 | } | 204 | } |
205 | 205 | ||
206 | void rsnd_set_slot(struct rsnd_dai *rdai, | ||
207 | int slots, int num) | ||
208 | { | ||
209 | rdai->slots = slots; | ||
210 | rdai->slots_num = num; | ||
211 | } | ||
212 | |||
213 | int rsnd_get_slot(struct rsnd_dai_stream *io) | ||
214 | { | ||
215 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
216 | |||
217 | return rdai->slots; | ||
218 | } | ||
219 | |||
220 | int rsnd_get_slot_num(struct rsnd_dai_stream *io) | ||
221 | { | ||
222 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
223 | |||
224 | return rdai->slots_num; | ||
225 | } | ||
226 | |||
227 | int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) | 206 | int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) |
228 | { | 207 | { |
229 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 208 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
@@ -248,13 +227,14 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) | |||
248 | 227 | ||
249 | int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) | 228 | int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) |
250 | { | 229 | { |
230 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
251 | int chan = rsnd_io_is_play(io) ? | 231 | int chan = rsnd_io_is_play(io) ? |
252 | rsnd_runtime_channel_after_ctu(io) : | 232 | rsnd_runtime_channel_after_ctu(io) : |
253 | rsnd_runtime_channel_original(io); | 233 | rsnd_runtime_channel_original(io); |
254 | 234 | ||
255 | /* Use Multi SSI */ | 235 | /* Use Multi SSI */ |
256 | if (rsnd_runtime_is_ssi_multi(io)) | 236 | if (rsnd_runtime_is_ssi_multi(io)) |
257 | chan /= rsnd_get_slot_num(io); | 237 | chan /= rsnd_rdai_ssi_lane_get(rdai); |
258 | 238 | ||
259 | /* TDM Extend Mode needs 8ch */ | 239 | /* TDM Extend Mode needs 8ch */ |
260 | if (chan == 6) | 240 | if (chan == 6) |
@@ -265,12 +245,13 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) | |||
265 | 245 | ||
266 | int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) | 246 | int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) |
267 | { | 247 | { |
268 | int slots = rsnd_get_slot_num(io); | 248 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
249 | int lane = rsnd_rdai_ssi_lane_get(rdai); | ||
269 | int chan = rsnd_io_is_play(io) ? | 250 | int chan = rsnd_io_is_play(io) ? |
270 | rsnd_runtime_channel_after_ctu(io) : | 251 | rsnd_runtime_channel_after_ctu(io) : |
271 | rsnd_runtime_channel_original(io); | 252 | rsnd_runtime_channel_original(io); |
272 | 253 | ||
273 | return (chan >= 6) && (slots > 1); | 254 | return (chan > 2) && (lane > 1); |
274 | } | 255 | } |
275 | 256 | ||
276 | int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) | 257 | int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) |
@@ -310,6 +291,24 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
310 | u32 val = 0x76543210; | 291 | u32 val = 0x76543210; |
311 | u32 mask = ~0; | 292 | u32 mask = ~0; |
312 | 293 | ||
294 | /* | ||
295 | * *Hardware* L/R and *Software* L/R are inverted. | ||
296 | * We need to care about inversion timing to control | ||
297 | * Playback/Capture correctly. | ||
298 | * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R | ||
299 | * | ||
300 | * sL/R : software L/R | ||
301 | * hL/R : hardware L/R | ||
302 | * (*) : conversion timing | ||
303 | * | ||
304 | * Playback | ||
305 | * sL/R (*) hL/R hL/R hL/R hL/R hL/R | ||
306 | * [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec | ||
307 | * | ||
308 | * Capture | ||
309 | * hL/R hL/R hL/R hL/R hL/R (*) sL/R | ||
310 | * codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM] | ||
311 | */ | ||
313 | if (rsnd_io_is_play(io)) { | 312 | if (rsnd_io_is_play(io)) { |
314 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 313 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
315 | 314 | ||
@@ -470,8 +469,7 @@ static int rsnd_status_update(u32 *status, | |||
470 | 469 | ||
471 | #define rsnd_dai_call(fn, io, param...) \ | 470 | #define rsnd_dai_call(fn, io, param...) \ |
472 | ({ \ | 471 | ({ \ |
473 | struct rsnd_priv *priv = rsnd_io_to_priv(io); \ | 472 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \ |
474 | struct device *dev = rsnd_priv_to_dev(priv); \ | ||
475 | struct rsnd_mod *mod; \ | 473 | struct rsnd_mod *mod; \ |
476 | int is_play = rsnd_io_is_play(io); \ | 474 | int is_play = rsnd_io_is_play(io); \ |
477 | int ret = 0, i; \ | 475 | int ret = 0, i; \ |
@@ -532,6 +530,24 @@ static void rsnd_dai_disconnect(struct rsnd_mod *mod, | |||
532 | io->mod[type] = NULL; | 530 | io->mod[type] = NULL; |
533 | } | 531 | } |
534 | 532 | ||
533 | int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, | ||
534 | int max_channels) | ||
535 | { | ||
536 | if (max_channels > 0) | ||
537 | rdai->max_channels = max_channels; | ||
538 | |||
539 | return rdai->max_channels; | ||
540 | } | ||
541 | |||
542 | int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, | ||
543 | int ssi_lane) | ||
544 | { | ||
545 | if (ssi_lane > 0) | ||
546 | rdai->ssi_lane = ssi_lane; | ||
547 | |||
548 | return rdai->ssi_lane; | ||
549 | } | ||
550 | |||
535 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) | 551 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) |
536 | { | 552 | { |
537 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) | 553 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) |
@@ -551,40 +567,6 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) | |||
551 | /* | 567 | /* |
552 | * rsnd_soc_dai functions | 568 | * rsnd_soc_dai functions |
553 | */ | 569 | */ |
554 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional) | ||
555 | { | ||
556 | struct snd_pcm_substream *substream = io->substream; | ||
557 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
558 | int pos = io->byte_pos + additional; | ||
559 | |||
560 | pos %= (runtime->periods * io->byte_per_period); | ||
561 | |||
562 | return pos; | ||
563 | } | ||
564 | |||
565 | bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) | ||
566 | { | ||
567 | io->byte_pos += byte; | ||
568 | |||
569 | if (io->byte_pos >= io->next_period_byte) { | ||
570 | struct snd_pcm_substream *substream = io->substream; | ||
571 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
572 | |||
573 | io->period_pos++; | ||
574 | io->next_period_byte += io->byte_per_period; | ||
575 | |||
576 | if (io->period_pos >= runtime->periods) { | ||
577 | io->byte_pos = 0; | ||
578 | io->period_pos = 0; | ||
579 | io->next_period_byte = io->byte_per_period; | ||
580 | } | ||
581 | |||
582 | return true; | ||
583 | } | ||
584 | |||
585 | return false; | ||
586 | } | ||
587 | |||
588 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) | 570 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) |
589 | { | 571 | { |
590 | struct snd_pcm_substream *substream = io->substream; | 572 | struct snd_pcm_substream *substream = io->substream; |
@@ -602,15 +584,7 @@ void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) | |||
602 | static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, | 584 | static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, |
603 | struct snd_pcm_substream *substream) | 585 | struct snd_pcm_substream *substream) |
604 | { | 586 | { |
605 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
606 | |||
607 | io->substream = substream; | 587 | io->substream = substream; |
608 | io->byte_pos = 0; | ||
609 | io->period_pos = 0; | ||
610 | io->byte_per_period = runtime->period_size * | ||
611 | runtime->channels * | ||
612 | samples_to_bytes(runtime, 1); | ||
613 | io->next_period_byte = io->byte_per_period; | ||
614 | } | 588 | } |
615 | 589 | ||
616 | static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) | 590 | static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) |
@@ -749,9 +723,13 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, | |||
749 | struct device *dev = rsnd_priv_to_dev(priv); | 723 | struct device *dev = rsnd_priv_to_dev(priv); |
750 | 724 | ||
751 | switch (slots) { | 725 | switch (slots) { |
726 | case 2: | ||
752 | case 6: | 727 | case 6: |
728 | case 8: | ||
729 | case 16: | ||
753 | /* TDM Extend Mode */ | 730 | /* TDM Extend Mode */ |
754 | rsnd_set_slot(rdai, slots, 1); | 731 | rsnd_rdai_channels_set(rdai, slots); |
732 | rsnd_rdai_ssi_lane_set(rdai, 1); | ||
755 | break; | 733 | break; |
756 | default: | 734 | default: |
757 | dev_err(dev, "unsupported TDM slots (%d)\n", slots); | 735 | dev_err(dev, "unsupported TDM slots (%d)\n", slots); |
@@ -761,22 +739,177 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, | |||
761 | return 0; | 739 | return 0; |
762 | } | 740 | } |
763 | 741 | ||
742 | static unsigned int rsnd_soc_hw_channels_list[] = { | ||
743 | 2, 6, 8, 16, | ||
744 | }; | ||
745 | |||
746 | static unsigned int rsnd_soc_hw_rate_list[] = { | ||
747 | 8000, | ||
748 | 11025, | ||
749 | 16000, | ||
750 | 22050, | ||
751 | 32000, | ||
752 | 44100, | ||
753 | 48000, | ||
754 | 64000, | ||
755 | 88200, | ||
756 | 96000, | ||
757 | 176400, | ||
758 | 192000, | ||
759 | }; | ||
760 | |||
761 | static int rsnd_soc_hw_rule(struct rsnd_priv *priv, | ||
762 | unsigned int *list, int list_num, | ||
763 | struct snd_interval *baseline, struct snd_interval *iv) | ||
764 | { | ||
765 | struct snd_interval p; | ||
766 | unsigned int rate; | ||
767 | int i; | ||
768 | |||
769 | snd_interval_any(&p); | ||
770 | p.min = UINT_MAX; | ||
771 | p.max = 0; | ||
772 | |||
773 | for (i = 0; i < list_num; i++) { | ||
774 | |||
775 | if (!snd_interval_test(iv, list[i])) | ||
776 | continue; | ||
777 | |||
778 | rate = rsnd_ssi_clk_query(priv, | ||
779 | baseline->min, list[i], NULL); | ||
780 | if (rate > 0) { | ||
781 | p.min = min(p.min, list[i]); | ||
782 | p.max = max(p.max, list[i]); | ||
783 | } | ||
784 | |||
785 | rate = rsnd_ssi_clk_query(priv, | ||
786 | baseline->max, list[i], NULL); | ||
787 | if (rate > 0) { | ||
788 | p.min = min(p.min, list[i]); | ||
789 | p.max = max(p.max, list[i]); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | return snd_interval_refine(iv, &p); | ||
794 | } | ||
795 | |||
796 | static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, | ||
797 | struct snd_pcm_hw_rule *rule) | ||
798 | { | ||
799 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
800 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
801 | struct snd_interval ic; | ||
802 | struct snd_soc_dai *dai = rule->private; | ||
803 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
804 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | ||
805 | |||
806 | /* | ||
807 | * possible sampling rate limitation is same as | ||
808 | * 2ch if it supports multi ssi | ||
809 | */ | ||
810 | ic = *ic_; | ||
811 | if (1 < rsnd_rdai_ssi_lane_get(rdai)) { | ||
812 | ic.min = 2; | ||
813 | ic.max = 2; | ||
814 | } | ||
815 | |||
816 | return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, | ||
817 | ARRAY_SIZE(rsnd_soc_hw_rate_list), | ||
818 | &ic, ir); | ||
819 | } | ||
820 | |||
821 | |||
822 | static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, | ||
823 | struct snd_pcm_hw_rule *rule) | ||
824 | { | ||
825 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
826 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
827 | struct snd_interval ic; | ||
828 | struct snd_soc_dai *dai = rule->private; | ||
829 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
830 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | ||
831 | |||
832 | /* | ||
833 | * possible sampling rate limitation is same as | ||
834 | * 2ch if it supports multi ssi | ||
835 | */ | ||
836 | ic = *ic_; | ||
837 | if (1 < rsnd_rdai_ssi_lane_get(rdai)) { | ||
838 | ic.min = 2; | ||
839 | ic.max = 2; | ||
840 | } | ||
841 | |||
842 | return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, | ||
843 | ARRAY_SIZE(rsnd_soc_hw_channels_list), | ||
844 | ir, &ic); | ||
845 | } | ||
846 | |||
847 | static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime, | ||
848 | struct snd_soc_dai *dai) | ||
849 | { | ||
850 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
851 | struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; | ||
852 | unsigned int max_channels = rsnd_rdai_channels_get(rdai); | ||
853 | int i; | ||
854 | |||
855 | /* | ||
856 | * Channel Limitation | ||
857 | * It depends on Platform design | ||
858 | */ | ||
859 | constraint->list = rsnd_soc_hw_channels_list; | ||
860 | constraint->count = 0; | ||
861 | constraint->mask = 0; | ||
862 | |||
863 | for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) { | ||
864 | if (rsnd_soc_hw_channels_list[i] > max_channels) | ||
865 | break; | ||
866 | constraint->count = i + 1; | ||
867 | } | ||
868 | |||
869 | snd_pcm_hw_constraint_list(runtime, 0, | ||
870 | SNDRV_PCM_HW_PARAM_CHANNELS, constraint); | ||
871 | |||
872 | /* | ||
873 | * Sampling Rate / Channel Limitation | ||
874 | * It depends on Clock Master Mode | ||
875 | */ | ||
876 | if (!rsnd_rdai_is_clk_master(rdai)) | ||
877 | return; | ||
878 | |||
879 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
880 | rsnd_soc_hw_rule_rate, dai, | ||
881 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
882 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
883 | rsnd_soc_hw_rule_channels, dai, | ||
884 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
885 | } | ||
886 | |||
764 | static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, | 887 | static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, |
765 | struct snd_soc_dai *dai) | 888 | struct snd_soc_dai *dai) |
766 | { | 889 | { |
767 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 890 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
891 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | ||
768 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | 892 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
893 | int ret; | ||
894 | |||
895 | /* rsnd_io_to_runtime() is not yet enabled here */ | ||
896 | rsnd_soc_hw_constraint(substream->runtime, dai); | ||
769 | 897 | ||
770 | /* | 898 | /* |
771 | * call rsnd_dai_call without spinlock | 899 | * call rsnd_dai_call without spinlock |
772 | */ | 900 | */ |
773 | return rsnd_dai_call(nolock_start, io, priv); | 901 | ret = rsnd_dai_call(nolock_start, io, priv); |
902 | if (ret < 0) | ||
903 | rsnd_dai_call(nolock_stop, io, priv); | ||
904 | |||
905 | return ret; | ||
774 | } | 906 | } |
775 | 907 | ||
776 | static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, | 908 | static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, |
777 | struct snd_soc_dai *dai) | 909 | struct snd_soc_dai *dai) |
778 | { | 910 | { |
779 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 911 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
912 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | ||
780 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | 913 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
781 | 914 | ||
782 | /* | 915 | /* |
@@ -820,32 +953,132 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, | |||
820 | of_node_put(node); | 953 | of_node_put(node); |
821 | } | 954 | } |
822 | 955 | ||
823 | static int rsnd_dai_probe(struct rsnd_priv *priv) | 956 | static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, |
957 | int *is_graph) | ||
824 | { | 958 | { |
959 | struct device *dev = rsnd_priv_to_dev(priv); | ||
960 | struct device_node *np = dev->of_node; | ||
825 | struct device_node *dai_node; | 961 | struct device_node *dai_node; |
826 | struct device_node *dai_np; | 962 | struct device_node *ret; |
963 | |||
964 | *is_graph = 0; | ||
965 | |||
966 | /* | ||
967 | * parse both previous dai (= rcar_sound,dai), and | ||
968 | * graph dai (= ports/port) | ||
969 | */ | ||
970 | dai_node = of_get_child_by_name(np, RSND_NODE_DAI); | ||
971 | if (dai_node) { | ||
972 | ret = dai_node; | ||
973 | goto of_node_compatible; | ||
974 | } | ||
975 | |||
976 | ret = np; | ||
977 | |||
978 | dai_node = of_graph_get_next_endpoint(np, NULL); | ||
979 | if (dai_node) | ||
980 | goto of_node_graph; | ||
981 | |||
982 | return NULL; | ||
983 | |||
984 | of_node_graph: | ||
985 | *is_graph = 1; | ||
986 | of_node_compatible: | ||
987 | of_node_put(dai_node); | ||
988 | |||
989 | return ret; | ||
990 | } | ||
991 | |||
992 | static void __rsnd_dai_probe(struct rsnd_priv *priv, | ||
993 | struct device_node *dai_np, | ||
994 | int dai_i, int is_graph) | ||
995 | { | ||
827 | struct device_node *playback, *capture; | 996 | struct device_node *playback, *capture; |
828 | struct rsnd_dai_stream *io_playback; | 997 | struct rsnd_dai_stream *io_playback; |
829 | struct rsnd_dai_stream *io_capture; | 998 | struct rsnd_dai_stream *io_capture; |
830 | struct snd_soc_dai_driver *rdrv, *drv; | 999 | struct snd_soc_dai_driver *drv; |
831 | struct rsnd_dai *rdai; | 1000 | struct rsnd_dai *rdai; |
832 | struct device *dev = rsnd_priv_to_dev(priv); | 1001 | struct device *dev = rsnd_priv_to_dev(priv); |
833 | int nr, dai_i, io_i; | 1002 | int io_i; |
834 | int ret; | 1003 | |
1004 | rdai = rsnd_rdai_get(priv, dai_i); | ||
1005 | drv = priv->daidrv + dai_i; | ||
1006 | io_playback = &rdai->playback; | ||
1007 | io_capture = &rdai->capture; | ||
1008 | |||
1009 | snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); | ||
1010 | |||
1011 | rdai->priv = priv; | ||
1012 | drv->name = rdai->name; | ||
1013 | drv->ops = &rsnd_soc_dai_ops; | ||
1014 | |||
1015 | snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, | ||
1016 | "DAI%d Playback", dai_i); | ||
1017 | drv->playback.rates = RSND_RATES; | ||
1018 | drv->playback.formats = RSND_FMTS; | ||
1019 | drv->playback.channels_min = 2; | ||
1020 | drv->playback.channels_max = 16; | ||
1021 | drv->playback.stream_name = rdai->playback.name; | ||
1022 | |||
1023 | snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, | ||
1024 | "DAI%d Capture", dai_i); | ||
1025 | drv->capture.rates = RSND_RATES; | ||
1026 | drv->capture.formats = RSND_FMTS; | ||
1027 | drv->capture.channels_min = 2; | ||
1028 | drv->capture.channels_max = 16; | ||
1029 | drv->capture.stream_name = rdai->capture.name; | ||
1030 | |||
1031 | rdai->playback.rdai = rdai; | ||
1032 | rdai->capture.rdai = rdai; | ||
1033 | rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ | ||
1034 | rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ | ||
1035 | |||
1036 | for (io_i = 0;; io_i++) { | ||
1037 | playback = of_parse_phandle(dai_np, "playback", io_i); | ||
1038 | capture = of_parse_phandle(dai_np, "capture", io_i); | ||
1039 | |||
1040 | if (!playback && !capture) | ||
1041 | break; | ||
835 | 1042 | ||
836 | dai_node = rsnd_dai_of_node(priv); | 1043 | rsnd_parse_connect_ssi(rdai, playback, capture); |
837 | nr = of_get_child_count(dai_node); | 1044 | rsnd_parse_connect_src(rdai, playback, capture); |
838 | if (!nr) { | 1045 | rsnd_parse_connect_ctu(rdai, playback, capture); |
839 | ret = -EINVAL; | 1046 | rsnd_parse_connect_mix(rdai, playback, capture); |
840 | goto rsnd_dai_probe_done; | 1047 | rsnd_parse_connect_dvc(rdai, playback, capture); |
1048 | |||
1049 | of_node_put(playback); | ||
1050 | of_node_put(capture); | ||
841 | } | 1051 | } |
842 | 1052 | ||
1053 | dev_dbg(dev, "%s (%s/%s)\n", rdai->name, | ||
1054 | rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", | ||
1055 | rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); | ||
1056 | } | ||
1057 | |||
1058 | static int rsnd_dai_probe(struct rsnd_priv *priv) | ||
1059 | { | ||
1060 | struct device_node *dai_node; | ||
1061 | struct device_node *dai_np; | ||
1062 | struct snd_soc_dai_driver *rdrv; | ||
1063 | struct device *dev = rsnd_priv_to_dev(priv); | ||
1064 | struct rsnd_dai *rdai; | ||
1065 | int nr; | ||
1066 | int is_graph; | ||
1067 | int dai_i; | ||
1068 | |||
1069 | dai_node = rsnd_dai_of_node(priv, &is_graph); | ||
1070 | if (is_graph) | ||
1071 | nr = of_graph_get_endpoint_count(dai_node); | ||
1072 | else | ||
1073 | nr = of_get_child_count(dai_node); | ||
1074 | |||
1075 | if (!nr) | ||
1076 | return -EINVAL; | ||
1077 | |||
843 | rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL); | 1078 | rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL); |
844 | rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); | 1079 | rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); |
845 | if (!rdrv || !rdai) { | 1080 | if (!rdrv || !rdai) |
846 | ret = -ENOMEM; | 1081 | return -ENOMEM; |
847 | goto rsnd_dai_probe_done; | ||
848 | } | ||
849 | 1082 | ||
850 | priv->rdai_nr = nr; | 1083 | priv->rdai_nr = nr; |
851 | priv->daidrv = rdrv; | 1084 | priv->daidrv = rdrv; |
@@ -855,68 +1088,18 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) | |||
855 | * parse all dai | 1088 | * parse all dai |
856 | */ | 1089 | */ |
857 | dai_i = 0; | 1090 | dai_i = 0; |
858 | for_each_child_of_node(dai_node, dai_np) { | 1091 | if (is_graph) { |
859 | rdai = rsnd_rdai_get(priv, dai_i); | 1092 | for_each_endpoint_of_node(dai_node, dai_np) { |
860 | drv = rdrv + dai_i; | 1093 | __rsnd_dai_probe(priv, dai_np, dai_i, is_graph); |
861 | io_playback = &rdai->playback; | 1094 | rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); |
862 | io_capture = &rdai->capture; | 1095 | 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 | } | 1096 | } |
906 | 1097 | } else { | |
907 | dai_i++; | 1098 | for_each_child_of_node(dai_node, dai_np) |
908 | 1099 | __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 | } | 1100 | } |
913 | 1101 | ||
914 | ret = 0; | 1102 | return 0; |
915 | |||
916 | rsnd_dai_probe_done: | ||
917 | of_node_put(dai_node); | ||
918 | |||
919 | return ret; | ||
920 | } | 1103 | } |
921 | 1104 | ||
922 | /* | 1105 | /* |
@@ -965,12 +1148,14 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream, | |||
965 | 1148 | ||
966 | static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) | 1149 | static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) |
967 | { | 1150 | { |
968 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
969 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); | 1151 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); |
970 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 1152 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
971 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | 1153 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
1154 | snd_pcm_uframes_t pointer = 0; | ||
1155 | |||
1156 | rsnd_dai_call(pointer, io, &pointer); | ||
972 | 1157 | ||
973 | return bytes_to_frames(runtime, io->byte_pos); | 1158 | return pointer; |
974 | } | 1159 | } |
975 | 1160 | ||
976 | static struct snd_pcm_ops rsnd_pcm_ops = { | 1161 | static struct snd_pcm_ops rsnd_pcm_ops = { |
@@ -1033,6 +1218,9 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, | |||
1033 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); | 1218 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); |
1034 | int i, change = 0; | 1219 | int i, change = 0; |
1035 | 1220 | ||
1221 | if (!cfg->accept(cfg->io)) | ||
1222 | return 0; | ||
1223 | |||
1036 | for (i = 0; i < cfg->size; i++) { | 1224 | for (i = 0; i < cfg->size; i++) { |
1037 | if (cfg->texts) { | 1225 | if (cfg->texts) { |
1038 | change |= (uc->value.enumerated.item[i] != cfg->val[i]); | 1226 | change |= (uc->value.enumerated.item[i] != cfg->val[i]); |
@@ -1049,6 +1237,18 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, | |||
1049 | return change; | 1237 | return change; |
1050 | } | 1238 | } |
1051 | 1239 | ||
1240 | int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) | ||
1241 | { | ||
1242 | return 1; | ||
1243 | } | ||
1244 | |||
1245 | int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) | ||
1246 | { | ||
1247 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
1248 | |||
1249 | return !!runtime; | ||
1250 | } | ||
1251 | |||
1052 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) | 1252 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) |
1053 | { | 1253 | { |
1054 | cfg->cfg.val = cfg->val; | 1254 | cfg->cfg.val = cfg->val; |
@@ -1067,6 +1267,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, | |||
1067 | struct rsnd_dai_stream *io, | 1267 | struct rsnd_dai_stream *io, |
1068 | struct snd_soc_pcm_runtime *rtd, | 1268 | struct snd_soc_pcm_runtime *rtd, |
1069 | const unsigned char *name, | 1269 | const unsigned char *name, |
1270 | int (*accept)(struct rsnd_dai_stream *io), | ||
1070 | void (*update)(struct rsnd_dai_stream *io, | 1271 | void (*update)(struct rsnd_dai_stream *io, |
1071 | struct rsnd_mod *mod), | 1272 | struct rsnd_mod *mod), |
1072 | struct rsnd_kctrl_cfg *cfg, | 1273 | struct rsnd_kctrl_cfg *cfg, |
@@ -1101,6 +1302,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, | |||
1101 | cfg->texts = texts; | 1302 | cfg->texts = texts; |
1102 | cfg->max = max; | 1303 | cfg->max = max; |
1103 | cfg->size = size; | 1304 | cfg->size = size; |
1305 | cfg->accept = accept; | ||
1104 | cfg->update = update; | 1306 | cfg->update = update; |
1105 | cfg->card = card; | 1307 | cfg->card = card; |
1106 | cfg->kctrl = kctrl; | 1308 | cfg->kctrl = kctrl; |
@@ -1332,7 +1534,7 @@ static int rsnd_resume(struct device *dev) | |||
1332 | return 0; | 1534 | return 0; |
1333 | } | 1535 | } |
1334 | 1536 | ||
1335 | static struct dev_pm_ops rsnd_pm_ops = { | 1537 | static const struct dev_pm_ops rsnd_pm_ops = { |
1336 | .suspend = rsnd_suspend, | 1538 | .suspend = rsnd_suspend, |
1337 | .resume = rsnd_resume, | 1539 | .resume = rsnd_resume, |
1338 | }; | 1540 | }; |
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 9dcc1f9db026..4ba8f2fe7a4c 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c | |||
@@ -279,12 +279,14 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
279 | 279 | ||
280 | /* CTU Pass */ | 280 | /* CTU Pass */ |
281 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", | 281 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", |
282 | rsnd_kctrl_accept_anytime, | ||
282 | NULL, | 283 | NULL, |
283 | &ctu->pass, RSND_MAX_CHANNELS, | 284 | &ctu->pass, RSND_MAX_CHANNELS, |
284 | 0xC); | 285 | 0xC); |
285 | 286 | ||
286 | /* ROW0 */ | 287 | /* ROW0 */ |
287 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", | 288 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", |
289 | rsnd_kctrl_accept_anytime, | ||
288 | NULL, | 290 | NULL, |
289 | &ctu->sv0, RSND_MAX_CHANNELS, | 291 | &ctu->sv0, RSND_MAX_CHANNELS, |
290 | 0x00FFFFFF); | 292 | 0x00FFFFFF); |
@@ -293,6 +295,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
293 | 295 | ||
294 | /* ROW1 */ | 296 | /* ROW1 */ |
295 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", | 297 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", |
298 | rsnd_kctrl_accept_anytime, | ||
296 | NULL, | 299 | NULL, |
297 | &ctu->sv1, RSND_MAX_CHANNELS, | 300 | &ctu->sv1, RSND_MAX_CHANNELS, |
298 | 0x00FFFFFF); | 301 | 0x00FFFFFF); |
@@ -301,6 +304,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
301 | 304 | ||
302 | /* ROW2 */ | 305 | /* ROW2 */ |
303 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", | 306 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", |
307 | rsnd_kctrl_accept_anytime, | ||
304 | NULL, | 308 | NULL, |
305 | &ctu->sv2, RSND_MAX_CHANNELS, | 309 | &ctu->sv2, RSND_MAX_CHANNELS, |
306 | 0x00FFFFFF); | 310 | 0x00FFFFFF); |
@@ -309,6 +313,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
309 | 313 | ||
310 | /* ROW3 */ | 314 | /* ROW3 */ |
311 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", | 315 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", |
316 | rsnd_kctrl_accept_anytime, | ||
312 | NULL, | 317 | NULL, |
313 | &ctu->sv3, RSND_MAX_CHANNELS, | 318 | &ctu->sv3, RSND_MAX_CHANNELS, |
314 | 0x00FFFFFF); | 319 | 0x00FFFFFF); |
@@ -317,6 +322,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
317 | 322 | ||
318 | /* Reset */ | 323 | /* Reset */ |
319 | ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset", | 324 | ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset", |
325 | rsnd_kctrl_accept_anytime, | ||
320 | rsnd_ctu_value_reset, | 326 | rsnd_ctu_value_reset, |
321 | &ctu->reset, 1); | 327 | &ctu->reset, 1); |
322 | 328 | ||
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 241cb3b08a07..60aa5e96a49f 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | struct rsnd_dmaen { | 26 | struct 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; |
@@ -103,10 +104,6 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, | |||
103 | * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. | 104 | * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. |
104 | * But, Audio-DMAC-peri-peri doesn't have interrupt, | 105 | * But, Audio-DMAC-peri-peri doesn't have interrupt, |
105 | * and this driver is assuming that here. | 106 | * and this driver is assuming that here. |
106 | * | ||
107 | * If Audio-DMAC-peri-peri has interrpt, | ||
108 | * rsnd_dai_pointer_update() will be called twice, | ||
109 | * ant it will breaks io->byte_pos | ||
110 | */ | 107 | */ |
111 | spin_lock_irqsave(&priv->lock, flags); | 108 | spin_lock_irqsave(&priv->lock, flags); |
112 | 109 | ||
@@ -121,7 +118,7 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, | |||
121 | */ | 118 | */ |
122 | rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); | 119 | rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); |
123 | 120 | ||
124 | elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); | 121 | elapsed = true; |
125 | 122 | ||
126 | dmaen->dma_cnt++; | 123 | dmaen->dma_cnt++; |
127 | } | 124 | } |
@@ -292,7 +289,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, | |||
292 | for (i = 0; i < 2; i++) | 289 | for (i = 0; i < 2; i++) |
293 | rsnd_dmaen_sync(dmaen, io, i); | 290 | rsnd_dmaen_sync(dmaen, io, i); |
294 | 291 | ||
295 | if (dmaengine_submit(desc) < 0) { | 292 | dmaen->cookie = dmaengine_submit(desc); |
293 | if (dmaen->cookie < 0) { | ||
296 | dev_err(dev, "dmaengine_submit() fail\n"); | 294 | dev_err(dev, "dmaengine_submit() fail\n"); |
297 | return -EIO; | 295 | return -EIO; |
298 | } | 296 | } |
@@ -348,12 +346,34 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, | |||
348 | return 0; | 346 | return 0; |
349 | } | 347 | } |
350 | 348 | ||
349 | static int rsnd_dmaen_pointer(struct rsnd_mod *mod, | ||
350 | struct rsnd_dai_stream *io, | ||
351 | snd_pcm_uframes_t *pointer) | ||
352 | { | ||
353 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
354 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
355 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | ||
356 | struct dma_tx_state state; | ||
357 | enum dma_status status; | ||
358 | unsigned int pos = 0; | ||
359 | |||
360 | status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state); | ||
361 | if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { | ||
362 | if (state.residue > 0 && state.residue <= dmaen->dma_len) | ||
363 | pos = dmaen->dma_len - state.residue; | ||
364 | } | ||
365 | *pointer = bytes_to_frames(runtime, pos); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
351 | static struct rsnd_mod_ops rsnd_dmaen_ops = { | 370 | static struct rsnd_mod_ops rsnd_dmaen_ops = { |
352 | .name = "audmac", | 371 | .name = "audmac", |
353 | .nolock_start = rsnd_dmaen_nolock_start, | 372 | .nolock_start = rsnd_dmaen_nolock_start, |
354 | .nolock_stop = rsnd_dmaen_nolock_stop, | 373 | .nolock_stop = rsnd_dmaen_nolock_stop, |
355 | .start = rsnd_dmaen_start, | 374 | .start = rsnd_dmaen_start, |
356 | .stop = rsnd_dmaen_stop, | 375 | .stop = rsnd_dmaen_stop, |
376 | .pointer= rsnd_dmaen_pointer, | ||
357 | }; | 377 | }; |
358 | 378 | ||
359 | /* | 379 | /* |
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 463de8360985..99d2d9459e75 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
@@ -249,16 +249,18 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
249 | struct snd_soc_pcm_runtime *rtd) | 249 | struct snd_soc_pcm_runtime *rtd) |
250 | { | 250 | { |
251 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 251 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
252 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
252 | int is_play = rsnd_io_is_play(io); | 253 | int is_play = rsnd_io_is_play(io); |
253 | int slots = rsnd_get_slot(io); | 254 | int channels = rsnd_rdai_channels_get(rdai); |
254 | int ret; | 255 | int ret; |
255 | 256 | ||
256 | /* Volume */ | 257 | /* Volume */ |
257 | ret = rsnd_kctrl_new_m(mod, io, rtd, | 258 | ret = rsnd_kctrl_new_m(mod, io, rtd, |
258 | is_play ? | 259 | is_play ? |
259 | "DVC Out Playback Volume" : "DVC In Capture Volume", | 260 | "DVC Out Playback Volume" : "DVC In Capture Volume", |
261 | rsnd_kctrl_accept_anytime, | ||
260 | rsnd_dvc_volume_update, | 262 | rsnd_dvc_volume_update, |
261 | &dvc->volume, slots, | 263 | &dvc->volume, channels, |
262 | 0x00800000 - 1); | 264 | 0x00800000 - 1); |
263 | if (ret < 0) | 265 | if (ret < 0) |
264 | return ret; | 266 | return ret; |
@@ -267,8 +269,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
267 | ret = rsnd_kctrl_new_m(mod, io, rtd, | 269 | ret = rsnd_kctrl_new_m(mod, io, rtd, |
268 | is_play ? | 270 | is_play ? |
269 | "DVC Out Mute Switch" : "DVC In Mute Switch", | 271 | "DVC Out Mute Switch" : "DVC In Mute Switch", |
272 | rsnd_kctrl_accept_anytime, | ||
270 | rsnd_dvc_volume_update, | 273 | rsnd_dvc_volume_update, |
271 | &dvc->mute, slots, | 274 | &dvc->mute, channels, |
272 | 1); | 275 | 1); |
273 | if (ret < 0) | 276 | if (ret < 0) |
274 | return ret; | 277 | return ret; |
@@ -277,6 +280,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
277 | ret = rsnd_kctrl_new_s(mod, io, rtd, | 280 | ret = rsnd_kctrl_new_s(mod, io, rtd, |
278 | is_play ? | 281 | is_play ? |
279 | "DVC Out Ramp Switch" : "DVC In Ramp Switch", | 282 | "DVC Out Ramp Switch" : "DVC In Ramp Switch", |
283 | rsnd_kctrl_accept_anytime, | ||
280 | rsnd_dvc_volume_update, | 284 | rsnd_dvc_volume_update, |
281 | &dvc->ren, 1); | 285 | &dvc->ren, 1); |
282 | if (ret < 0) | 286 | if (ret < 0) |
@@ -285,6 +289,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
285 | ret = rsnd_kctrl_new_e(mod, io, rtd, | 289 | ret = rsnd_kctrl_new_e(mod, io, rtd, |
286 | is_play ? | 290 | is_play ? |
287 | "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", | 291 | "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", |
292 | rsnd_kctrl_accept_anytime, | ||
288 | rsnd_dvc_volume_update, | 293 | rsnd_dvc_volume_update, |
289 | &dvc->rup, | 294 | &dvc->rup, |
290 | dvc_ramp_rate); | 295 | dvc_ramp_rate); |
@@ -294,6 +299,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
294 | ret = rsnd_kctrl_new_e(mod, io, rtd, | 299 | ret = rsnd_kctrl_new_e(mod, io, rtd, |
295 | is_play ? | 300 | is_play ? |
296 | "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", | 301 | "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", |
302 | rsnd_kctrl_accept_anytime, | ||
297 | rsnd_dvc_volume_update, | 303 | rsnd_dvc_volume_update, |
298 | &dvc->rdown, | 304 | &dvc->rdown, |
299 | dvc_ramp_rate); | 305 | dvc_ramp_rate); |
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..99c57611df88 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 | ||
@@ -389,11 +399,6 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, | |||
389 | struct device_node *playback, | 399 | struct device_node *playback, |
390 | struct device_node *capture); | 400 | struct device_node *capture); |
391 | 401 | ||
392 | void rsnd_set_slot(struct rsnd_dai *rdai, | ||
393 | int slots, int slots_total); | ||
394 | int rsnd_get_slot(struct rsnd_dai_stream *io); | ||
395 | int rsnd_get_slot_num(struct rsnd_dai_stream *io); | ||
396 | |||
397 | int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); | 402 | int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); |
398 | int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); | 403 | int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); |
399 | int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); | 404 | int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); |
@@ -420,13 +425,8 @@ struct rsnd_dai_stream { | |||
420 | char name[RSND_DAI_NAME_SIZE]; | 425 | char name[RSND_DAI_NAME_SIZE]; |
421 | struct snd_pcm_substream *substream; | 426 | struct snd_pcm_substream *substream; |
422 | struct rsnd_mod *mod[RSND_MOD_MAX]; | 427 | struct rsnd_mod *mod[RSND_MOD_MAX]; |
423 | struct rsnd_dai_path_info *info; /* rcar_snd.h */ | ||
424 | struct rsnd_dai *rdai; | 428 | struct rsnd_dai *rdai; |
425 | u32 parent_ssi_status; | 429 | u32 parent_ssi_status; |
426 | int byte_pos; | ||
427 | int period_pos; | ||
428 | int byte_per_period; | ||
429 | int next_period_byte; | ||
430 | }; | 430 | }; |
431 | #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) | 431 | #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) |
432 | #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) | 432 | #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) |
@@ -449,9 +449,10 @@ struct rsnd_dai { | |||
449 | struct rsnd_dai_stream playback; | 449 | struct rsnd_dai_stream playback; |
450 | struct rsnd_dai_stream capture; | 450 | struct rsnd_dai_stream capture; |
451 | struct rsnd_priv *priv; | 451 | struct rsnd_priv *priv; |
452 | struct snd_pcm_hw_constraint_list constraint; | ||
452 | 453 | ||
453 | int slots; | 454 | int max_channels; /* 2ch - 16ch */ |
454 | int slots_num; | 455 | int ssi_lane; /* 1lane - 4lane */ |
455 | 456 | ||
456 | unsigned int clk_master:1; | 457 | unsigned int clk_master:1; |
457 | unsigned int bit_clk_inv:1; | 458 | unsigned int bit_clk_inv:1; |
@@ -471,13 +472,24 @@ struct rsnd_dai { | |||
471 | 472 | ||
472 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); | 473 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); |
473 | 474 | ||
474 | bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 475 | #define rsnd_rdai_channels_set(rdai, max_channels) \ |
476 | rsnd_rdai_channels_ctrl(rdai, max_channels) | ||
477 | #define rsnd_rdai_channels_get(rdai) \ | ||
478 | rsnd_rdai_channels_ctrl(rdai, 0) | ||
479 | int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, | ||
480 | int max_channels); | ||
481 | |||
482 | #define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \ | ||
483 | rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane) | ||
484 | #define rsnd_rdai_ssi_lane_get(rdai) \ | ||
485 | rsnd_rdai_ssi_lane_ctrl(rdai, 0) | ||
486 | int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, | ||
487 | int ssi_lane); | ||
488 | |||
475 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); | 489 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); |
476 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | ||
477 | int rsnd_dai_connect(struct rsnd_mod *mod, | 490 | int rsnd_dai_connect(struct rsnd_mod *mod, |
478 | struct rsnd_dai_stream *io, | 491 | struct rsnd_dai_stream *io, |
479 | enum rsnd_mod_type type); | 492 | enum rsnd_mod_type type); |
480 | #define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI) | ||
481 | 493 | ||
482 | /* | 494 | /* |
483 | * R-Car Gen1/Gen2 | 495 | * R-Car Gen1/Gen2 |
@@ -491,6 +503,7 @@ phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); | |||
491 | /* | 503 | /* |
492 | * R-Car ADG | 504 | * R-Car ADG |
493 | */ | 505 | */ |
506 | int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate); | ||
494 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); | 507 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); |
495 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); | 508 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); |
496 | int rsnd_adg_probe(struct rsnd_priv *priv); | 509 | int rsnd_adg_probe(struct rsnd_priv *priv); |
@@ -596,6 +609,7 @@ struct rsnd_kctrl_cfg { | |||
596 | unsigned int size; | 609 | unsigned int size; |
597 | u32 *val; | 610 | u32 *val; |
598 | const char * const *texts; | 611 | const char * const *texts; |
612 | int (*accept)(struct rsnd_dai_stream *io); | ||
599 | void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod); | 613 | void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod); |
600 | struct rsnd_dai_stream *io; | 614 | struct rsnd_dai_stream *io; |
601 | struct snd_card *card; | 615 | struct snd_card *card; |
@@ -613,12 +627,15 @@ struct rsnd_kctrl_cfg_s { | |||
613 | u32 val; | 627 | u32 val; |
614 | }; | 628 | }; |
615 | 629 | ||
630 | int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io); | ||
631 | int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io); | ||
616 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg); | 632 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg); |
617 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg); | 633 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg); |
618 | int rsnd_kctrl_new(struct rsnd_mod *mod, | 634 | int rsnd_kctrl_new(struct rsnd_mod *mod, |
619 | struct rsnd_dai_stream *io, | 635 | struct rsnd_dai_stream *io, |
620 | struct snd_soc_pcm_runtime *rtd, | 636 | struct snd_soc_pcm_runtime *rtd, |
621 | const unsigned char *name, | 637 | const unsigned char *name, |
638 | int (*accept)(struct rsnd_dai_stream *io), | ||
622 | void (*update)(struct rsnd_dai_stream *io, | 639 | void (*update)(struct rsnd_dai_stream *io, |
623 | struct rsnd_mod *mod), | 640 | struct rsnd_mod *mod), |
624 | struct rsnd_kctrl_cfg *cfg, | 641 | struct rsnd_kctrl_cfg *cfg, |
@@ -626,16 +643,16 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, | |||
626 | int size, | 643 | int size, |
627 | u32 max); | 644 | u32 max); |
628 | 645 | ||
629 | #define rsnd_kctrl_new_m(mod, io, rtd, name, update, cfg, size, max) \ | 646 | #define rsnd_kctrl_new_m(mod, io, rtd, name, accept, update, cfg, size, max) \ |
630 | rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_m(cfg), \ | 647 | rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_m(cfg), \ |
631 | NULL, size, max) | 648 | NULL, size, max) |
632 | 649 | ||
633 | #define rsnd_kctrl_new_s(mod, io, rtd, name, update, cfg, max) \ | 650 | #define rsnd_kctrl_new_s(mod, io, rtd, name, accept, update, cfg, max) \ |
634 | rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \ | 651 | rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ |
635 | NULL, 1, max) | 652 | NULL, 1, max) |
636 | 653 | ||
637 | #define rsnd_kctrl_new_e(mod, io, rtd, name, update, cfg, texts) \ | 654 | #define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts) \ |
638 | rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \ | 655 | rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ |
639 | texts, 1, ARRAY_SIZE(texts)) | 656 | texts, 1, ARRAY_SIZE(texts)) |
640 | 657 | ||
641 | /* | 658 | /* |
@@ -648,6 +665,13 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); | |||
648 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); | 665 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); |
649 | u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); | 666 | u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); |
650 | 667 | ||
668 | #define RSND_SSI_HDMI_PORT0 0xf0 | ||
669 | #define RSND_SSI_HDMI_PORT1 0xf1 | ||
670 | int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io); | ||
671 | void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, | ||
672 | struct device_node *endpoint, | ||
673 | int dai_i); | ||
674 | |||
651 | #define rsnd_ssi_is_pin_sharing(io) \ | 675 | #define rsnd_ssi_is_pin_sharing(io) \ |
652 | __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) | 676 | __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) |
653 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | 677 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); |
@@ -656,6 +680,8 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | |||
656 | void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, | 680 | void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, |
657 | struct device_node *playback, | 681 | struct device_node *playback, |
658 | struct device_node *capture); | 682 | struct device_node *capture); |
683 | unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, | ||
684 | int param1, int param2, int *idx); | ||
659 | 685 | ||
660 | /* | 686 | /* |
661 | * R-Car SSIU | 687 | * R-Car SSIU |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 76a477a3ccb5..7aa239e28491 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 | |||
72 | static void rsnd_src_activation(struct rsnd_mod *mod) | 54 | static 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); |
@@ -515,6 +497,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, | |||
515 | rsnd_io_is_play(io) ? | 497 | rsnd_io_is_play(io) ? |
516 | "SRC Out Rate Switch" : | 498 | "SRC Out Rate Switch" : |
517 | "SRC In Rate Switch", | 499 | "SRC In Rate Switch", |
500 | rsnd_kctrl_accept_anytime, | ||
518 | rsnd_src_set_convert_rate, | 501 | rsnd_src_set_convert_rate, |
519 | &src->sen, 1); | 502 | &src->sen, 1); |
520 | if (ret < 0) | 503 | if (ret < 0) |
@@ -524,6 +507,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, | |||
524 | rsnd_io_is_play(io) ? | 507 | rsnd_io_is_play(io) ? |
525 | "SRC Out Rate" : | 508 | "SRC Out Rate" : |
526 | "SRC In Rate", | 509 | "SRC In Rate", |
510 | rsnd_kctrl_accept_runtime, | ||
527 | rsnd_src_set_convert_rate, | 511 | rsnd_src_set_convert_rate, |
528 | &src->sync, 192000); | 512 | &src->sync, 192000); |
529 | 513 | ||
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 91e5c07911b4..46feddd78ee2 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 |
@@ -76,11 +77,18 @@ struct rsnd_ssi { | |||
76 | int rate; | 77 | int rate; |
77 | int irq; | 78 | int irq; |
78 | unsigned int usrcnt; | 79 | unsigned int usrcnt; |
80 | |||
81 | int byte_pos; | ||
82 | int period_pos; | ||
83 | int byte_per_period; | ||
84 | int next_period_byte; | ||
79 | }; | 85 | }; |
80 | 86 | ||
81 | /* flags */ | 87 | /* flags */ |
82 | #define RSND_SSI_CLK_PIN_SHARE (1 << 0) | 88 | #define RSND_SSI_CLK_PIN_SHARE (1 << 0) |
83 | #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ | 89 | #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ |
90 | #define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */ | ||
91 | #define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */ | ||
84 | 92 | ||
85 | #define for_each_rsnd_ssi(pos, priv, i) \ | 93 | #define for_each_rsnd_ssi(pos, priv, i) \ |
86 | for (i = 0; \ | 94 | for (i = 0; \ |
@@ -99,6 +107,20 @@ struct rsnd_ssi { | |||
99 | #define rsnd_ssi_is_run_mods(mod, io) \ | 107 | #define rsnd_ssi_is_run_mods(mod, io) \ |
100 | (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) | 108 | (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) |
101 | 109 | ||
110 | int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io) | ||
111 | { | ||
112 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); | ||
113 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
114 | |||
115 | if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0) | ||
116 | return RSND_SSI_HDMI_PORT0; | ||
117 | |||
118 | if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1) | ||
119 | return RSND_SSI_HDMI_PORT1; | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
102 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) | 124 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) |
103 | { | 125 | { |
104 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); | 126 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); |
@@ -186,6 +208,46 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) | |||
186 | return 0; | 208 | return 0; |
187 | } | 209 | } |
188 | 210 | ||
211 | unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, | ||
212 | int param1, int param2, int *idx) | ||
213 | { | ||
214 | int ssi_clk_mul_table[] = { | ||
215 | 1, 2, 4, 8, 16, 6, 12, | ||
216 | }; | ||
217 | int j, ret; | ||
218 | unsigned int main_rate; | ||
219 | |||
220 | for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { | ||
221 | |||
222 | /* | ||
223 | * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 | ||
224 | * with it is not allowed. (SSIWSR.WS_MODE with | ||
225 | * SSICR.CKDV = 000 is not allowed either). | ||
226 | * Skip it. See SSICR.CKDV | ||
227 | */ | ||
228 | if (j == 0) | ||
229 | continue; | ||
230 | |||
231 | /* | ||
232 | * this driver is assuming that | ||
233 | * system word is 32bit x chan | ||
234 | * see rsnd_ssi_init() | ||
235 | */ | ||
236 | main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j]; | ||
237 | |||
238 | ret = rsnd_adg_clk_query(priv, main_rate); | ||
239 | if (ret < 0) | ||
240 | continue; | ||
241 | |||
242 | if (idx) | ||
243 | *idx = j; | ||
244 | |||
245 | return main_rate; | ||
246 | } | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
189 | static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, | 251 | static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, |
190 | struct rsnd_dai_stream *io) | 252 | struct rsnd_dai_stream *io) |
191 | { | 253 | { |
@@ -195,10 +257,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, | |||
195 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 257 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
196 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); | 258 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); |
197 | int chan = rsnd_runtime_channel_for_ssi(io); | 259 | int chan = rsnd_runtime_channel_for_ssi(io); |
198 | int j, ret; | 260 | int idx, ret; |
199 | int ssi_clk_mul_table[] = { | ||
200 | 1, 2, 4, 8, 16, 6, 12, | ||
201 | }; | ||
202 | unsigned int main_rate; | 261 | unsigned int main_rate; |
203 | unsigned int rate = rsnd_io_is_play(io) ? | 262 | unsigned int rate = rsnd_io_is_play(io) ? |
204 | rsnd_src_get_out_rate(priv, io) : | 263 | rsnd_src_get_out_rate(priv, io) : |
@@ -222,45 +281,25 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, | |||
222 | return 0; | 281 | return 0; |
223 | } | 282 | } |
224 | 283 | ||
225 | /* | 284 | main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx); |
226 | * Find best clock, and try to start ADG | 285 | if (!main_rate) { |
227 | */ | 286 | dev_err(dev, "unsupported clock rate\n"); |
228 | for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { | 287 | return -EIO; |
229 | 288 | } | |
230 | /* | ||
231 | * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 | ||
232 | * with it is not allowed. (SSIWSR.WS_MODE with | ||
233 | * SSICR.CKDV = 000 is not allowed either). | ||
234 | * Skip it. See SSICR.CKDV | ||
235 | */ | ||
236 | if (j == 0) | ||
237 | continue; | ||
238 | |||
239 | /* | ||
240 | * this driver is assuming that | ||
241 | * system word is 32bit x chan | ||
242 | * see rsnd_ssi_init() | ||
243 | */ | ||
244 | main_rate = rate * 32 * chan * ssi_clk_mul_table[j]; | ||
245 | |||
246 | ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); | ||
247 | if (0 == ret) { | ||
248 | ssi->cr_clk = FORCE | SWL_32 | | ||
249 | SCKD | SWSD | CKDV(j); | ||
250 | ssi->wsr = CONT; | ||
251 | 289 | ||
252 | ssi->rate = rate; | 290 | ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); |
291 | if (ret < 0) | ||
292 | return ret; | ||
253 | 293 | ||
254 | dev_dbg(dev, "%s[%d] outputs %u Hz\n", | 294 | ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx); |
255 | rsnd_mod_name(mod), | 295 | ssi->wsr = CONT; |
256 | rsnd_mod_id(mod), rate); | 296 | ssi->rate = rate; |
257 | 297 | ||
258 | return 0; | 298 | dev_dbg(dev, "%s[%d] outputs %u Hz\n", |
259 | } | 299 | rsnd_mod_name(mod), |
260 | } | 300 | rsnd_mod_id(mod), rate); |
261 | 301 | ||
262 | dev_err(dev, "unsupported clock rate\n"); | 302 | return 0; |
263 | return -EIO; | ||
264 | } | 303 | } |
265 | 304 | ||
266 | static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, | 305 | static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, |
@@ -357,6 +396,59 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod) | |||
357 | ssi->cr_mode); /* without EN */ | 396 | ssi->cr_mode); /* without EN */ |
358 | } | 397 | } |
359 | 398 | ||
399 | static void rsnd_ssi_pointer_init(struct rsnd_mod *mod, | ||
400 | struct rsnd_dai_stream *io) | ||
401 | { | ||
402 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
403 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
404 | |||
405 | ssi->byte_pos = 0; | ||
406 | ssi->period_pos = 0; | ||
407 | ssi->byte_per_period = runtime->period_size * | ||
408 | runtime->channels * | ||
409 | samples_to_bytes(runtime, 1); | ||
410 | ssi->next_period_byte = ssi->byte_per_period; | ||
411 | } | ||
412 | |||
413 | static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod, | ||
414 | struct rsnd_dai_stream *io, | ||
415 | int additional) | ||
416 | { | ||
417 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
418 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
419 | int pos = ssi->byte_pos + additional; | ||
420 | |||
421 | pos %= (runtime->periods * ssi->byte_per_period); | ||
422 | |||
423 | return pos; | ||
424 | } | ||
425 | |||
426 | static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod, | ||
427 | struct rsnd_dai_stream *io, | ||
428 | int byte) | ||
429 | { | ||
430 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
431 | |||
432 | ssi->byte_pos += byte; | ||
433 | |||
434 | if (ssi->byte_pos >= ssi->next_period_byte) { | ||
435 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
436 | |||
437 | ssi->period_pos++; | ||
438 | ssi->next_period_byte += ssi->byte_per_period; | ||
439 | |||
440 | if (ssi->period_pos >= runtime->periods) { | ||
441 | ssi->byte_pos = 0; | ||
442 | ssi->period_pos = 0; | ||
443 | ssi->next_period_byte = ssi->byte_per_period; | ||
444 | } | ||
445 | |||
446 | return true; | ||
447 | } | ||
448 | |||
449 | return false; | ||
450 | } | ||
451 | |||
360 | /* | 452 | /* |
361 | * SSI mod common functions | 453 | * SSI mod common functions |
362 | */ | 454 | */ |
@@ -370,6 +462,8 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
370 | if (!rsnd_ssi_is_run_mods(mod, io)) | 462 | if (!rsnd_ssi_is_run_mods(mod, io)) |
371 | return 0; | 463 | return 0; |
372 | 464 | ||
465 | rsnd_ssi_pointer_init(mod, io); | ||
466 | |||
373 | ssi->usrcnt++; | 467 | ssi->usrcnt++; |
374 | 468 | ||
375 | rsnd_mod_power_on(mod); | 469 | rsnd_mod_power_on(mod); |
@@ -549,7 +643,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
549 | if (!is_dma && (status & DIRQ)) { | 643 | if (!is_dma && (status & DIRQ)) { |
550 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 644 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
551 | u32 *buf = (u32 *)(runtime->dma_area + | 645 | u32 *buf = (u32 *)(runtime->dma_area + |
552 | rsnd_dai_pointer_offset(io, 0)); | 646 | rsnd_ssi_pointer_offset(mod, io, 0)); |
553 | int shift = 0; | 647 | int shift = 0; |
554 | 648 | ||
555 | switch (runtime->sample_bits) { | 649 | switch (runtime->sample_bits) { |
@@ -568,7 +662,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
568 | else | 662 | else |
569 | *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); | 663 | *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); |
570 | 664 | ||
571 | elapsed = rsnd_dai_pointer_update(io, sizeof(*buf)); | 665 | elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf)); |
572 | } | 666 | } |
573 | 667 | ||
574 | /* DMA only */ | 668 | /* DMA only */ |
@@ -675,6 +769,18 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, | |||
675 | return ret; | 769 | return ret; |
676 | } | 770 | } |
677 | 771 | ||
772 | static int rsnd_ssi_pointer(struct rsnd_mod *mod, | ||
773 | struct rsnd_dai_stream *io, | ||
774 | snd_pcm_uframes_t *pointer) | ||
775 | { | ||
776 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
777 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
778 | |||
779 | *pointer = bytes_to_frames(runtime, ssi->byte_pos); | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
678 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 784 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
679 | .name = SSI_NAME, | 785 | .name = SSI_NAME, |
680 | .probe = rsnd_ssi_common_probe, | 786 | .probe = rsnd_ssi_common_probe, |
@@ -683,6 +789,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | |||
683 | .start = rsnd_ssi_start, | 789 | .start = rsnd_ssi_start, |
684 | .stop = rsnd_ssi_stop, | 790 | .stop = rsnd_ssi_stop, |
685 | .irq = rsnd_ssi_irq, | 791 | .irq = rsnd_ssi_irq, |
792 | .pointer= rsnd_ssi_pointer, | ||
686 | .pcm_new = rsnd_ssi_pcm_new, | 793 | .pcm_new = rsnd_ssi_pcm_new, |
687 | .hw_params = rsnd_ssi_hw_params, | 794 | .hw_params = rsnd_ssi_hw_params, |
688 | }; | 795 | }; |
@@ -787,13 +894,6 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) | |||
787 | 894 | ||
788 | 895 | ||
789 | /* | 896 | /* |
790 | * Non SSI | ||
791 | */ | ||
792 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { | ||
793 | .name = SSI_NAME, | ||
794 | }; | ||
795 | |||
796 | /* | ||
797 | * ssi mod function | 897 | * ssi mod function |
798 | */ | 898 | */ |
799 | static void rsnd_ssi_connect(struct rsnd_mod *mod, | 899 | static void rsnd_ssi_connect(struct rsnd_mod *mod, |
@@ -814,7 +914,8 @@ static void rsnd_ssi_connect(struct rsnd_mod *mod, | |||
814 | type = types[i]; | 914 | type = types[i]; |
815 | if (!rsnd_io_to_mod(io, type)) { | 915 | if (!rsnd_io_to_mod(io, type)) { |
816 | rsnd_dai_connect(mod, io, type); | 916 | rsnd_dai_connect(mod, io, type); |
817 | rsnd_set_slot(rdai, 2 * (i + 1), (i + 1)); | 917 | rsnd_rdai_channels_set(rdai, (i + 1) * 2); |
918 | rsnd_rdai_ssi_lane_set(rdai, (i + 1)); | ||
818 | return; | 919 | return; |
819 | } | 920 | } |
820 | } | 921 | } |
@@ -847,6 +948,47 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, | |||
847 | of_node_put(node); | 948 | of_node_put(node); |
848 | } | 949 | } |
849 | 950 | ||
951 | static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, | ||
952 | struct rsnd_dai_stream *io, | ||
953 | struct device_node *remote_ep) | ||
954 | { | ||
955 | struct device *dev = rsnd_priv_to_dev(priv); | ||
956 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); | ||
957 | struct rsnd_ssi *ssi; | ||
958 | |||
959 | if (!mod) | ||
960 | return; | ||
961 | |||
962 | ssi = rsnd_mod_to_ssi(mod); | ||
963 | |||
964 | if (strstr(remote_ep->full_name, "hdmi0")) { | ||
965 | ssi->flags |= RSND_SSI_HDMI0; | ||
966 | dev_dbg(dev, "%s[%d] connected to HDMI0\n", | ||
967 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
968 | } | ||
969 | |||
970 | if (strstr(remote_ep->full_name, "hdmi1")) { | ||
971 | ssi->flags |= RSND_SSI_HDMI1; | ||
972 | dev_dbg(dev, "%s[%d] connected to HDMI1\n", | ||
973 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
974 | } | ||
975 | } | ||
976 | |||
977 | void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, | ||
978 | struct device_node *endpoint, | ||
979 | int dai_i) | ||
980 | { | ||
981 | struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); | ||
982 | struct device_node *remote_ep; | ||
983 | |||
984 | remote_ep = of_graph_get_remote_endpoint(endpoint); | ||
985 | if (!remote_ep) | ||
986 | return; | ||
987 | |||
988 | __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep); | ||
989 | __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep); | ||
990 | } | ||
991 | |||
850 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | 992 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) |
851 | { | 993 | { |
852 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) | 994 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) |
@@ -952,7 +1094,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) | |||
952 | goto rsnd_ssi_probe_done; | 1094 | goto rsnd_ssi_probe_done; |
953 | } | 1095 | } |
954 | 1096 | ||
955 | ops = &rsnd_ssi_non_ops; | ||
956 | if (of_property_read_bool(np, "pio-transfer")) | 1097 | if (of_property_read_bool(np, "pio-transfer")) |
957 | ops = &rsnd_ssi_pio_ops; | 1098 | ops = &rsnd_ssi_pio_ops; |
958 | else | 1099 | 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 180bfbfe833d..921622a01944 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> |
@@ -3992,11 +3993,15 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
3992 | prefix = ""; | 3993 | prefix = ""; |
3993 | 3994 | ||
3994 | /* | 3995 | /* |
3995 | * check "[prefix]format = xxx" | 3996 | * check "dai-format = xxx" |
3997 | * or "[prefix]format = xxx" | ||
3996 | * SND_SOC_DAIFMT_FORMAT_MASK area | 3998 | * SND_SOC_DAIFMT_FORMAT_MASK area |
3997 | */ | 3999 | */ |
3998 | snprintf(prop, sizeof(prop), "%sformat", prefix); | 4000 | ret = of_property_read_string(np, "dai-format", &str); |
3999 | ret = of_property_read_string(np, prop, &str); | 4001 | if (ret < 0) { |
4002 | snprintf(prop, sizeof(prop), "%sformat", prefix); | ||
4003 | ret = of_property_read_string(np, prop, &str); | ||
4004 | } | ||
4000 | if (ret == 0) { | 4005 | if (ret == 0) { |
4001 | for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { | 4006 | for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { |
4002 | if (strcmp(str, of_fmt_table[i].name) == 0) { | 4007 | if (strcmp(str, of_fmt_table[i].name) == 0) { |
@@ -4076,6 +4081,42 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
4076 | } | 4081 | } |
4077 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); | 4082 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); |
4078 | 4083 | ||
4084 | int snd_soc_get_dai_id(struct device_node *ep) | ||
4085 | { | ||
4086 | struct snd_soc_component *pos; | ||
4087 | struct device_node *node; | ||
4088 | int ret; | ||
4089 | |||
4090 | node = of_graph_get_port_parent(ep); | ||
4091 | |||
4092 | /* | ||
4093 | * For example HDMI case, HDMI has video/sound port, | ||
4094 | * but ALSA SoC needs sound port number only. | ||
4095 | * Thus counting HDMI DT port/endpoint doesn't work. | ||
4096 | * Then, it should have .of_xlate_dai_id | ||
4097 | */ | ||
4098 | ret = -ENOTSUPP; | ||
4099 | mutex_lock(&client_mutex); | ||
4100 | list_for_each_entry(pos, &component_list, list) { | ||
4101 | struct device_node *component_of_node = pos->dev->of_node; | ||
4102 | |||
4103 | if (!component_of_node && pos->dev->parent) | ||
4104 | component_of_node = pos->dev->parent->of_node; | ||
4105 | |||
4106 | if (component_of_node != node) | ||
4107 | continue; | ||
4108 | |||
4109 | if (pos->driver->of_xlate_dai_id) | ||
4110 | ret = pos->driver->of_xlate_dai_id(pos, ep); | ||
4111 | |||
4112 | break; | ||
4113 | } | ||
4114 | mutex_unlock(&client_mutex); | ||
4115 | |||
4116 | return ret; | ||
4117 | } | ||
4118 | EXPORT_SYMBOL_GPL(snd_soc_get_dai_id); | ||
4119 | |||
4079 | int snd_soc_get_dai_name(struct of_phandle_args *args, | 4120 | int snd_soc_get_dai_name(struct of_phandle_args *args, |
4080 | const char **dai_name) | 4121 | const char **dai_name) |
4081 | { | 4122 | { |