summaryrefslogtreecommitdiffstats
path: root/sound/soc/generic/simple-card.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/generic/simple-card.c')
-rw-r--r--sound/soc/generic/simple-card.c80
1 files changed, 56 insertions, 24 deletions
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 5dd47691ba4..2ee8ed56bcf 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -20,7 +20,6 @@
struct simple_card_data {
struct snd_soc_card snd_card;
- unsigned int daifmt;
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
struct snd_soc_dai_link snd_link;
@@ -105,12 +104,12 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
/* get dai->name */
ret = snd_soc_of_get_dai_name(np, name);
if (ret < 0)
- goto parse_error;
+ return ret;
/* parse TDM slot */
ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
if (ret)
- goto parse_error;
+ return ret;
/*
* bitclock-inversion, frame-inversion
@@ -130,7 +129,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- goto parse_error;
+ return ret;
}
dai->sysclk = clk_get_rate(clk);
@@ -144,12 +143,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
dai->sysclk = clk_get_rate(clk);
}
- ret = 0;
-
-parse_error:
- of_node_put(node);
-
- return ret;
+ return 0;
}
static int asoc_simple_card_parse_of(struct device_node *node,
@@ -157,15 +151,18 @@ static int asoc_simple_card_parse_of(struct device_node *node,
struct device *dev)
{
struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
+ struct asoc_simple_dai *codec_dai = &priv->codec_dai;
+ struct asoc_simple_dai *cpu_dai = &priv->cpu_dai;
struct device_node *np;
char *name;
+ unsigned int daifmt;
int ret;
/* parsing the card name from DT */
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
/* get CPU/CODEC common format via simple-audio-card,format */
- priv->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
+ daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
/* off-codec widgets */
@@ -187,25 +184,35 @@ static int asoc_simple_card_parse_of(struct device_node *node,
/* CPU sub-node */
ret = -EINVAL;
np = of_get_child_by_name(node, "simple-audio-card,cpu");
- if (np)
- ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
- &priv->cpu_dai,
+ if (np) {
+ ret = asoc_simple_card_sub_parse_of(np, daifmt,
+ cpu_dai,
&dai_link->cpu_of_node,
&dai_link->cpu_dai_name);
+ of_node_put(np);
+ }
if (ret < 0)
return ret;
/* CODEC sub-node */
ret = -EINVAL;
np = of_get_child_by_name(node, "simple-audio-card,codec");
- if (np)
- ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
- &priv->codec_dai,
+ if (np) {
+ ret = asoc_simple_card_sub_parse_of(np, daifmt,
+ codec_dai,
&dai_link->codec_of_node,
&dai_link->codec_dai_name);
+ of_node_put(np);
+ }
if (ret < 0)
return ret;
+ /*
+ * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
+ * while the other bits should be identical unless buggy SW/HW design.
+ */
+ cpu_dai->fmt = codec_dai->fmt;
+
if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
return -EINVAL;
@@ -224,15 +231,15 @@ static int asoc_simple_card_parse_of(struct device_node *node,
dai_link->platform_of_node = dai_link->cpu_of_node;
dev_dbg(dev, "card-name : %s\n", name);
- dev_dbg(dev, "platform : %04x\n", priv->daifmt);
+ dev_dbg(dev, "platform : %04x\n", daifmt);
dev_dbg(dev, "cpu : %s / %04x / %d\n",
dai_link->cpu_dai_name,
- priv->cpu_dai.fmt,
- priv->cpu_dai.sysclk);
+ cpu_dai->fmt,
+ cpu_dai->sysclk);
dev_dbg(dev, "codec : %s / %04x / %d\n",
dai_link->codec_dai_name,
- priv->codec_dai.fmt,
- priv->codec_dai.sysclk);
+ codec_dai->fmt,
+ codec_dai->sysclk);
/*
* soc_bind_dai_link() will check cpu name
@@ -248,6 +255,27 @@ static int asoc_simple_card_parse_of(struct device_node *node,
return 0;
}
+/* update the reference count of the devices nodes at end of probe */
+static int asoc_simple_card_unref(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct snd_soc_dai_link *dai_link;
+ struct device_node *np;
+ int num_links;
+
+ for (num_links = 0, dai_link = card->dai_link;
+ num_links < card->num_links;
+ num_links++, dai_link++) {
+ np = (struct device_node *) dai_link->cpu_of_node;
+ if (np)
+ of_node_put(np);
+ np = (struct device_node *) dai_link->codec_of_node;
+ if (np)
+ of_node_put(np);
+ }
+ return 0;
+}
+
static int asoc_simple_card_probe(struct platform_device *pdev)
{
struct simple_card_data *priv;
@@ -275,7 +303,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "parse error %d\n", ret);
- return ret;
+ goto err;
}
} else {
struct asoc_simple_card_info *cinfo;
@@ -318,7 +346,11 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&priv->snd_card, priv);
- return devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+ ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+
+err:
+ asoc_simple_card_unref(pdev);
+ return ret;
}
static const struct of_device_id asoc_simple_of_match[] = {