ASoC: omap-abe-twl6040: Fix missing audio card caused by deferred probing

The machine driver fails to probe in next-20181113 with:

[    2.539093] omap-abe-twl6040 sound: ASoC: CODEC DAI twl6040-legacy not registered
[    2.546630] omap-abe-twl6040 sound: devm_snd_soc_register_card() failed: -517
...
[    3.693206] omap-abe-twl6040 sound: ASoC: Both platform name/of_node are set for TWL6040
[    3.701446] omap-abe-twl6040 sound: ASoC: failed to init link TWL6040
[    3.708007] omap-abe-twl6040 sound: devm_snd_soc_register_card() failed: -22
[    3.715148] omap-abe-twl6040: probe of sound failed with error -22

Bisect pointed to a merge commit:
first bad commit: [0f688ab20a540aafa984c5dbd68a71debebf4d7f] Merge remote-tracking branch 'net-next/master'

and a diff between a working kernel does not reveal anything which would
explain the change in behavior.

Further investigation showed that on the second try of loading fails
because the dai_link->platform is no longer NULL and it might be pointing
to uninitialized memory.

The fix is to move the snd_soc_dai_link and snd_soc_card inside of the
abe_twl6040 struct, which is dynamically allocated every time the driver
probes.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Peter Ujfalusi 2018-11-14 14:58:20 +02:00 committed by Mark Brown
parent 933a95496e
commit 76836fd354
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -36,6 +36,8 @@
#include "../codecs/twl6040.h"
struct abe_twl6040 {
struct snd_soc_card card;
struct snd_soc_dai_link dai_links[2];
int jack_detection; /* board can detect jack events */
int mclk_freq; /* MCLK frequency speed for twl6040 */
};
@ -208,40 +210,10 @@ static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
ARRAY_SIZE(dmic_audio_map));
}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
{
.name = "TWL6040",
.stream_name = "TWL6040",
.codec_dai_name = "twl6040-legacy",
.codec_name = "twl6040-codec",
.init = omap_abe_twl6040_init,
.ops = &omap_abe_ops,
},
{
.name = "DMIC",
.stream_name = "DMIC Capture",
.codec_dai_name = "dmic-hifi",
.codec_name = "dmic-codec",
.init = omap_abe_dmic_init,
.ops = &omap_abe_dmic_ops,
},
};
/* Audio machine driver */
static struct snd_soc_card omap_abe_card = {
.owner = THIS_MODULE,
.dapm_widgets = twl6040_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
static int omap_abe_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct snd_soc_card *card = &omap_abe_card;
struct snd_soc_card *card;
struct device_node *dai_node;
struct abe_twl6040 *priv;
int num_links = 0;
@ -252,12 +224,18 @@ static int omap_abe_probe(struct platform_device *pdev)
return -ENODEV;
}
card->dev = &pdev->dev;
priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
card = &priv->card;
card->dev = &pdev->dev;
card->owner = THIS_MODULE;
card->dapm_widgets = twl6040_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets);
card->dapm_routes = audio_map;
card->num_dapm_routes = ARRAY_SIZE(audio_map);
if (snd_soc_of_parse_card_name(card, "ti,model")) {
dev_err(&pdev->dev, "Card name is not provided\n");
return -ENODEV;
@ -274,14 +252,27 @@ static int omap_abe_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "McPDM node is not provided\n");
return -EINVAL;
}
abe_twl6040_dai_links[0].cpu_of_node = dai_node;
abe_twl6040_dai_links[0].platform_of_node = dai_node;
priv->dai_links[0].name = "DMIC";
priv->dai_links[0].stream_name = "TWL6040";
priv->dai_links[0].cpu_of_node = dai_node;
priv->dai_links[0].platform_of_node = dai_node;
priv->dai_links[0].codec_dai_name = "twl6040-legacy";
priv->dai_links[0].codec_name = "twl6040-codec";
priv->dai_links[0].init = omap_abe_twl6040_init;
priv->dai_links[0].ops = &omap_abe_ops;
dai_node = of_parse_phandle(node, "ti,dmic", 0);
if (dai_node) {
num_links = 2;
abe_twl6040_dai_links[1].cpu_of_node = dai_node;
abe_twl6040_dai_links[1].platform_of_node = dai_node;
priv->dai_links[1].name = "TWL6040";
priv->dai_links[1].stream_name = "DMIC Capture";
priv->dai_links[1].cpu_of_node = dai_node;
priv->dai_links[1].platform_of_node = dai_node;
priv->dai_links[1].codec_dai_name = "dmic-hifi";
priv->dai_links[1].codec_name = "dmic-codec";
priv->dai_links[1].init = omap_abe_dmic_init;
priv->dai_links[1].ops = &omap_abe_dmic_ops;
} else {
num_links = 1;
}
@ -300,7 +291,7 @@ static int omap_abe_probe(struct platform_device *pdev)
return -ENODEV;
}
card->dai_link = abe_twl6040_dai_links;
card->dai_link = priv->dai_links;
card->num_links = num_links;
snd_soc_card_set_drvdata(card, priv);