aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r--sound/soc/soc-core.c295
1 files changed, 215 insertions, 80 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index dcf6be4c4aaa..12a82f5a3ff6 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -72,7 +72,7 @@ static ssize_t pmdown_time_show(struct device *dev,
{
struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
- return sprintf(buf, "%ld\n", rtd->pmdown_time);
+ return sysfs_emit(buf, "%ld\n", rtd->pmdown_time);
}
static ssize_t pmdown_time_store(struct device *dev,
@@ -107,7 +107,7 @@ static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
if (attr == &dev_attr_pmdown_time.attr)
return attr->mode; /* always visible */
- return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */
+ return rtd->dai_link->num_codecs ? attr->mode : 0; /* enabled only with codec */
}
static const struct attribute_group soc_dapm_dev_group = {
@@ -482,11 +482,10 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
* asoc_rtd_to_cpu()
* asoc_rtd_to_codec()
*/
- rtd->num_cpus = dai_link->num_cpus;
- rtd->num_codecs = dai_link->num_codecs;
rtd->card = card;
rtd->dai_link = dai_link;
rtd->num = card->num_rtd++;
+ rtd->pmdown_time = pmdown_time; /* default power off timeout */
/* see for_each_card_rtds */
list_add_tail(&rtd->list, &card->rtd_list);
@@ -1214,7 +1213,6 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
- unsigned int inv_dai_fmt;
unsigned int i;
int ret;
@@ -1227,18 +1225,11 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- /*
- * Flip the polarity for the "CPU" end of a CODEC<->CODEC link
- */
- inv_dai_fmt = snd_soc_daifmt_clock_provider_fliped(dai_fmt);
+ /* Flip the polarity for the "CPU" end of link */
+ dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- unsigned int fmt = dai_fmt;
-
- if (snd_soc_component_is_codec(cpu_dai->component))
- fmt = inv_dai_fmt;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret != 0 && ret != -ENOTSUPP)
return ret;
}
@@ -1255,9 +1246,6 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_component *component;
int ret, num, i;
- /* set default power off timeout */
- rtd->pmdown_time = pmdown_time;
-
/* do machine specific initialization */
ret = snd_soc_link_init(rtd);
if (ret < 0)
@@ -1848,21 +1836,22 @@ match:
}
}
-#define soc_setup_card_name(name, name1, name2, norm) \
- __soc_setup_card_name(name, sizeof(name), name1, name2, norm)
-static void __soc_setup_card_name(char *name, int len,
- const char *name1, const char *name2,
- int normalization)
+#define soc_setup_card_name(card, name, name1, name2) \
+ __soc_setup_card_name(card, name, sizeof(name), name1, name2)
+static void __soc_setup_card_name(struct snd_soc_card *card,
+ char *name, int len,
+ const char *name1, const char *name2)
{
+ const char *src = name1 ? name1 : name2;
int i;
- snprintf(name, len, "%s", name1 ? name1 : name2);
+ snprintf(name, len, "%s", src);
- if (!normalization)
+ if (name != card->snd_card->driver)
return;
/*
- * Name normalization
+ * Name normalization (driver field)
*
* The driver name is somewhat special, as it's used as a key for
* searches in the user-space.
@@ -1882,6 +1871,14 @@ static void __soc_setup_card_name(char *name, int len,
break;
}
}
+
+ /*
+ * The driver field should contain a valid string from the user view.
+ * The wrapping usually does not work so well here. Set a smaller string
+ * in the specific ASoC driver.
+ */
+ if (strlen(src) > len - 1)
+ dev_err(card->dev, "ASoC: driver name too long '%s' -> '%s'\n", src, name);
}
static void soc_cleanup_card_resources(struct snd_soc_card *card)
@@ -2049,12 +2046,12 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
/* try to set some sane longname if DMI is available */
snd_soc_set_dmi_name(card, NULL);
- soc_setup_card_name(card->snd_card->shortname,
- card->name, NULL, 0);
- soc_setup_card_name(card->snd_card->longname,
- card->long_name, card->name, 0);
- soc_setup_card_name(card->snd_card->driver,
- card->driver_name, card->name, 1);
+ soc_setup_card_name(card, card->snd_card->shortname,
+ card->name, NULL);
+ soc_setup_card_name(card, card->snd_card->longname,
+ card->long_name, card->name);
+ soc_setup_card_name(card, card->snd_card->driver,
+ card->driver_name, card->name);
if (card->components) {
/* the current implementation of snd_component_add() accepts */
@@ -2074,6 +2071,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
goto probe_end;
snd_soc_dapm_new_widgets(card);
+ snd_soc_card_fixup_controls(card);
ret = snd_card_register(card->snd_card);
if (ret < 0) {
@@ -2315,7 +2313,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
mutex_init(&card->mutex);
mutex_init(&card->dapm_mutex);
mutex_init(&card->pcm_mutex);
- spin_lock_init(&card->dpcm_lock);
return snd_soc_bind_card(card);
}
@@ -2327,14 +2324,12 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
* @card: Card to unregister
*
*/
-int snd_soc_unregister_card(struct snd_soc_card *card)
+void snd_soc_unregister_card(struct snd_soc_card *card)
{
mutex_lock(&client_mutex);
snd_soc_unbind_card(card, true);
mutex_unlock(&client_mutex);
dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
-
- return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
@@ -2466,6 +2461,7 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
return dai;
}
+EXPORT_SYMBOL_GPL(snd_soc_register_dai);
/**
* snd_soc_unregister_dais - Unregister DAIs from the ASoC core
@@ -2497,7 +2493,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
for (i = 0; i < count; i++) {
dai = snd_soc_register_dai(component, dai_drv + i, count == 1 &&
- !snd_soc_component_is_codec(component));
+ component->driver->legacy_dai_naming);
if (dai == NULL) {
ret = -ENOMEM;
goto err;
@@ -2587,6 +2583,11 @@ int snd_soc_component_initialize(struct snd_soc_component *component,
component->dev = dev;
component->driver = driver;
+#ifdef CONFIG_DEBUG_FS
+ if (!component->debugfs_prefix)
+ component->debugfs_prefix = driver->debugfs_prefix;
+#endif
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_component_initialize);
@@ -2758,6 +2759,11 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
"ASoC: Property '%s' does not exist\n", propname);
return -EINVAL;
}
+ if (!num_widgets) {
+ dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
+ propname);
+ return -EINVAL;
+ }
if (num_widgets & 1) {
dev_err(card->dev,
"ASoC: Property '%s' length is not even\n", propname);
@@ -2765,11 +2771,6 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
}
num_widgets /= 2;
- if (!num_widgets) {
- dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
- propname);
- return -EINVAL;
- }
widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
GFP_KERNEL);
@@ -2824,6 +2825,56 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
+int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop)
+{
+ const unsigned int nb_controls_max = 16;
+ const char **strings, *control_name;
+ struct snd_kcontrol_new *controls;
+ struct device *dev = card->dev;
+ unsigned int i, nb_controls;
+ int ret;
+
+ if (!of_property_read_bool(dev->of_node, prop))
+ return 0;
+
+ strings = devm_kcalloc(dev, nb_controls_max,
+ sizeof(*strings), GFP_KERNEL);
+ if (!strings)
+ return -ENOMEM;
+
+ ret = of_property_read_string_array(dev->of_node, prop,
+ strings, nb_controls_max);
+ if (ret < 0)
+ return ret;
+
+ nb_controls = (unsigned int)ret;
+
+ controls = devm_kcalloc(dev, nb_controls,
+ sizeof(*controls), GFP_KERNEL);
+ if (!controls)
+ return -ENOMEM;
+
+ for (i = 0; i < nb_controls; i++) {
+ control_name = devm_kasprintf(dev, GFP_KERNEL,
+ "%s Switch", strings[i]);
+ if (!control_name)
+ return -ENOMEM;
+
+ controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ controls[i].name = control_name;
+ controls[i].info = snd_soc_dapm_info_pin_switch;
+ controls[i].get = snd_soc_dapm_get_pin_switch;
+ controls[i].put = snd_soc_dapm_put_pin_switch;
+ controls[i].private_value = (unsigned long)strings[i];
+ }
+
+ card->controls = controls;
+ card->num_controls = nb_controls;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_pin_switches);
+
int snd_soc_of_get_slot_mask(struct device_node *np,
const char *prop_name,
unsigned int *mask)
@@ -2980,7 +3031,7 @@ int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname)
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_aux_devs);
-unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt)
+unsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt)
{
unsigned int inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
@@ -3001,7 +3052,7 @@ unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt)
return inv_dai_fmt;
}
-EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_fliped);
+EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_flipped);
unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame)
{
@@ -3184,7 +3235,7 @@ int snd_soc_get_dai_name(const struct of_phandle_args *args,
for_each_component(pos) {
struct device_node *component_of_node = soc_component_to_node(pos);
- if (component_of_node != args->np)
+ if (component_of_node != args->np || !pos->num_dai)
continue;
ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name);
@@ -3257,6 +3308,61 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
}
EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
+static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component)
+{
+ if (component->of_node) {
+ of_node_put(component->of_node);
+ component->of_node = NULL;
+ }
+}
+
+static int __snd_soc_of_get_dai_link_component_alloc(
+ struct device *dev, struct device_node *of_node,
+ struct snd_soc_dai_link_component **ret_component,
+ int *ret_num)
+{
+ struct snd_soc_dai_link_component *component;
+ int num;
+
+ /* Count the number of CPUs/CODECs */
+ num = of_count_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells");
+ if (num <= 0) {
+ if (num == -ENOENT)
+ dev_err(dev, "No 'sound-dai' property\n");
+ else
+ dev_err(dev, "Bad phandle in 'sound-dai'\n");
+ return num;
+ }
+ component = devm_kcalloc(dev, num, sizeof(*component), GFP_KERNEL);
+ if (!component)
+ return -ENOMEM;
+
+ *ret_component = component;
+ *ret_num = num;
+
+ return 0;
+}
+
+static int __snd_soc_of_get_dai_link_component_parse(
+ struct device_node *of_node,
+ struct snd_soc_dai_link_component *component, int index)
+{
+ struct of_phandle_args args;
+ int ret;
+
+ ret = of_parse_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells",
+ index, &args);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_get_dai_name(&args, &component->dai_name);
+ if (ret < 0)
+ return ret;
+
+ component->of_node = args.np;
+ return 0;
+}
+
/*
* snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
* @dai_link: DAI link
@@ -3268,12 +3374,8 @@ void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
struct snd_soc_dai_link_component *component;
int index;
- for_each_link_codecs(dai_link, index, component) {
- if (!component->of_node)
- break;
- of_node_put(component->of_node);
- component->of_node = NULL;
- }
+ for_each_link_codecs(dai_link, index, component)
+ __snd_soc_of_put_component(component);
}
EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs);
@@ -3295,41 +3397,19 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
struct device_node *of_node,
struct snd_soc_dai_link *dai_link)
{
- struct of_phandle_args args;
struct snd_soc_dai_link_component *component;
- char *name;
- int index, num_codecs, ret;
-
- /* Count the number of CODECs */
- name = "sound-dai";
- num_codecs = of_count_phandle_with_args(of_node, name,
- "#sound-dai-cells");
- if (num_codecs <= 0) {
- if (num_codecs == -ENOENT)
- dev_err(dev, "No 'sound-dai' property\n");
- else
- dev_err(dev, "Bad phandle in 'sound-dai'\n");
- return num_codecs;
- }
- component = devm_kcalloc(dev,
- num_codecs, sizeof(*component),
- GFP_KERNEL);
- if (!component)
- return -ENOMEM;
- dai_link->codecs = component;
- dai_link->num_codecs = num_codecs;
+ int index, ret;
+
+ ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node,
+ &dai_link->codecs, &dai_link->num_codecs);
+ if (ret < 0)
+ return ret;
/* Parse the list */
for_each_link_codecs(dai_link, index, component) {
- ret = of_parse_phandle_with_args(of_node, name,
- "#sound-dai-cells",
- index, &args);
+ ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index);
if (ret)
goto err;
- component->of_node = args.np;
- ret = snd_soc_get_dai_name(&args, &component->dai_name);
- if (ret < 0)
- goto err;
}
return 0;
err:
@@ -3340,6 +3420,61 @@ err:
}
EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
+/*
+ * snd_soc_of_put_dai_link_cpus - Dereference device nodes in the codecs array
+ * @dai_link: DAI link
+ *
+ * Dereference device nodes acquired by snd_soc_of_get_dai_link_cpus().
+ */
+void snd_soc_of_put_dai_link_cpus(struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_dai_link_component *component;
+ int index;
+
+ for_each_link_cpus(dai_link, index, component)
+ __snd_soc_of_put_component(component);
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_cpus);
+
+/*
+ * snd_soc_of_get_dai_link_cpus - Parse a list of CPU DAIs in the devicetree
+ * @dev: Card device
+ * @of_node: Device node
+ * @dai_link: DAI link
+ *
+ * Is analogous to snd_soc_of_get_dai_link_codecs but parses a list of CPU DAIs
+ * instead.
+ *
+ * Returns 0 for success
+ */
+int snd_soc_of_get_dai_link_cpus(struct device *dev,
+ struct device_node *of_node,
+ struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_dai_link_component *component;
+ int index, ret;
+
+ /* Count the number of CPUs */
+ ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node,
+ &dai_link->cpus, &dai_link->num_cpus);
+ if (ret < 0)
+ return ret;
+
+ /* Parse the list */
+ for_each_link_cpus(dai_link, index, component) {
+ ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index);
+ if (ret)
+ goto err;
+ }
+ return 0;
+err:
+ snd_soc_of_put_dai_link_cpus(dai_link);
+ dai_link->cpus = NULL;
+ dai_link->num_cpus = 0;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_cpus);
+
static int __init snd_soc_init(void)
{
snd_soc_debugfs_init();