summaryrefslogtreecommitdiffstats
path: root/sound/soc/generic/audio-graph-card2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/generic/audio-graph-card2.c')
-rw-r--r--sound/soc/generic/audio-graph-card2.c206
1 files changed, 119 insertions, 87 deletions
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 81e84095107e..4ad3d1b0714f 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -236,6 +236,18 @@ enum graph_type {
#define port_to_endpoint(port) of_get_child_by_name(port, "endpoint")
+#define ep_to_port(ep) of_get_parent(ep)
+static struct device_node *port_to_ports(struct device_node *port)
+{
+ struct device_node *ports = of_get_parent(port);
+
+ if (!of_node_name_eq(ports, "ports")) {
+ of_node_put(ports);
+ return NULL;
+ }
+ return ports;
+}
+
static enum graph_type __graph_get_type(struct device_node *lnk)
{
struct device_node *np, *parent_np;
@@ -320,7 +332,7 @@ static int graph_lnk_is_multi(struct device_node *lnk)
static struct device_node *graph_get_next_multi_ep(struct device_node **port)
{
- struct device_node *ports = of_get_parent(*port);
+ struct device_node *ports = port_to_ports(*port);
struct device_node *ep = NULL;
struct device_node *rep = NULL;
@@ -365,12 +377,11 @@ static const struct snd_soc_ops graph_ops = {
static void graph_parse_convert(struct device_node *ep,
struct simple_dai_props *props)
{
- struct device_node *port = of_get_parent(ep);
- struct device_node *ports = of_get_parent(port);
+ struct device_node *port = ep_to_port(ep);
+ struct device_node *ports = port_to_ports(port);
struct simple_util_data *adata = &props->adata;
- if (of_node_name_eq(ports, "ports"))
- simple_util_parse_convert(ports, NULL, adata);
+ simple_util_parse_convert(ports, NULL, adata);
simple_util_parse_convert(port, NULL, adata);
simple_util_parse_convert(ep, NULL, adata);
@@ -378,21 +389,6 @@ static void graph_parse_convert(struct device_node *ep,
of_node_put(ports);
}
-static void graph_parse_mclk_fs(struct device_node *ep,
- struct simple_dai_props *props)
-{
- struct device_node *port = of_get_parent(ep);
- struct device_node *ports = of_get_parent(port);
-
- if (of_node_name_eq(ports, "ports"))
- of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
- of_property_read_u32(port, "mclk-fs", &props->mclk_fs);
- of_property_read_u32(ep, "mclk-fs", &props->mclk_fs);
-
- of_node_put(port);
- of_node_put(ports);
-}
-
static int __graph_parse_node(struct simple_util_priv *priv,
enum graph_type gtype,
struct device_node *ep,
@@ -414,8 +410,6 @@ static int __graph_parse_node(struct simple_util_priv *priv,
dai = simple_props_to_dai_codec(dai_props, idx);
}
- graph_parse_mclk_fs(ep, dai_props);
-
ret = graph_util_parse_dai(dev, ep, dlc, &is_single_links);
if (ret < 0)
return ret;
@@ -481,11 +475,10 @@ static int __graph_parse_node(struct simple_util_priv *priv,
if (!is_cpu && gtype == GRAPH_DPCM) {
struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, idx);
- struct device_node *rport = of_get_parent(ep);
- struct device_node *rports = of_get_parent(rport);
+ struct device_node *rport = ep_to_port(ep);
+ struct device_node *rports = port_to_ports(rport);
- if (of_node_name_eq(rports, "ports"))
- snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
+ snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
snd_soc_of_parse_node_prefix(rport, cconf, codecs->of_node, "prefix");
of_node_put(rport);
@@ -539,11 +532,11 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
*/
struct device_node *mcpu_ep = port_to_endpoint(mcpu_port);
struct device_node *mcpu_ep_n = mcpu_ep;
- struct device_node *mcpu_port_top = of_get_next_child(of_get_parent(mcpu_port), NULL);
+ struct device_node *mcpu_port_top = of_get_next_child(port_to_ports(mcpu_port), NULL);
struct device_node *mcpu_ep_top = port_to_endpoint(mcpu_port_top);
struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top);
- struct device_node *mcodec_port_top = of_get_parent(mcodec_ep_top);
- struct device_node *mcodec_ports = of_get_parent(mcodec_port_top);
+ struct device_node *mcodec_port_top = ep_to_port(mcodec_ep_top);
+ struct device_node *mcodec_ports = port_to_ports(mcodec_port_top);
int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
int ret = -EINVAL;
@@ -566,9 +559,9 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
}
mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n);
- mcodec_port = of_get_parent(mcodec_ep_n);
+ mcodec_port = ep_to_port(mcodec_ep_n);
- if (mcodec_ports != of_get_parent(mcodec_port))
+ if (mcodec_ports != port_to_ports(mcodec_port))
goto mcpu_err;
codec_idx = 0;
@@ -705,6 +698,9 @@ static void graph_parse_daifmt(struct device_node *node,
{
unsigned int fmt;
+ if (!node)
+ return;
+
/*
* see also above "daifmt" explanation
* and samples.
@@ -751,43 +747,74 @@ static void graph_parse_daifmt(struct device_node *node,
}
static void graph_link_init(struct simple_util_priv *priv,
- struct device_node *port,
+ struct device_node *lnk,
+ struct device_node *port_cpu,
+ struct device_node *port_codec,
struct link_info *li,
int is_cpu_node)
{
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
- struct device_node *ep;
- struct device_node *ports;
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
+ struct device_node *ep_cpu, *ep_codec;
+ struct device_node *ports_cpu, *ports_codec;
unsigned int daifmt = 0, daiclk = 0;
bool playback_only = 0, capture_only = 0;
+ enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
+ enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT;
unsigned int bit_frame = 0;
- if (graph_lnk_is_multi(port)) {
- of_node_get(port);
- ep = graph_get_next_multi_ep(&port);
- port = of_get_parent(ep);
+ of_node_get(port_cpu);
+ if (graph_lnk_is_multi(port_cpu)) {
+ ep_cpu = graph_get_next_multi_ep(&port_cpu);
+ of_node_put(port_cpu);
+ port_cpu = ep_to_port(ep_cpu);
} else {
- ep = port_to_endpoint(port);
+ ep_cpu = port_to_endpoint(port_cpu);
}
+ ports_cpu = port_to_ports(port_cpu);
- ports = of_get_parent(port);
-
- /*
- * ports {
- * (A)
- * port {
- * (B)
- * endpoint {
- * (C)
- * };
- * };
- * };
- * };
- */
- graph_parse_daifmt(ep, &daifmt, &bit_frame); /* (C) */
- graph_parse_daifmt(port, &daifmt, &bit_frame); /* (B) */
- if (of_node_name_eq(ports, "ports"))
- graph_parse_daifmt(ports, &daifmt, &bit_frame); /* (A) */
+ of_node_get(port_codec);
+ if (graph_lnk_is_multi(port_codec)) {
+ ep_codec = graph_get_next_multi_ep(&port_codec);
+ of_node_put(port_cpu);
+ port_codec = ep_to_port(ep_codec);
+ } else {
+ ep_codec = port_to_endpoint(port_codec);
+ }
+ ports_codec = port_to_ports(port_codec);
+
+
+ graph_parse_daifmt(ep_cpu, &daifmt, &bit_frame);
+ graph_parse_daifmt(ep_codec, &daifmt, &bit_frame);
+ graph_parse_daifmt(port_cpu, &daifmt, &bit_frame);
+ graph_parse_daifmt(port_codec, &daifmt, &bit_frame);
+ graph_parse_daifmt(ports_cpu, &daifmt, &bit_frame);
+ graph_parse_daifmt(ports_codec, &daifmt, &bit_frame);
+ graph_parse_daifmt(lnk, &daifmt, &bit_frame);
+
+ graph_util_parse_link_direction(lnk, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ports_codec, &playback_only, &capture_only);
+ graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(port_codec, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only);
+
+ of_property_read_u32(lnk, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports_codec, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port_codec, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs);
+
+ graph_util_parse_trigger_order(priv, lnk, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop);
/*
* convert bit_frame
@@ -798,16 +825,24 @@ static void graph_link_init(struct simple_util_priv *priv,
if (is_cpu_node)
daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk);
- graph_util_parse_link_direction(port, &playback_only, &capture_only);
+ dai_link->playback_only = playback_only;
+ dai_link->capture_only = capture_only;
- dai_link->playback_only = playback_only;
- dai_link->capture_only = capture_only;
+ dai_link->trigger_start = trigger_start;
+ dai_link->trigger_stop = trigger_stop;
dai_link->dai_fmt = daifmt | daiclk;
dai_link->init = simple_util_dai_init;
dai_link->ops = &graph_ops;
if (priv->ops)
dai_link->ops = priv->ops;
+
+ of_node_put(ports_cpu);
+ of_node_put(ports_codec);
+ of_node_put(port_cpu);
+ of_node_put(port_codec);
+ of_node_put(ep_cpu);
+ of_node_put(ep_codec);
}
int audio_graph2_link_normal(struct simple_util_priv *priv,
@@ -835,7 +870,7 @@ int audio_graph2_link_normal(struct simple_util_priv *priv,
if (ret < 0)
goto err;
- graph_link_init(priv, cpu_port, li, 1);
+ graph_link_init(priv, lnk, cpu_port, codec_port, li, 1);
err:
of_node_put(codec_port);
of_node_put(cpu_ep);
@@ -850,13 +885,16 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
{
struct device_node *ep = port_to_endpoint(lnk);
struct device_node *rep = of_graph_get_remote_endpoint(ep);
- struct device_node *rport = of_graph_get_remote_port(ep);
+ struct device_node *cpu_port = NULL;
+ struct device_node *codec_port = NULL;
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
int is_cpu = graph_util_is_ports0(lnk);
int ret;
if (is_cpu) {
+ cpu_port = of_graph_get_remote_port(ep); /* rport */
+
/*
* dpcm {
* // Front-End
@@ -884,10 +922,13 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
- ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 1);
+ ret = graph_parse_node(priv, GRAPH_DPCM, cpu_port, li, 1);
if (ret)
goto err;
+
} else {
+ codec_port = of_graph_get_remote_port(ep); /* rport */
+
/*
* dpcm {
* // Front-End
@@ -917,7 +958,7 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
- ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 0);
+ ret = graph_parse_node(priv, GRAPH_DPCM, codec_port, li, 0);
if (ret < 0)
goto err;
}
@@ -925,13 +966,12 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
graph_parse_convert(ep, dai_props); /* at node of <dpcm> */
graph_parse_convert(rep, dai_props); /* at node of <CPU/Codec> */
- snd_soc_dai_link_set_capabilities(dai_link);
-
- graph_link_init(priv, rport, li, is_cpu);
+ graph_link_init(priv, lnk, cpu_port, codec_port, li, is_cpu);
err:
of_node_put(ep);
of_node_put(rep);
- of_node_put(rport);
+ of_node_put(cpu_port);
+ of_node_put(codec_port);
return ret;
}
@@ -966,7 +1006,7 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
*/
of_node_get(lnk);
port0 = lnk;
- ports = of_get_parent(port0);
+ ports = port_to_ports(port0);
port1 = of_get_next_child(ports, lnk);
/*
@@ -1019,7 +1059,7 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
if (ret < 0)
goto err2;
- graph_link_init(priv, codec0_port, li, 1);
+ graph_link_init(priv, lnk, codec0_port, codec1_port, li, 1);
err2:
of_node_put(ep0);
of_node_put(ep1);
@@ -1098,22 +1138,13 @@ static int graph_counter(struct device_node *lnk)
* ignore first lnk part
*/
if (graph_lnk_is_multi(lnk)) {
- struct device_node *ports = of_get_parent(lnk);
- struct device_node *port = NULL;
- int cnt = 0;
+ struct device_node *ports = port_to_ports(lnk);
/*
* CPU/Codec = N:M case has many endpoints.
* We can't use of_graph_get_endpoint_count() here
*/
- while(1) {
- port = of_get_next_child(ports, port);
- if (!port)
- break;
- cnt++;
- }
-
- return cnt - 1;
+ return of_get_child_count(ports) - 1;
}
/*
* Single CPU / Codec
@@ -1195,7 +1226,7 @@ static int graph_count_c2c(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
- struct device_node *ports = of_get_parent(lnk);
+ struct device_node *ports = port_to_ports(lnk);
struct device_node *port0 = lnk;
struct device_node *port1 = of_get_next_child(ports, of_node_get(lnk));
struct device_node *ep0 = port_to_endpoint(port0);
@@ -1308,10 +1339,9 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
struct graph2_custom_hooks *hooks)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct link_info *li;
int ret;
- li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+ struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
if (!li)
return -ENOMEM;
@@ -1369,10 +1399,12 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
simple_util_debug_info(priv);
+ ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
+ if (ret < 0)
+ goto err;
+
ret = devm_snd_soc_register_card(dev, card);
err:
- devm_kfree(dev, li);
-
if (ret < 0)
dev_err_probe(dev, ret, "parse error\n");
@@ -1406,7 +1438,7 @@ static struct platform_driver graph_card = {
.of_match_table = graph_of_match,
},
.probe = graph_probe,
- .remove_new = simple_util_remove,
+ .remove = simple_util_remove,
};
module_platform_driver(graph_card);