Commit d20b09f0 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/component' into asoc-next

parents 2fc175c4 cb470087
......@@ -13,6 +13,7 @@
#ifndef __LINUX_SND_SOC_H
#define __LINUX_SND_SOC_H
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/notifier.h>
......@@ -670,6 +671,26 @@ struct snd_soc_cache_ops {
int (*sync)(struct snd_soc_codec *codec);
};
/* component interface */
struct snd_soc_component_driver {
const char *name;
/* DT */
int (*of_xlate_dai_name)(struct snd_soc_component *component,
struct of_phandle_args *args,
const char **dai_name);
};
struct snd_soc_component {
const char *name;
int id;
int num_dai;
struct device *dev;
struct list_head list;
const struct snd_soc_component_driver *driver;
};
/* SoC Audio Codec device */
struct snd_soc_codec {
const char *name;
......@@ -715,6 +736,9 @@ struct snd_soc_codec {
struct mutex cache_rw_mutex;
int val_bytes;
/* component */
struct snd_soc_component component;
/* dapm */
struct snd_soc_dapm_context dapm;
unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
......@@ -733,6 +757,7 @@ struct snd_soc_codec_driver {
int (*remove)(struct snd_soc_codec *);
int (*suspend)(struct snd_soc_codec *);
int (*resume)(struct snd_soc_codec *);
struct snd_soc_component_driver component_driver;
/* Default control and setup, added after probe() is run */
const struct snd_kcontrol_new *controls;
......@@ -849,20 +874,6 @@ struct snd_soc_platform {
#endif
};
struct snd_soc_component_driver {
const char *name;
};
struct snd_soc_component {
const char *name;
int id;
int num_dai;
struct device *dev;
struct list_head list;
const struct snd_soc_component_driver *driver;
};
struct snd_soc_dai_link {
/* config - must be set by machine driver */
const char *name; /* Codec name */
......@@ -1201,6 +1212,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
const char *prefix);
int snd_soc_of_get_dai_name(struct device_node *of_node,
const char **dai_name);
#include <sound/soc-dai.h>
......
......@@ -4035,6 +4035,112 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count)
snd_soc_unregister_dai(dev);
}
/**
* snd_soc_register_component - Register a component with the ASoC core
*
*/
static int
__snd_soc_register_component(struct device *dev,
struct snd_soc_component *cmpnt,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai, bool allow_single_dai)
{
int ret;
dev_dbg(dev, "component register %s\n", dev_name(dev));
if (!cmpnt) {
dev_err(dev, "ASoC: Failed to connecting component\n");
return -ENOMEM;
}
cmpnt->name = fmt_single_name(dev, &cmpnt->id);
if (!cmpnt->name) {
dev_err(dev, "ASoC: Failed to simplifying name\n");
return -ENOMEM;
}
cmpnt->dev = dev;
cmpnt->driver = cmpnt_drv;
cmpnt->num_dai = num_dai;
/*
* snd_soc_register_dai() uses fmt_single_name(), and
* snd_soc_register_dais() uses fmt_multiple_name()
* for dai->name which is used for name based matching
*
* this function is used from cpu/codec.
* allow_single_dai flag can ignore "codec" driver reworking
* since it had been used snd_soc_register_dais(),
*/
if ((1 == num_dai) && allow_single_dai)
ret = snd_soc_register_dai(dev, dai_drv);
else
ret = snd_soc_register_dais(dev, dai_drv, num_dai);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
goto error_component_name;
}
mutex_lock(&client_mutex);
list_add(&cmpnt->list, &component_list);
mutex_unlock(&client_mutex);
dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name);
return ret;
error_component_name:
kfree(cmpnt->name);
return ret;
}
int snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
struct snd_soc_component *cmpnt;
cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL);
if (!cmpnt) {
dev_err(dev, "ASoC: Failed to allocate memory\n");
return -ENOMEM;
}
return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
dai_drv, num_dai, true);
}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
/**
* snd_soc_unregister_component - Unregister a component from the ASoC core
*
*/
void snd_soc_unregister_component(struct device *dev)
{
struct snd_soc_component *cmpnt;
list_for_each_entry(cmpnt, &component_list, list) {
if (dev == cmpnt->dev)
goto found;
}
return;
found:
snd_soc_unregister_dais(dev, cmpnt->num_dai);
mutex_lock(&client_mutex);
list_del(&cmpnt->list);
mutex_unlock(&client_mutex);
dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
kfree(cmpnt->name);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
/**
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
......@@ -4257,10 +4363,12 @@ int snd_soc_register_codec(struct device *dev,
list_add(&codec->list, &codec_list);
mutex_unlock(&client_mutex);
/* register any DAIs */
ret = snd_soc_register_dais(dev, dai_drv, num_dai);
/* register component */
ret = __snd_soc_register_component(dev, &codec->component,
&codec_drv->component_driver,
dai_drv, num_dai, false);
if (ret < 0) {
dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret);
dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret);
goto fail_codec_name;
}
......@@ -4295,7 +4403,7 @@ void snd_soc_unregister_codec(struct device *dev)
return;
found:
snd_soc_unregister_dais(dev, codec->num_dai);
snd_soc_unregister_component(dev);
mutex_lock(&client_mutex);
list_del(&codec->list);
......@@ -4310,92 +4418,6 @@ void snd_soc_unregister_codec(struct device *dev)
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
/**
* snd_soc_register_component - Register a component with the ASoC core
*
*/
int snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
struct snd_soc_component *cmpnt;
int ret;
dev_dbg(dev, "component register %s\n", dev_name(dev));
cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL);
if (!cmpnt) {
dev_err(dev, "ASoC: Failed to allocate memory\n");
return -ENOMEM;
}
cmpnt->name = fmt_single_name(dev, &cmpnt->id);
if (!cmpnt->name) {
dev_err(dev, "ASoC: Failed to simplifying name\n");
return -ENOMEM;
}
cmpnt->dev = dev;
cmpnt->driver = cmpnt_drv;
cmpnt->num_dai = num_dai;
/*
* snd_soc_register_dai() uses fmt_single_name(), and
* snd_soc_register_dais() uses fmt_multiple_name()
* for dai->name which is used for name based matching
*/
if (1 == num_dai)
ret = snd_soc_register_dai(dev, dai_drv);
else
ret = snd_soc_register_dais(dev, dai_drv, num_dai);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
goto error_component_name;
}
mutex_lock(&client_mutex);
list_add(&cmpnt->list, &component_list);
mutex_unlock(&client_mutex);
dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name);
return ret;
error_component_name:
kfree(cmpnt->name);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
/**
* snd_soc_unregister_component - Unregister a component from the ASoC core
*
*/
void snd_soc_unregister_component(struct device *dev)
{
struct snd_soc_component *cmpnt;
list_for_each_entry(cmpnt, &component_list, list) {
if (dev == cmpnt->dev)
goto found;
}
return;
found:
snd_soc_unregister_dais(dev, cmpnt->num_dai);
mutex_lock(&client_mutex);
list_del(&cmpnt->list);
mutex_unlock(&client_mutex);
dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
kfree(cmpnt->name);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
/* Retrieve a card's name from device tree */
int snd_soc_of_parse_card_name(struct snd_soc_card *card,
const char *propname)
......@@ -4583,6 +4605,41 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
int snd_soc_of_get_dai_name(struct device_node *of_node,
const char **dai_name)
{
struct snd_soc_component *pos;
struct of_phandle_args args;
int ret;
ret = of_parse_phandle_with_args(of_node, "sound-dai",
"#sound-dai-cells", 0, &args);
if (ret)
return ret;
ret = -EPROBE_DEFER;
mutex_lock(&client_mutex);
list_for_each_entry(pos, &component_list, list) {
if (pos->dev->of_node != args.np)
continue;
if (!pos->driver->of_xlate_dai_name) {
ret = -ENOSYS;
break;
}
ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name);
break;
}
mutex_unlock(&client_mutex);
of_node_put(args.np);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
static int __init snd_soc_init(void)
{
#ifdef CONFIG_DEBUG_FS
......
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