mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 07:31:45 +00:00
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: Jyri Sarha <jsarha@ti.com> Acked-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
parent
389cb8348c
commit
b3ca11ff59
@ -1,6 +1,6 @@
|
||||
Simple-Card:
|
||||
|
||||
Simple-Card specifies audio DAI connection of SoC <-> codec.
|
||||
Simple-Card specifies audio DAI connections of SoC <-> codec.
|
||||
|
||||
Required properties:
|
||||
|
||||
@ -10,26 +10,51 @@ Optional properties:
|
||||
|
||||
- simple-audio-card,name : User specified audio sound card name, one string
|
||||
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,routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the
|
||||
connection's sink, the second being the connection's
|
||||
source.
|
||||
- dai-tdm-slot-num : Please refer to tdm-slot.txt.
|
||||
- dai-tdm-slot-width : Please refer to tdm-slot.txt.
|
||||
Optional subnodes:
|
||||
|
||||
Required subnodes:
|
||||
- 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.
|
||||
|
||||
- simple-audio-card,dai-link : container for the CPU and CODEC sub-nodes
|
||||
This container may be omitted when the
|
||||
card has only one DAI link.
|
||||
See the examples.
|
||||
Dai-link subnode properties and subnodes:
|
||||
|
||||
- simple-audio-card,cpu : CPU sub-node
|
||||
- simple-audio-card,codec : CODEC sub-node
|
||||
If dai-link subnode is omitted and the subnode properties are directly
|
||||
under "sound"-node the subnode property and subnode names have to be
|
||||
prefixed with "simple-audio-card,"-prefix.
|
||||
|
||||
Required dai-link subnodes:
|
||||
|
||||
- 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:
|
||||
|
||||
@ -37,29 +62,21 @@ Required CPU/CODEC subnodes properties:
|
||||
|
||||
Optional CPU/CODEC subnodes properties:
|
||||
|
||||
- format : CPU/CODEC specific audio format if needed.
|
||||
see simple-audio-card,format
|
||||
- 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
|
||||
- dai-tdm-slot-num : Please refer to tdm-slot.txt.
|
||||
- dai-tdm-slot-width : Please refer to tdm-slot.txt.
|
||||
- clocks / system-clock-frequency : specify subnode's clock if needed.
|
||||
it can be specified via "clocks" if system has
|
||||
clock node (= common clock), or "system-clock-frequency"
|
||||
(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:
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,name = "VF610-Tower-Sound-Card";
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&dailink0_master>;
|
||||
simple-audio-card,frame-master = <&dailink0_master>;
|
||||
simple-audio-card,widgets =
|
||||
"Microphone", "Microphone Jack",
|
||||
"Headphone", "Headphone Jack",
|
||||
@ -69,17 +86,12 @@ sound {
|
||||
"Headphone Jack", "HP_OUT",
|
||||
"External Speaker", "LINE_OUT";
|
||||
|
||||
dai-tdm-slot-num = <2>;
|
||||
dai-tdm-slot-width = <8>;
|
||||
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&sh_fsi2 0>;
|
||||
};
|
||||
|
||||
simple-audio-card,codec {
|
||||
dailink0_master: simple-audio-card,codec {
|
||||
sound-dai = <&ak4648>;
|
||||
bitclock-master;
|
||||
frame-master;
|
||||
clocks = <&osc>;
|
||||
};
|
||||
};
|
||||
@ -105,31 +117,31 @@ Example 2 - many DAI links:
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,name = "Cubox Audio";
|
||||
simple-audio-card,format = "i2s";
|
||||
|
||||
simple-audio-card,dai-link@0 { /* I2S - HDMI */
|
||||
simple-audio-card,cpu {
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&audio1 0>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
codec {
|
||||
sound-dai = <&tda998x 0>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */
|
||||
simple-audio-card,cpu {
|
||||
cpu {
|
||||
sound-dai = <&audio1 1>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
codec {
|
||||
sound-dai = <&tda998x 1>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */
|
||||
simple-audio-card,cpu {
|
||||
cpu {
|
||||
sound-dai = <&audio1 1>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
codec {
|
||||
sound-dai = <&spdif_codec>;
|
||||
};
|
||||
};
|
||||
|
@ -88,7 +88,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
|
||||
static int
|
||||
asoc_simple_card_sub_parse_of(struct device_node *np,
|
||||
unsigned int daifmt,
|
||||
struct asoc_simple_dai *dai,
|
||||
const struct device_node **p_node,
|
||||
const char **name)
|
||||
@ -116,14 +115,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
|
||||
if (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
|
||||
* "clocks = <&xxx>" (if system has common clock)
|
||||
@ -151,37 +142,135 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int simple_card_cpu_codec_of(struct device_node *node,
|
||||
int daifmt,
|
||||
struct snd_soc_dai_link *dai_link,
|
||||
struct simple_dai_props *dai_props)
|
||||
static int simple_card_dai_link_of(struct device_node *node,
|
||||
struct device *dev,
|
||||
struct snd_soc_dai_link *dai_link,
|
||||
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;
|
||||
|
||||
/* 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, daifmt,
|
||||
&dai_props->cpu_dai,
|
||||
&dai_link->cpu_of_node,
|
||||
&dai_link->cpu_dai_name);
|
||||
of_node_put(np);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!strcmp("sound", node->name))
|
||||
prefix = "simple-audio-card,";
|
||||
|
||||
/* 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, daifmt,
|
||||
&dai_props->codec_dai,
|
||||
&dai_link->codec_of_node,
|
||||
&dai_link->codec_dai_name);
|
||||
of_node_put(np);
|
||||
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;
|
||||
dev_err(dev, "%s: Can't find simple-audio-card,cpu DT node\n",
|
||||
__func__);
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
|
||||
&dai_link->cpu_of_node,
|
||||
&dai_link->cpu_dai_name);
|
||||
if (ret < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
snprintf(prop, sizeof(prop), "%scodec", prefix);
|
||||
np = of_get_child_by_name(node, prop);
|
||||
if (!np) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "%s: Can't find simple-audio-card,codec DT node\n",
|
||||
__func__);
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
|
||||
&dai_link->codec_of_node,
|
||||
&dai_link->codec_dai_name);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 simple_dai_props *dai_props = priv->dai_props;
|
||||
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 */
|
||||
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 */
|
||||
if (of_property_read_bool(node, "simple-audio-card,widgets")) {
|
||||
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,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* loop on the DAI links */
|
||||
np = NULL;
|
||||
for (;;) {
|
||||
if (multi) {
|
||||
np = of_get_next_child(node, np);
|
||||
if (!np)
|
||||
break;
|
||||
}
|
||||
dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
|
||||
priv->snd_card.name : "");
|
||||
|
||||
ret = simple_card_cpu_codec_of(multi ? np : node,
|
||||
daifmt, dai_link, dai_props);
|
||||
if (multi) {
|
||||
struct device_node *np = NULL;
|
||||
int i;
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = simple_card_dai_link_of(node, dev, 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;
|
||||
}
|
||||
|
||||
/* simple-card assumes platform == cpu */
|
||||
dai_link->platform_of_node = dai_link->cpu_of_node;
|
||||
|
||||
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++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* card name is created from CPU/CODEC dai name */
|
||||
dai_link = priv->snd_card.dai_link;
|
||||
if (!priv->snd_card.name)
|
||||
priv->snd_card.name = 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);
|
||||
priv->snd_card.name = priv->snd_card.dai_link->name;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* update the reference count of the devices nodes at end of probe */
|
||||
|
Loading…
Reference in New Issue
Block a user