Commit a1916ff3 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/pcm-list' into asoc-next

parents 2dd49f8e f2ed6b07
...@@ -222,6 +222,7 @@ struct snd_soc_dai_driver { ...@@ -222,6 +222,7 @@ struct snd_soc_dai_driver {
const char *name; const char *name;
unsigned int id; unsigned int id;
unsigned int base; unsigned int base;
struct snd_soc_dobj dobj;
/* DAI driver callbacks */ /* DAI driver callbacks */
int (*probe)(struct snd_soc_dai *dai); int (*probe)(struct snd_soc_dai *dai);
......
...@@ -798,6 +798,7 @@ struct snd_soc_component { ...@@ -798,6 +798,7 @@ struct snd_soc_component {
unsigned int registered_as_component:1; unsigned int registered_as_component:1;
struct list_head list; struct list_head list;
struct list_head list_aux; /* for auxiliary component of the card */
struct snd_soc_dai_driver *dai_drv; struct snd_soc_dai_driver *dai_drv;
int num_dai; int num_dai;
...@@ -841,6 +842,9 @@ struct snd_soc_component { ...@@ -841,6 +842,9 @@ struct snd_soc_component {
int (*probe)(struct snd_soc_component *); int (*probe)(struct snd_soc_component *);
void (*remove)(struct snd_soc_component *); void (*remove)(struct snd_soc_component *);
/* machine specific init */
int (*init)(struct snd_soc_component *component);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void (*init_debugfs)(struct snd_soc_component *component); void (*init_debugfs)(struct snd_soc_component *component);
const char *debugfs_prefix; const char *debugfs_prefix;
...@@ -1141,8 +1145,7 @@ struct snd_soc_card { ...@@ -1141,8 +1145,7 @@ struct snd_soc_card {
*/ */
struct snd_soc_aux_dev *aux_dev; struct snd_soc_aux_dev *aux_dev;
int num_aux_devs; int num_aux_devs;
struct snd_soc_pcm_runtime *rtd_aux; struct list_head aux_comp_list;
int num_aux_rtd;
const struct snd_kcontrol_new *controls; const struct snd_kcontrol_new *controls;
int num_controls; int num_controls;
...@@ -1550,6 +1553,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) ...@@ -1550,6 +1553,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths); INIT_LIST_HEAD(&card->paths);
INIT_LIST_HEAD(&card->dapm_list); INIT_LIST_HEAD(&card->dapm_list);
INIT_LIST_HEAD(&card->aux_comp_list);
} }
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
...@@ -1676,6 +1680,9 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, ...@@ -1676,6 +1680,9 @@ int snd_soc_add_dai_link(struct snd_soc_card *card,
void snd_soc_remove_dai_link(struct snd_soc_card *card, void snd_soc_remove_dai_link(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link); struct snd_soc_dai_link *dai_link);
int snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv);
#include <sound/soc-dai.h> #include <sound/soc-dai.h>
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
......
...@@ -1413,6 +1413,16 @@ static int soc_probe_component(struct snd_soc_card *card, ...@@ -1413,6 +1413,16 @@ static int soc_probe_component(struct snd_soc_card *card,
component->name); component->name);
} }
/* machine specific init */
if (component->init) {
ret = component->init(component);
if (ret < 0) {
dev_err(component->dev,
"Failed to do machine specific init %d\n", ret);
goto err_probe;
}
}
if (component->controls) if (component->controls)
snd_soc_add_component_controls(component, component->controls, snd_soc_add_component_controls(component, component->controls,
component->num_controls); component->num_controls);
...@@ -1657,65 +1667,81 @@ static int soc_probe_link_dais(struct snd_soc_card *card, ...@@ -1657,65 +1667,81 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
static int soc_bind_aux_dev(struct snd_soc_card *card, int num) static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
{ {
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
const char *name = aux_dev->codec_name; struct snd_soc_component *component;
const char *name;
rtd->component = soc_find_component(aux_dev->codec_of_node, name); struct device_node *codec_of_node;
if (!rtd->component) {
if (aux_dev->codec_of_node) if (aux_dev->codec_of_node || aux_dev->codec_name) {
name = of_node_full_name(aux_dev->codec_of_node); /* codecs, usually analog devices */
name = aux_dev->codec_name;
dev_err(card->dev, "ASoC: %s not registered\n", name); codec_of_node = aux_dev->codec_of_node;
return -EPROBE_DEFER; component = soc_find_component(codec_of_node, name);
if (!component) {
if (codec_of_node)
name = of_node_full_name(codec_of_node);
goto err_defer;
}
} else if (aux_dev->name) {
/* generic components */
name = aux_dev->name;
component = soc_find_component(NULL, name);
if (!component)
goto err_defer;
} else {
dev_err(card->dev, "ASoC: Invalid auxiliary device\n");
return -EINVAL;
} }
/* component->init = aux_dev->init;
* Some places still reference rtd->codec, so we have to keep that list_add(&component->list_aux, &card->aux_comp_list);
* initialized if the component is a CODEC. Once all those references
* have been removed, this code can be removed as well.
*/
rtd->codec = rtd->component->codec;
return 0; return 0;
err_defer:
dev_err(card->dev, "ASoC: %s not registered\n", name);
return -EPROBE_DEFER;
} }
static int soc_probe_aux_dev(struct snd_soc_card *card, int num) static int soc_probe_aux_devices(struct snd_soc_card *card)
{ {
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_component *comp;
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int order;
int ret; int ret;
ret = soc_probe_component(card, rtd->component); for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
if (ret < 0) order++) {
return ret; list_for_each_entry(comp, &card->aux_comp_list, list_aux) {
if (comp->driver->probe_order == order) {
/* do machine specific initialization */ ret = soc_probe_component(card, comp);
if (aux_dev->init) { if (ret < 0) {
ret = aux_dev->init(rtd->component); dev_err(card->dev,
if (ret < 0) { "ASoC: failed to probe aux component %s %d\n",
dev_err(card->dev, "ASoC: failed to init %s: %d\n", comp->name, ret);
aux_dev->name, ret); return ret;
return ret; }
}
} }
} }
return soc_post_component_init(rtd, aux_dev->name); return 0;
} }
static void soc_remove_aux_dev(struct snd_soc_card *card, int num) static void soc_remove_aux_devices(struct snd_soc_card *card)
{ {
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_component *comp, *_comp;
struct snd_soc_component *component = rtd->component; int order;
/* unregister the rtd device */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
if (rtd->dev_registered) { order++) {
device_unregister(rtd->dev); list_for_each_entry_safe(comp, _comp,
rtd->dev_registered = 0; &card->aux_comp_list, list_aux) {
if (comp->driver->remove_order == order) {
soc_remove_component(comp);
/* remove it from the card's aux_comp_list */
list_del(&comp->list_aux);
}
}
} }
if (component)
soc_remove_component(component);
} }
static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
...@@ -1894,6 +1920,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ...@@ -1894,6 +1920,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
} }
} }
/* probe auxiliary components */
ret = soc_probe_aux_devices(card);
if (ret < 0)
goto probe_dai_err;
/* Find new DAI links added during probing components and bind them. /* Find new DAI links added during probing components and bind them.
* Components with topology may bring new DAIs and DAI links. * Components with topology may bring new DAIs and DAI links.
*/ */
...@@ -1923,16 +1954,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ...@@ -1923,16 +1954,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
} }
} }
for (i = 0; i < card->num_aux_devs; i++) {
ret = soc_probe_aux_dev(card, i);
if (ret < 0) {
dev_err(card->dev,
"ASoC: failed to add auxiliary devices %d\n",
ret);
goto probe_aux_dev_err;
}
}
snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_link_dai_widgets(card);
snd_soc_dapm_connect_dai_link_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card);
...@@ -1992,8 +2013,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ...@@ -1992,8 +2013,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
return 0; return 0;
probe_aux_dev_err: probe_aux_dev_err:
for (i = 0; i < card->num_aux_devs; i++) soc_remove_aux_devices(card);
soc_remove_aux_dev(card, i);
probe_dai_err: probe_dai_err:
soc_remove_dai_links(card); soc_remove_dai_links(card);
...@@ -2039,20 +2059,18 @@ static int soc_probe(struct platform_device *pdev) ...@@ -2039,20 +2059,18 @@ static int soc_probe(struct platform_device *pdev)
static int soc_cleanup_card_resources(struct snd_soc_card *card) static int soc_cleanup_card_resources(struct snd_soc_card *card)
{ {
struct snd_soc_pcm_runtime *rtd; struct snd_soc_pcm_runtime *rtd;
int i;
/* make sure any delayed work runs */ /* make sure any delayed work runs */
list_for_each_entry(rtd, &card->rtd_list, list) list_for_each_entry(rtd, &card->rtd_list, list)
flush_delayed_work(&rtd->delayed_work); flush_delayed_work(&rtd->delayed_work);
/* remove auxiliary devices */
for (i = 0; i < card->num_aux_devs; i++)
soc_remove_aux_dev(card, i);
/* remove and free each DAI */ /* remove and free each DAI */
soc_remove_dai_links(card); soc_remove_dai_links(card);
soc_remove_pcm_runtimes(card); soc_remove_pcm_runtimes(card);
/* remove auxiliary devices */
soc_remove_aux_devices(card);
soc_cleanup_card_debugfs(card); soc_cleanup_card_debugfs(card);
/* remove the card */ /* remove the card */
...@@ -2608,16 +2626,6 @@ int snd_soc_register_card(struct snd_soc_card *card) ...@@ -2608,16 +2626,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->rtd_list); INIT_LIST_HEAD(&card->rtd_list);
card->num_rtd = 0; card->num_rtd = 0;
card->rtd_aux = devm_kzalloc(card->dev,
sizeof(struct snd_soc_pcm_runtime) *
card->num_aux_devs,
GFP_KERNEL);
if (card->rtd_aux == NULL)
return -ENOMEM;
for (i = 0; i < card->num_aux_devs; i++)
card->rtd_aux[i].card = card;
INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dapm_dirty);
INIT_LIST_HEAD(&card->dobj_list); INIT_LIST_HEAD(&card->dobj_list);
card->instantiated = 0; card->instantiated = 0;
...@@ -2744,6 +2752,56 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) ...@@ -2744,6 +2752,56 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component)
} }
} }
/* Create a DAI and add it to the component's DAI list */
static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
bool legacy_dai_naming)
{
struct device *dev = component->dev;
struct snd_soc_dai *dai;
dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
if (dai == NULL)
return NULL;
/*
* Back in the old days when we still had component-less DAIs,
* instead of having a static name, component-less DAIs would
* inherit the name of the parent device so it is possible to
* register multiple instances of the DAI. We still need to keep
* the same naming style even though those DAIs are not
* component-less anymore.
*/
if (legacy_dai_naming &&
(dai_drv->id == 0 || dai_drv->name == NULL)) {
dai->name = fmt_single_name(dev, &dai->id);
} else {
dai->name = fmt_multiple_name(dev, dai_drv);
if (dai_drv->id)
dai->id = dai_drv->id;
else
dai->id = component->num_dai;
}
if (dai->name == NULL) {
kfree(dai);
return NULL;
}
dai->component = component;
dai->dev = dev;
dai->driver = dai_drv;
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
list_add(&dai->list, &component->dai_list);
component->num_dai++;
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
return dai;
}
/** /**
* snd_soc_register_dais - Register a DAI with the ASoC core * snd_soc_register_dais - Register a DAI with the ASoC core
* *
...@@ -2765,58 +2823,66 @@ static int snd_soc_register_dais(struct snd_soc_component *component, ...@@ -2765,58 +2823,66 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
component->dai_drv = dai_drv; component->dai_drv = dai_drv;
component->num_dai = count;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); dai = soc_add_dai(component, dai_drv + i,
count == 1 && legacy_dai_naming);
if (dai == NULL) { if (dai == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
}
/* return 0;
* Back in the old days when we still had component-less DAIs,
* instead of having a static name, component-less DAIs would
* inherit the name of the parent device so it is possible to
* register multiple instances of the DAI. We still need to keep
* the same naming style even though those DAIs are not
* component-less anymore.
*/
if (count == 1 && legacy_dai_naming &&
(dai_drv[i].id == 0 || dai_drv[i].name == NULL)) {
dai->name = fmt_single_name(dev, &dai->id);
} else {
dai->name = fmt_multiple_name(dev, &dai_drv[i]);
if (dai_drv[i].id)
dai->id = dai_drv[i].id;
else
dai->id = i;
}
if (dai->name == NULL) {
kfree(dai);
ret = -ENOMEM;
goto err;
}
dai->component = component; err:
dai->dev = dev; snd_soc_unregister_dais(component);
dai->driver = &dai_drv[i];
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
list_add(&dai->list, &component->dai_list); return ret;
}
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); /**
* snd_soc_register_dai - Register a DAI dynamically & create its widgets
*
* @component: The component the DAIs are registered for
* @dai_drv: DAI driver to use for the DAI
*
* Topology can use this API to register DAIs when probing a component.
* These DAIs's widgets will be freed in the card cleanup and the DAIs
* will be freed in the component cleanup.
*/
int snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv)
{
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
struct snd_soc_dai *dai;
int ret;
if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) {
dev_err(component->dev, "Invalid dai type %d\n",
dai_drv->dobj.type);
return -EINVAL;
} }
return 0; lockdep_assert_held(&client_mutex);
dai = soc_add_dai(component, dai_drv, false);
if (!dai)
return -ENOMEM;
err: /* Create the DAI widgets here. After adding DAIs, topology may
snd_soc_unregister_dais(component); * also add routes that need these widgets as source or sink.
*/
ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
if (ret != 0) {
dev_err(component->dev,
"Failed to create DAI widgets %d\n", ret);
}
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(snd_soc_register_dai);
static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm,
enum snd_soc_dapm_type type, int subseq) enum snd_soc_dapm_type type, int subseq)
......
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