Commit b3ca11ff authored by Jyri Sarha's avatar Jyri Sarha Committed by Mark Brown

ASoC: simple-card: Move dai-link level properties away from dai subnodes

The properties like format, bitclock-master, frame-master,
bitclock-inversion, and frame-inversion should be common to the dais
connected with a dai-link. For bitclock-master and frame-master
properties to be unambiguous they need to indicate the mastering dai
node with a phandle.
Signed-off-by: default avatarJyri Sarha <jsarha@ti.com>
Acked-by: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent 389cb834
Simple-Card: Simple-Card:
Simple-Card specifies audio DAI connection of SoC <-> codec. Simple-Card specifies audio DAI connections of SoC <-> codec.
Required properties: Required properties:
...@@ -10,26 +10,51 @@ Optional properties: ...@@ -10,26 +10,51 @@ Optional properties:
- simple-audio-card,name : User specified audio sound card name, one string - simple-audio-card,name : User specified audio sound card name, one string
property. property.
- simple-audio-card,format : CPU/CODEC common audio format.
"i2s", "right_j", "left_j" , "dsp_a"
"dsp_b", "ac97", "pdm", "msb", "lsb"
- simple-audio-card,widgets : Please refer to widgets.txt. - simple-audio-card,widgets : Please refer to widgets.txt.
- simple-audio-card,routing : A list of the connections between audio components. - simple-audio-card,routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's connection's sink, the second being the connection's
source. source.
- dai-tdm-slot-num : Please refer to tdm-slot.txt. Optional subnodes:
- dai-tdm-slot-width : Please refer to tdm-slot.txt.
- simple-audio-card,dai-link : Container for dai-link level
properties and the CPU and CODEC
sub-nodes. This container may be
omitted when the card has only one
DAI link. See the examples and the
section bellow.
Required subnodes: Dai-link subnode properties and subnodes:
- simple-audio-card,dai-link : container for the CPU and CODEC sub-nodes If dai-link subnode is omitted and the subnode properties are directly
This container may be omitted when the under "sound"-node the subnode property and subnode names have to be
card has only one DAI link. prefixed with "simple-audio-card,"-prefix.
See the examples.
- simple-audio-card,cpu : CPU sub-node Required dai-link subnodes:
- simple-audio-card,codec : CODEC sub-node
- cpu : CPU sub-node
- codec : CODEC sub-node
Optional dai-link subnode properties:
- format : CPU/CODEC common audio format.
"i2s", "right_j", "left_j" , "dsp_a"
"dsp_b", "ac97", "pdm", "msb", "lsb"
- frame-master : Indicates dai-link frame master.
phandle to a cpu or codec subnode.
- bitclock-master : Indicates dai-link bit clock master.
phandle to a cpu or codec subnode.
- bitclock-inversion : bool property. Add this if the
dai-link uses bit clock inversion.
- frame-inversion : bool property. Add this if the
dai-link uses frame clock inversion.
For backward compatibility the frame-master and bitclock-master
properties can be used as booleans in codec subnode to indicate if the
codec is the dai-link frame or bit clock master. In this case there
should be no dai-link node, the same properties should not be present
at sound-node level, and the bitclock-inversion and frame-inversion
properties should also be placed in the codec node if needed.
Required CPU/CODEC subnodes properties: Required CPU/CODEC subnodes properties:
...@@ -37,29 +62,21 @@ Required CPU/CODEC subnodes properties: ...@@ -37,29 +62,21 @@ Required CPU/CODEC subnodes properties:
Optional CPU/CODEC subnodes properties: Optional CPU/CODEC subnodes properties:
- format : CPU/CODEC specific audio format if needed. - dai-tdm-slot-num : Please refer to tdm-slot.txt.
see simple-audio-card,format - dai-tdm-slot-width : Please refer to tdm-slot.txt.
- frame-master : bool property. add this if subnode is frame master
- bitclock-master : bool property. add this if subnode is bitclock master
- bitclock-inversion : bool property. add this if subnode has clock inversion
- frame-inversion : bool property. add this if subnode has frame inversion
- clocks / system-clock-frequency : specify subnode's clock if needed. - clocks / system-clock-frequency : specify subnode's clock if needed.
it can be specified via "clocks" if system has it can be specified via "clocks" if system has
clock node (= common clock), or "system-clock-frequency" clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock) (if system doens't support common clock)
Note:
* For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
'frame-inversion', the simple card will use the settings of CODEC for both
CPU and CODEC sides as we need to keep the settings identical for both ends
of the link.
Example 1 - single DAI link: Example 1 - single DAI link:
sound { sound {
compatible = "simple-audio-card"; compatible = "simple-audio-card";
simple-audio-card,name = "VF610-Tower-Sound-Card"; simple-audio-card,name = "VF610-Tower-Sound-Card";
simple-audio-card,format = "left_j"; simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&dailink0_master>;
simple-audio-card,frame-master = <&dailink0_master>;
simple-audio-card,widgets = simple-audio-card,widgets =
"Microphone", "Microphone Jack", "Microphone", "Microphone Jack",
"Headphone", "Headphone Jack", "Headphone", "Headphone Jack",
...@@ -69,17 +86,12 @@ sound { ...@@ -69,17 +86,12 @@ sound {
"Headphone Jack", "HP_OUT", "Headphone Jack", "HP_OUT",
"External Speaker", "LINE_OUT"; "External Speaker", "LINE_OUT";
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <8>;
simple-audio-card,cpu { simple-audio-card,cpu {
sound-dai = <&sh_fsi2 0>; sound-dai = <&sh_fsi2 0>;
}; };
simple-audio-card,codec { dailink0_master: simple-audio-card,codec {
sound-dai = <&ak4648>; sound-dai = <&ak4648>;
bitclock-master;
frame-master;
clocks = <&osc>; clocks = <&osc>;
}; };
}; };
...@@ -105,31 +117,31 @@ Example 2 - many DAI links: ...@@ -105,31 +117,31 @@ Example 2 - many DAI links:
sound { sound {
compatible = "simple-audio-card"; compatible = "simple-audio-card";
simple-audio-card,name = "Cubox Audio"; simple-audio-card,name = "Cubox Audio";
simple-audio-card,format = "i2s";
simple-audio-card,dai-link@0 { /* I2S - HDMI */ simple-audio-card,dai-link@0 { /* I2S - HDMI */
simple-audio-card,cpu { format = "i2s";
cpu {
sound-dai = <&audio1 0>; sound-dai = <&audio1 0>;
}; };
simple-audio-card,codec { codec {
sound-dai = <&tda998x 0>; sound-dai = <&tda998x 0>;
}; };
}; };
simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */ simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */
simple-audio-card,cpu { cpu {
sound-dai = <&audio1 1>; sound-dai = <&audio1 1>;
}; };
simple-audio-card,codec { codec {
sound-dai = <&tda998x 1>; sound-dai = <&tda998x 1>;
}; };
}; };
simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */ simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */
simple-audio-card,cpu { cpu {
sound-dai = <&audio1 1>; sound-dai = <&audio1 1>;
}; };
simple-audio-card,codec { codec {
sound-dai = <&spdif_codec>; sound-dai = <&spdif_codec>;
}; };
}; };
......
...@@ -88,7 +88,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) ...@@ -88,7 +88,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
static int static int
asoc_simple_card_sub_parse_of(struct device_node *np, asoc_simple_card_sub_parse_of(struct device_node *np,
unsigned int daifmt,
struct asoc_simple_dai *dai, struct asoc_simple_dai *dai,
const struct device_node **p_node, const struct device_node **p_node,
const char **name) const char **name)
...@@ -116,14 +115,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np, ...@@ -116,14 +115,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
if (ret) if (ret)
return ret; return ret;
/*
* bitclock-inversion, frame-inversion
* bitclock-master, frame-master
* and specific "format" if it has
*/
dai->fmt = snd_soc_of_parse_daifmt(np, NULL, NULL, NULL);
dai->fmt |= daifmt;
/* /*
* dai->sysclk come from * dai->sysclk come from
* "clocks = <&xxx>" (if system has common clock) * "clocks = <&xxx>" (if system has common clock)
...@@ -151,37 +142,135 @@ asoc_simple_card_sub_parse_of(struct device_node *np, ...@@ -151,37 +142,135 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
return 0; return 0;
} }
static int simple_card_cpu_codec_of(struct device_node *node, static int simple_card_dai_link_of(struct device_node *node,
int daifmt, struct device *dev,
struct snd_soc_dai_link *dai_link, struct snd_soc_dai_link *dai_link,
struct simple_dai_props *dai_props) struct simple_dai_props *dai_props)
{ {
struct device_node *np; struct device_node *np = NULL;
struct device_node *bitclkmaster = NULL;
struct device_node *framemaster = NULL;
unsigned int daifmt;
char *name;
char prop[128];
char *prefix = "";
int ret; int ret;
/* CPU sub-node */ if (!strcmp("sound", node->name))
prefix = "simple-audio-card,";
daifmt = snd_soc_of_parse_daifmt(node, prefix,
&bitclkmaster, &framemaster);
daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
snprintf(prop, sizeof(prop), "%scpu", prefix);
np = of_get_child_by_name(node, prop);
if (!np) {
ret = -EINVAL; ret = -EINVAL;
np = of_get_child_by_name(node, "simple-audio-card,cpu"); dev_err(dev, "%s: Can't find simple-audio-card,cpu DT node\n",
if (np) { __func__);
ret = asoc_simple_card_sub_parse_of(np, daifmt, goto dai_link_of_err;
&dai_props->cpu_dai, }
ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
&dai_link->cpu_of_node, &dai_link->cpu_of_node,
&dai_link->cpu_dai_name); &dai_link->cpu_dai_name);
of_node_put(np);
}
if (ret < 0) if (ret < 0)
return ret; goto dai_link_of_err;
dai_props->cpu_dai.fmt = daifmt;
switch (((np == bitclkmaster)<<4)|(np == framemaster)) {
case 0x11:
dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
break;
case 0x10:
dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
break;
case 0x01:
dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
break;
default:
dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
break;
}
/* CODEC sub-node */ of_node_put(np);
snprintf(prop, sizeof(prop), "%scodec", prefix);
np = of_get_child_by_name(node, prop);
if (!np) {
ret = -EINVAL; ret = -EINVAL;
np = of_get_child_by_name(node, "simple-audio-card,codec"); dev_err(dev, "%s: Can't find simple-audio-card,codec DT node\n",
if (np) { __func__);
ret = asoc_simple_card_sub_parse_of(np, daifmt, goto dai_link_of_err;
&dai_props->codec_dai, }
ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
&dai_link->codec_of_node, &dai_link->codec_of_node,
&dai_link->codec_dai_name); &dai_link->codec_dai_name);
of_node_put(np); if (ret < 0)
goto dai_link_of_err;
if (strlen(prefix) && !bitclkmaster && !framemaster) {
/* No dai-link level and master setting was not found from
sound node level, revert back to legacy DT parsing and
take the settings from codec node. */
dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
__func__);
dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) |
(daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
} else {
dai_props->codec_dai.fmt = daifmt;
switch (((np == bitclkmaster)<<4)|(np == framemaster)) {
case 0x11:
dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
break;
case 0x10:
dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
break;
case 0x01:
dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
break;
default:
dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
break;
} }
}
if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
ret = -EINVAL;
goto dai_link_of_err;
}
/* simple-card assumes platform == cpu */
dai_link->platform_of_node = dai_link->cpu_of_node;
/* Link name is created from CPU/CODEC dai name */
name = devm_kzalloc(dev,
strlen(dai_link->cpu_dai_name) +
strlen(dai_link->codec_dai_name) + 2,
GFP_KERNEL);
sprintf(name, "%s-%s", dai_link->cpu_dai_name,
dai_link->codec_dai_name);
dai_link->name = dai_link->stream_name = name;
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
dai_link->cpu_dai_name,
dai_props->cpu_dai.fmt,
dai_props->cpu_dai.sysclk);
dev_dbg(dev, "\tcodec : %s / %04x / %d\n",
dai_link->codec_dai_name,
dai_props->codec_dai.fmt,
dai_props->codec_dai.sysclk);
dai_link_of_err:
if (np)
of_node_put(np);
if (bitclkmaster)
of_node_put(bitclkmaster);
if (framemaster)
of_node_put(framemaster);
return ret; return ret;
} }
...@@ -192,19 +281,11 @@ static int asoc_simple_card_parse_of(struct device_node *node, ...@@ -192,19 +281,11 @@ static int asoc_simple_card_parse_of(struct device_node *node,
{ {
struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
struct simple_dai_props *dai_props = priv->dai_props; struct simple_dai_props *dai_props = priv->dai_props;
struct device_node *np;
char *name;
unsigned int daifmt;
int ret; int ret;
/* parsing the card name from DT */ /* parsing the card name from DT */
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
/* get CPU/CODEC common format via simple-audio-card,format */
daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,", NULL,
NULL) &
(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
/* off-codec widgets */ /* off-codec widgets */
if (of_property_read_bool(node, "simple-audio-card,widgets")) { if (of_property_read_bool(node, "simple-audio-card,widgets")) {
ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
...@@ -221,71 +302,31 @@ static int asoc_simple_card_parse_of(struct device_node *node, ...@@ -221,71 +302,31 @@ static int asoc_simple_card_parse_of(struct device_node *node,
return ret; return ret;
} }
/* loop on the DAI links */ dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
np = NULL; priv->snd_card.name : "");
for (;;) {
if (multi) { if (multi) {
np = of_get_next_child(node, np); struct device_node *np = NULL;
if (!np) int i;
break; for (i = 0; (np = of_get_next_child(node, np)); i++) {
dev_dbg(dev, "\tlink %d:\n", i);
ret = simple_card_dai_link_of(np, dev, dai_link + i,
dai_props + i);
if (ret < 0) {
of_node_put(np);
return ret;
} }
ret = simple_card_cpu_codec_of(multi ? np : node,
daifmt, dai_link, dai_props);
if (ret < 0)
goto err;
/*
* 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.
*/
dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt;
if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
ret = -EINVAL;
goto err;
} }
} else {
/* simple-card assumes platform == cpu */ ret = simple_card_dai_link_of(node, dev, dai_link, dai_props);
dai_link->platform_of_node = dai_link->cpu_of_node; if (ret < 0)
return ret;
name = devm_kzalloc(dev,
strlen(dai_link->cpu_dai_name) +
strlen(dai_link->codec_dai_name) + 2,
GFP_KERNEL);
sprintf(name, "%s-%s", dai_link->cpu_dai_name,
dai_link->codec_dai_name);
dai_link->name = dai_link->stream_name = name;
if (!multi)
break;
dai_link++;
dai_props++;
} }
/* card name is created from CPU/CODEC dai name */
dai_link = priv->snd_card.dai_link;
if (!priv->snd_card.name) if (!priv->snd_card.name)
priv->snd_card.name = dai_link->name; priv->snd_card.name = priv->snd_card.dai_link->name;
dev_dbg(dev, "card-name : %s\n", priv->snd_card.name);
dev_dbg(dev, "platform : %04x\n", daifmt);
dai_props = priv->dai_props;
dev_dbg(dev, "cpu : %s / %04x / %d\n",
dai_link->cpu_dai_name,
dai_props->cpu_dai.fmt,
dai_props->cpu_dai.sysclk);
dev_dbg(dev, "codec : %s / %04x / %d\n",
dai_link->codec_dai_name,
dai_props->codec_dai.fmt,
dai_props->codec_dai.sysclk);
return 0; return 0;
err:
of_node_put(np);
return ret;
} }
/* update the reference count of the devices nodes at end of probe */ /* update the reference count of the devices nodes at end of probe */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment