Commit 0168bf0d authored by Liam Girdwood's avatar Liam Girdwood Committed by Mark Brown

ASoC: core - Allow components to probe/remove in sequence.

Some ASoC components depend on other ASoC components to provide clocks and
power resources in order to probe() and vice versa for remove().

Allow components to be ordered so that components can be probed() and removed()
in sequences that conform to their dependencies.
Signed-off-by: default avatarLiam Girdwood <lrg@ti.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 552d1ef6
...@@ -209,6 +209,10 @@ struct snd_soc_dai_driver { ...@@ -209,6 +209,10 @@ struct snd_soc_dai_driver {
struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream capture;
struct snd_soc_pcm_stream playback; struct snd_soc_pcm_stream playback;
unsigned int symmetric_rates:1; unsigned int symmetric_rates:1;
/* probe ordering - for components with runtime dependencies */
int probe_order;
int remove_order;
}; };
/* /*
......
...@@ -202,6 +202,16 @@ ...@@ -202,6 +202,16 @@
#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
/*
* Component probe and remove ordering levels for components with runtime
* dependencies.
*/
#define SND_SOC_COMP_ORDER_FIRST -2
#define SND_SOC_COMP_ORDER_EARLY -1
#define SND_SOC_COMP_ORDER_NORMAL 0
#define SND_SOC_COMP_ORDER_LATE 1
#define SND_SOC_COMP_ORDER_LAST 2
/* /*
* Bias levels * Bias levels
* *
...@@ -613,6 +623,10 @@ struct snd_soc_codec_driver { ...@@ -613,6 +623,10 @@ struct snd_soc_codec_driver {
void (*seq_notifier)(struct snd_soc_dapm_context *, void (*seq_notifier)(struct snd_soc_dapm_context *,
enum snd_soc_dapm_type, int); enum snd_soc_dapm_type, int);
/* probe ordering - for components with runtime dependencies */
int probe_order;
int remove_order;
}; };
/* SoC platform interface */ /* SoC platform interface */
...@@ -636,6 +650,10 @@ struct snd_soc_platform_driver { ...@@ -636,6 +650,10 @@ struct snd_soc_platform_driver {
/* platform stream ops */ /* platform stream ops */
struct snd_pcm_ops *ops; struct snd_pcm_ops *ops;
/* probe ordering - for components with runtime dependencies */
int probe_order;
int remove_order;
}; };
struct snd_soc_platform { struct snd_soc_platform {
......
...@@ -1394,7 +1394,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec) ...@@ -1394,7 +1394,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec)
module_put(codec->dev->driver->owner); module_put(codec->dev->driver->owner);
} }
static void soc_remove_dai_link(struct snd_soc_card *card, int num) static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
{ {
struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
...@@ -1411,7 +1411,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) ...@@ -1411,7 +1411,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
} }
/* remove the CODEC DAI */ /* remove the CODEC DAI */
if (codec_dai && codec_dai->probed) { if (codec_dai && codec_dai->probed &&
codec_dai->driver->remove_order == order) {
if (codec_dai->driver->remove) { if (codec_dai->driver->remove) {
err = codec_dai->driver->remove(codec_dai); err = codec_dai->driver->remove(codec_dai);
if (err < 0) if (err < 0)
...@@ -1422,7 +1423,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) ...@@ -1422,7 +1423,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
} }
/* remove the platform */ /* remove the platform */
if (platform && platform->probed) { if (platform && platform->probed &&
platform->driver->remove_order == order) {
if (platform->driver->remove) { if (platform->driver->remove) {
err = platform->driver->remove(platform); err = platform->driver->remove(platform);
if (err < 0) if (err < 0)
...@@ -1434,11 +1436,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) ...@@ -1434,11 +1436,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
} }
/* remove the CODEC */ /* remove the CODEC */
if (codec && codec->probed) if (codec && codec->probed &&
codec->driver->remove_order == order)
soc_remove_codec(codec); soc_remove_codec(codec);
/* remove the cpu_dai */ /* remove the cpu_dai */
if (cpu_dai && cpu_dai->probed) { if (cpu_dai && cpu_dai->probed &&
cpu_dai->driver->remove_order == order) {
if (cpu_dai->driver->remove) { if (cpu_dai->driver->remove) {
err = cpu_dai->driver->remove(cpu_dai); err = cpu_dai->driver->remove(cpu_dai);
if (err < 0) if (err < 0)
...@@ -1452,11 +1456,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) ...@@ -1452,11 +1456,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
static void soc_remove_dai_links(struct snd_soc_card *card) static void soc_remove_dai_links(struct snd_soc_card *card)
{ {
int i; int dai, order;
for (i = 0; i < card->num_rtd; i++)
soc_remove_dai_link(card, i);
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
for (dai = 0; dai < card->num_rtd; dai++)
soc_remove_dai_link(card, dai, order);
}
card->num_rtd = 0; card->num_rtd = 0;
} }
...@@ -1597,7 +1603,7 @@ static int soc_post_component_init(struct snd_soc_card *card, ...@@ -1597,7 +1603,7 @@ static int soc_post_component_init(struct snd_soc_card *card,
return 0; return 0;
} }
static int soc_probe_dai_link(struct snd_soc_card *card, int num) static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
{ {
struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
...@@ -1606,7 +1612,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) ...@@ -1606,7 +1612,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
int ret; int ret;
dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num); dev_dbg(card->dev, "probe %s dai link %d late %d\n",
card->name, num, order);
/* config components */ /* config components */
codec_dai->codec = codec; codec_dai->codec = codec;
...@@ -1618,7 +1625,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) ...@@ -1618,7 +1625,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
rtd->pmdown_time = pmdown_time; rtd->pmdown_time = pmdown_time;
/* probe the cpu_dai */ /* probe the cpu_dai */
if (!cpu_dai->probed) { if (!cpu_dai->probed &&
cpu_dai->driver->probe_order == order) {
if (!try_module_get(cpu_dai->dev->driver->owner)) if (!try_module_get(cpu_dai->dev->driver->owner))
return -ENODEV; return -ENODEV;
...@@ -1637,14 +1645,16 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) ...@@ -1637,14 +1645,16 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
} }
/* probe the CODEC */ /* probe the CODEC */
if (!codec->probed) { if (!codec->probed &&
codec->driver->probe_order == order) {
ret = soc_probe_codec(card, codec); ret = soc_probe_codec(card, codec);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
/* probe the platform */ /* probe the platform */
if (!platform->probed) { if (!platform->probed &&
platform->driver->probe_order == order) {
if (!try_module_get(platform->dev->driver->owner)) if (!try_module_get(platform->dev->driver->owner))
return -ENODEV; return -ENODEV;
...@@ -1663,7 +1673,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) ...@@ -1663,7 +1673,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
} }
/* probe the CODEC DAI */ /* probe the CODEC DAI */
if (!codec_dai->probed) { if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
if (codec_dai->driver->probe) { if (codec_dai->driver->probe) {
ret = codec_dai->driver->probe(codec_dai); ret = codec_dai->driver->probe(codec_dai);
if (ret < 0) { if (ret < 0) {
...@@ -1678,6 +1688,10 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) ...@@ -1678,6 +1688,10 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
list_add(&codec_dai->card_list, &card->dai_dev_list); list_add(&codec_dai->card_list, &card->dai_dev_list);
} }
/* complete DAI probe during last probe */
if (order != SND_SOC_COMP_ORDER_LAST)
return 0;
/* DAPM dai link stream work */ /* DAPM dai link stream work */
INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
...@@ -1818,7 +1832,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) ...@@ -1818,7 +1832,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
struct snd_soc_codec *codec; struct snd_soc_codec *codec;
struct snd_soc_codec_conf *codec_conf; struct snd_soc_codec_conf *codec_conf;
enum snd_soc_compress_type compress_type; enum snd_soc_compress_type compress_type;
int ret, i; int ret, i, order;
mutex_lock(&card->mutex); mutex_lock(&card->mutex);
...@@ -1896,14 +1910,18 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) ...@@ -1896,14 +1910,18 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
goto card_probe_error; goto card_probe_error;
} }
/* early DAI link probe */
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
for (i = 0; i < card->num_links; i++) { for (i = 0; i < card->num_links; i++) {
ret = soc_probe_dai_link(card, i); ret = soc_probe_dai_link(card, i, order);
if (ret < 0) { if (ret < 0) {
pr_err("asoc: failed to instantiate card %s: %d\n", pr_err("asoc: failed to instantiate card %s: %d\n",
card->name, ret); card->name, ret);
goto probe_dai_err; goto probe_dai_err;
} }
} }
}
for (i = 0; i < card->num_aux_devs; i++) { for (i = 0; i < card->num_aux_devs; i++) {
ret = soc_probe_aux_dev(card, i); ret = soc_probe_aux_dev(card, i);
......
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