ASoC: Make aux_dev more like a generic component
aux_dev is mainly used by the machine driver to specify analog devices, which are registered as codecs. Making it more like a generic component can help the machine driver to use it to specify any component with topology info by name. Details: - Remove the stub 'rtd_aux' array from the soc card. - Add a list 'aux_comp_list' to store the components of aux_devs. And add a list head 'list_aux' to struct snd_soc_component, for adding such components to the above list. - Add a 'init' ops to a component for machine specific init. soc_bind_aux_dev() will set it to be aux_dev's init. And it will be called when probing the component. - soc_bind_aux_dev() will also search components by name of an aux_dev, since it may not be a codec. - Move probing of aux_devs before checking new DAI links brought by topology. - Move removal of aux_devs later than removal of links. Because topology of aux components may register DAIs and the DAI drivers will go with removal of the aux components, we want soc_remove_link_dais() to remove the DAIs at first. Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Родитель
68003e6cf2
Коммит
f2ed6b0764
|
@ -787,6 +787,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;
|
||||||
|
@ -830,6 +831,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;
|
||||||
|
@ -1130,8 +1134,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;
|
||||||
|
@ -1537,6 +1540,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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
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;
|
||||||
|
struct device_node *codec_of_node;
|
||||||
|
|
||||||
rtd->component = soc_find_component(aux_dev->codec_of_node, name);
|
if (aux_dev->codec_of_node || aux_dev->codec_name) {
|
||||||
if (!rtd->component) {
|
/* codecs, usually analog devices */
|
||||||
if (aux_dev->codec_of_node)
|
name = aux_dev->codec_name;
|
||||||
name = of_node_full_name(aux_dev->codec_of_node);
|
codec_of_node = aux_dev->codec_of_node;
|
||||||
|
component = soc_find_component(codec_of_node, name);
|
||||||
dev_err(card->dev, "ASoC: %s not registered\n", name);
|
if (!component) {
|
||||||
return -EPROBE_DEFER;
|
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
|
return 0;
|
||||||
* have been removed, this code can be removed as well.
|
|
||||||
*/
|
err_defer:
|
||||||
rtd->codec = rtd->component->codec;
|
dev_err(card->dev, "ASoC: %s not registered\n", name);
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int soc_probe_aux_devices(struct snd_soc_card *card)
|
||||||
|
{
|
||||||
|
struct snd_soc_component *comp;
|
||||||
|
int order;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
|
||||||
|
order++) {
|
||||||
|
list_for_each_entry(comp, &card->aux_comp_list, list_aux) {
|
||||||
|
if (comp->driver->probe_order == order) {
|
||||||
|
ret = soc_probe_component(card, comp);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(card->dev,
|
||||||
|
"ASoC: failed to probe aux component %s %d\n",
|
||||||
|
comp->name, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int soc_probe_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_aux_dev *aux_dev = &card->aux_dev[num];
|
int order;
|
||||||
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_safe(comp, _comp,
|
||||||
|
&card->aux_comp_list, list_aux) {
|
||||||
/* do machine specific initialization */
|
if (comp->driver->remove_order == order) {
|
||||||
if (aux_dev->init) {
|
soc_remove_component(comp);
|
||||||
ret = aux_dev->init(rtd->component);
|
/* remove it from the card's aux_comp_list */
|
||||||
if (ret < 0) {
|
list_del(&comp->list_aux);
|
||||||
dev_err(card->dev, "ASoC: failed to init %s: %d\n",
|
}
|
||||||
aux_dev->name, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return soc_post_component_init(rtd, aux_dev->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
|
|
||||||
struct snd_soc_component *component = rtd->component;
|
|
||||||
|
|
||||||
/* unregister the rtd device */
|
|
||||||
if (rtd->dev_registered) {
|
|
||||||
device_unregister(rtd->dev);
|
|
||||||
rtd->dev_registered = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче