diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/audio-graph-card.txt | 124 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/sound/simple-scu-card.txt | 65 | ||||
-rw-r--r-- | drivers/of/base.c | 62 | ||||
-rw-r--r-- | include/linux/of_graph.h | 21 | ||||
-rw-r--r-- | include/sound/simple_card_utils.h | 10 | ||||
-rw-r--r-- | include/sound/soc.h | 3 | ||||
-rw-r--r-- | sound/soc/generic/Kconfig | 8 | ||||
-rw-r--r-- | sound/soc/generic/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/generic/audio-graph-card.c | 310 | ||||
-rw-r--r-- | sound/soc/generic/simple-card-utils.c | 82 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 47 |
11 files changed, 675 insertions, 59 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/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt index d6fe47ed09af..e894cef1d314 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,19 +32,11 @@ 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 Covert |
56 | 42 | ||
@@ -59,11 +45,10 @@ sound { | |||
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..efab584af11b 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h | |||
@@ -60,6 +60,16 @@ int asoc_simple_card_parse_dai(struct device_node *node, | |||
60 | const char *cells_name, | 60 | const char *cells_name, |
61 | int *is_single_links); | 61 | int *is_single_links); |
62 | 62 | ||
63 | #define asoc_simple_card_parse_graph_cpu(ep, dai_link) \ | ||
64 | asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \ | ||
65 | &dai_link->cpu_dai_name) | ||
66 | #define asoc_simple_card_parse_graph_codec(ep, dai_link) \ | ||
67 | asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \ | ||
68 | &dai_link->codec_dai_name) | ||
69 | int asoc_simple_card_parse_graph_dai(struct device_node *ep, | ||
70 | struct device_node **endpoint_np, | ||
71 | const char **dai_name); | ||
72 | |||
63 | int asoc_simple_card_init_dai(struct snd_soc_dai *dai, | 73 | int asoc_simple_card_init_dai(struct snd_soc_dai *dai, |
64 | struct asoc_simple_dai *simple_dai); | 74 | struct asoc_simple_dai *simple_dai); |
65 | 75 | ||
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..121a48e8bb7d 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig | |||
@@ -14,3 +14,11 @@ 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. | ||
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index ee750f3023ba..670068f257b9 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile | |||
@@ -1,7 +1,9 @@ | |||
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 | ||
4 | 5 | ||
5 | obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o | 6 | obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o |
6 | obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o | 7 | obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o |
7 | obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o | 8 | obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o |
9 | obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-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..93c167a91d2d --- /dev/null +++ b/sound/soc/generic/audio-graph-card.c | |||
@@ -0,0 +1,310 @@ | |||
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 | dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); | ||
173 | dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt); | ||
174 | dev_dbg(dev, "\tcpu : %s / %d\n", | ||
175 | dai_link->cpu_dai_name, | ||
176 | cpu_dai->sysclk); | ||
177 | dev_dbg(dev, "\tcodec : %s / %d\n", | ||
178 | dai_link->codec_dai_name, | ||
179 | codec_dai->sysclk); | ||
180 | |||
181 | asoc_simple_card_canonicalize_cpu(dai_link, | ||
182 | card->num_links == 1); | ||
183 | |||
184 | dai_link_of_err: | ||
185 | of_node_put(cpu_ep); | ||
186 | of_node_put(rcpu_ep); | ||
187 | of_node_put(codec_ep); | ||
188 | |||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static int asoc_graph_card_parse_of(struct graph_card_data *priv) | ||
193 | { | ||
194 | struct of_phandle_iterator it; | ||
195 | struct device *dev = graph_priv_to_dev(priv); | ||
196 | struct snd_soc_card *card = graph_priv_to_card(priv); | ||
197 | struct device_node *node = dev->of_node; | ||
198 | int rc, idx = 0; | ||
199 | int ret; | ||
200 | |||
201 | /* | ||
202 | * we need to consider "widgets", "routing", "mclk-fs" around here | ||
203 | * see simple-card | ||
204 | */ | ||
205 | |||
206 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { | ||
207 | ret = asoc_graph_card_dai_link_of(it.node, priv, idx++); | ||
208 | of_node_put(it.node); | ||
209 | if (ret < 0) | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | return asoc_simple_card_parse_card_name(card, NULL); | ||
214 | } | ||
215 | |||
216 | static int asoc_graph_get_dais_count(struct device *dev) | ||
217 | { | ||
218 | struct of_phandle_iterator it; | ||
219 | struct device_node *node = dev->of_node; | ||
220 | int count = 0; | ||
221 | int rc; | ||
222 | |||
223 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { | ||
224 | count++; | ||
225 | of_node_put(it.node); | ||
226 | } | ||
227 | |||
228 | return count; | ||
229 | } | ||
230 | |||
231 | static int asoc_graph_card_probe(struct platform_device *pdev) | ||
232 | { | ||
233 | struct graph_card_data *priv; | ||
234 | struct snd_soc_dai_link *dai_link; | ||
235 | struct graph_dai_props *dai_props; | ||
236 | struct device *dev = &pdev->dev; | ||
237 | struct snd_soc_card *card; | ||
238 | int num, ret; | ||
239 | |||
240 | /* Allocate the private data and the DAI link array */ | ||
241 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
242 | if (!priv) | ||
243 | return -ENOMEM; | ||
244 | |||
245 | num = asoc_graph_get_dais_count(dev); | ||
246 | if (num == 0) | ||
247 | return -EINVAL; | ||
248 | |||
249 | dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); | ||
250 | dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); | ||
251 | if (!dai_props || !dai_link) | ||
252 | return -ENOMEM; | ||
253 | |||
254 | priv->dai_props = dai_props; | ||
255 | priv->dai_link = dai_link; | ||
256 | |||
257 | /* Init snd_soc_card */ | ||
258 | card = graph_priv_to_card(priv); | ||
259 | card->owner = THIS_MODULE; | ||
260 | card->dev = dev; | ||
261 | card->dai_link = dai_link; | ||
262 | card->num_links = num; | ||
263 | |||
264 | ret = asoc_graph_card_parse_of(priv); | ||
265 | if (ret < 0) { | ||
266 | if (ret != -EPROBE_DEFER) | ||
267 | dev_err(dev, "parse error %d\n", ret); | ||
268 | goto err; | ||
269 | } | ||
270 | |||
271 | snd_soc_card_set_drvdata(card, priv); | ||
272 | |||
273 | ret = devm_snd_soc_register_card(dev, card); | ||
274 | if (ret < 0) | ||
275 | goto err; | ||
276 | |||
277 | return 0; | ||
278 | err: | ||
279 | asoc_simple_card_clean_reference(card); | ||
280 | |||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static int asoc_graph_card_remove(struct platform_device *pdev) | ||
285 | { | ||
286 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
287 | |||
288 | return asoc_simple_card_clean_reference(card); | ||
289 | } | ||
290 | |||
291 | static const struct of_device_id asoc_graph_of_match[] = { | ||
292 | { .compatible = "audio-graph-card", }, | ||
293 | {}, | ||
294 | }; | ||
295 | MODULE_DEVICE_TABLE(of, asoc_graph_of_match); | ||
296 | |||
297 | static struct platform_driver asoc_graph_card = { | ||
298 | .driver = { | ||
299 | .name = "asoc-audio-graph-card", | ||
300 | .of_match_table = asoc_graph_of_match, | ||
301 | }, | ||
302 | .probe = asoc_graph_card_probe, | ||
303 | .remove = asoc_graph_card_remove, | ||
304 | }; | ||
305 | module_platform_driver(asoc_graph_card); | ||
306 | |||
307 | MODULE_ALIAS("platform:asoc-audio-graph-card"); | ||
308 | MODULE_LICENSE("GPL v2"); | ||
309 | MODULE_DESCRIPTION("ASoC Audio Graph Sound Card"); | ||
310 | 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..fe726e83d0bd 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, |
@@ -81,15 +82,21 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name); | |||
81 | int asoc_simple_card_parse_card_name(struct snd_soc_card *card, | 82 | int asoc_simple_card_parse_card_name(struct snd_soc_card *card, |
82 | char *prefix) | 83 | char *prefix) |
83 | { | 84 | { |
84 | char prop[128]; | ||
85 | int ret; | 85 | int ret; |
86 | 86 | ||
87 | snprintf(prop, sizeof(prop), "%sname", prefix); | 87 | if (!prefix) |
88 | prefix = ""; | ||
88 | 89 | ||
89 | /* Parse the card name from DT */ | 90 | /* Parse the card name from DT */ |
90 | ret = snd_soc_of_parse_card_name(card, prop); | 91 | ret = snd_soc_of_parse_card_name(card, "label"); |
91 | if (ret < 0) | 92 | if (ret < 0) { |
92 | return ret; | 93 | char prop[128]; |
94 | |||
95 | snprintf(prop, sizeof(prop), "%sname", prefix); | ||
96 | ret = snd_soc_of_parse_card_name(card, prop); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | } | ||
93 | 100 | ||
94 | if (!card->name && card->dai_link) | 101 | if (!card->name && card->dai_link) |
95 | card->name = card->dai_link->name; | 102 | card->name = card->dai_link->name; |
@@ -165,6 +172,71 @@ int asoc_simple_card_parse_dai(struct device_node *node, | |||
165 | } | 172 | } |
166 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); | 173 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); |
167 | 174 | ||
175 | static int asoc_simple_card_get_dai_id(struct device_node *ep) | ||
176 | { | ||
177 | struct device_node *node; | ||
178 | struct device_node *endpoint; | ||
179 | int i, id; | ||
180 | int ret; | ||
181 | |||
182 | ret = snd_soc_get_dai_id(ep); | ||
183 | if (ret != -ENOTSUPP) | ||
184 | return ret; | ||
185 | |||
186 | node = of_graph_get_port_parent(ep); | ||
187 | |||
188 | /* | ||
189 | * Non HDMI sound case, counting port/endpoint on its DT | ||
190 | * is enough. Let's count it. | ||
191 | */ | ||
192 | i = 0; | ||
193 | id = -1; | ||
194 | for_each_endpoint_of_node(node, endpoint) { | ||
195 | if (endpoint == ep) | ||
196 | id = i; | ||
197 | i++; | ||
198 | } | ||
199 | if (id < 0) | ||
200 | return -ENODEV; | ||
201 | |||
202 | return id; | ||
203 | } | ||
204 | |||
205 | int asoc_simple_card_parse_graph_dai(struct device_node *ep, | ||
206 | struct device_node **dai_of_node, | ||
207 | const char **dai_name) | ||
208 | { | ||
209 | struct device_node *node; | ||
210 | struct of_phandle_args args; | ||
211 | int ret; | ||
212 | |||
213 | if (!ep) | ||
214 | return 0; | ||
215 | if (!dai_name) | ||
216 | return 0; | ||
217 | |||
218 | /* | ||
219 | * of_graph_get_port_parent() will call | ||
220 | * of_node_put(). So, call of_node_get() here | ||
221 | */ | ||
222 | of_node_get(ep); | ||
223 | node = of_graph_get_port_parent(ep); | ||
224 | |||
225 | /* Get dai->name */ | ||
226 | args.np = node; | ||
227 | args.args[0] = asoc_simple_card_get_dai_id(ep); | ||
228 | args.args_count = (of_graph_get_endpoint_count(node) > 1); | ||
229 | |||
230 | ret = snd_soc_get_dai_name(&args, dai_name); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | |||
234 | *dai_of_node = node; | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai); | ||
239 | |||
168 | int asoc_simple_card_init_dai(struct snd_soc_dai *dai, | 240 | int asoc_simple_card_init_dai(struct snd_soc_dai *dai, |
169 | struct asoc_simple_dai *simple_dai) | 241 | struct asoc_simple_dai *simple_dai) |
170 | { | 242 | { |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index aae099c0e502..9ba183781017 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/ctype.h> | 34 | #include <linux/ctype.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/of.h> | 36 | #include <linux/of.h> |
37 | #include <linux/of_graph.h> | ||
37 | #include <linux/dmi.h> | 38 | #include <linux/dmi.h> |
38 | #include <sound/core.h> | 39 | #include <sound/core.h> |
39 | #include <sound/jack.h> | 40 | #include <sound/jack.h> |
@@ -3960,11 +3961,15 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
3960 | prefix = ""; | 3961 | prefix = ""; |
3961 | 3962 | ||
3962 | /* | 3963 | /* |
3963 | * check "[prefix]format = xxx" | 3964 | * check "dai-format = xxx" |
3965 | * or "[prefix]format = xxx" | ||
3964 | * SND_SOC_DAIFMT_FORMAT_MASK area | 3966 | * SND_SOC_DAIFMT_FORMAT_MASK area |
3965 | */ | 3967 | */ |
3966 | snprintf(prop, sizeof(prop), "%sformat", prefix); | 3968 | ret = of_property_read_string(np, "dai-format", &str); |
3967 | ret = of_property_read_string(np, prop, &str); | 3969 | if (ret < 0) { |
3970 | snprintf(prop, sizeof(prop), "%sformat", prefix); | ||
3971 | ret = of_property_read_string(np, prop, &str); | ||
3972 | } | ||
3968 | if (ret == 0) { | 3973 | if (ret == 0) { |
3969 | for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { | 3974 | for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { |
3970 | if (strcmp(str, of_fmt_table[i].name) == 0) { | 3975 | if (strcmp(str, of_fmt_table[i].name) == 0) { |
@@ -4044,6 +4049,42 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
4044 | } | 4049 | } |
4045 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); | 4050 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); |
4046 | 4051 | ||
4052 | int snd_soc_get_dai_id(struct device_node *ep) | ||
4053 | { | ||
4054 | struct snd_soc_component *pos; | ||
4055 | struct device_node *node; | ||
4056 | int ret; | ||
4057 | |||
4058 | node = of_graph_get_port_parent(ep); | ||
4059 | |||
4060 | /* | ||
4061 | * For example HDMI case, HDMI has video/sound port, | ||
4062 | * but ALSA SoC needs sound port number only. | ||
4063 | * Thus counting HDMI DT port/endpoint doesn't work. | ||
4064 | * Then, it should have .of_xlate_dai_id | ||
4065 | */ | ||
4066 | ret = -ENOTSUPP; | ||
4067 | mutex_lock(&client_mutex); | ||
4068 | list_for_each_entry(pos, &component_list, list) { | ||
4069 | struct device_node *component_of_node = pos->dev->of_node; | ||
4070 | |||
4071 | if (!component_of_node && pos->dev->parent) | ||
4072 | component_of_node = pos->dev->parent->of_node; | ||
4073 | |||
4074 | if (component_of_node != node) | ||
4075 | continue; | ||
4076 | |||
4077 | if (pos->driver->of_xlate_dai_id) | ||
4078 | ret = pos->driver->of_xlate_dai_id(pos, ep); | ||
4079 | |||
4080 | break; | ||
4081 | } | ||
4082 | mutex_unlock(&client_mutex); | ||
4083 | |||
4084 | return ret; | ||
4085 | } | ||
4086 | EXPORT_SYMBOL_GPL(snd_soc_get_dai_id); | ||
4087 | |||
4047 | int snd_soc_get_dai_name(struct of_phandle_args *args, | 4088 | int snd_soc_get_dai_name(struct of_phandle_args *args, |
4048 | const char **dai_name) | 4089 | const char **dai_name) |
4049 | { | 4090 | { |