summaryrefslogtreecommitdiffstats
path: root/sound/soc/generic/simple-card-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/generic/simple-card-utils.c')
-rw-r--r--sound/soc/generic/simple-card-utils.c198
1 files changed, 189 insertions, 9 deletions
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 343b291fc372..26d64fa40c9c 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -10,8 +10,49 @@
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <sound/simple_card_utils.h>
+void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (data->convert_rate)
+ rate->min =
+ rate->max = data->convert_rate;
+
+ if (data->convert_channels)
+ channels->min =
+ channels->max = data->convert_channels;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
+
+void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+ struct asoc_simple_card_data *data)
+{
+ struct device_node *np = dev->of_node;
+ char prop[128];
+
+ if (!prefix)
+ prefix = "";
+
+ /* sampling rate convert */
+ snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
+ of_property_read_u32(np, prop, &data->convert_rate);
+
+ /* channels transfer */
+ snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
+ of_property_read_u32(np, prop, &data->convert_channels);
+
+ dev_dbg(dev, "convert_rate %d\n", data->convert_rate);
+ dev_dbg(dev, "convert_channels %d\n", data->convert_channels);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert);
+
int asoc_simple_card_parse_daifmt(struct device *dev,
struct device_node *node,
struct device_node *codec,
@@ -20,14 +61,13 @@ int asoc_simple_card_parse_daifmt(struct device *dev,
{
struct device_node *bitclkmaster = NULL;
struct device_node *framemaster = NULL;
- int prefix_len = prefix ? strlen(prefix) : 0;
unsigned int daifmt;
daifmt = snd_soc_of_parse_daifmt(node, prefix,
&bitclkmaster, &framemaster);
daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
- if (prefix_len && !bitclkmaster && !framemaster) {
+ if (!bitclkmaster && !framemaster) {
/*
* No dai-link level and master setting was not found from
* sound node level, revert back to legacy DT parsing and
@@ -51,6 +91,8 @@ int asoc_simple_card_parse_daifmt(struct device *dev,
*retfmt = daifmt;
+ dev_dbg(dev, "format : %04x\n", daifmt);
+
return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt);
@@ -72,6 +114,8 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
dai_link->name = name;
dai_link->stream_name = name;
+
+ dev_dbg(dev, "name : %s\n", name);
}
return ret;
@@ -81,27 +125,54 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name);
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
char *prefix)
{
- char prop[128];
int ret;
- snprintf(prop, sizeof(prop), "%sname", prefix);
+ if (!prefix)
+ prefix = "";
/* Parse the card name from DT */
- ret = snd_soc_of_parse_card_name(card, prop);
- if (ret < 0)
- return ret;
+ ret = snd_soc_of_parse_card_name(card, "label");
+ if (ret < 0) {
+ char prop[128];
+
+ snprintf(prop, sizeof(prop), "%sname", prefix);
+ ret = snd_soc_of_parse_card_name(card, prop);
+ if (ret < 0)
+ return ret;
+ }
if (!card->name && card->dai_link)
card->name = card->dai_link->name;
+ dev_dbg(card->dev, "Card Name: %s\n", card->name ? card->name : "");
+
return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
+static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
+ struct clk *clk)
+{
+ dai->clk = clk;
+}
+
+int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
+{
+ return clk_prepare_enable(dai->clk);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
+
+void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
+{
+ clk_disable_unprepare(dai->clk);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
+
int asoc_simple_card_parse_clk(struct device *dev,
struct device_node *node,
struct device_node *dai_of_node,
- struct asoc_simple_dai *simple_dai)
+ struct asoc_simple_dai *simple_dai,
+ const char *name)
{
struct clk *clk;
u32 val;
@@ -115,7 +186,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
clk = devm_get_clk_from_child(dev, node, NULL);
if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk);
- simple_dai->clk = clk;
+
+ asoc_simple_card_clk_register(simple_dai, clk);
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val;
} else {
@@ -124,6 +196,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
simple_dai->sysclk = clk_get_rate(clk);
}
+ dev_dbg(dev, "%s : sysclk = %d\n", name, simple_dai->sysclk);
+
return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk);
@@ -165,6 +239,71 @@ int asoc_simple_card_parse_dai(struct device_node *node,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai);
+static int asoc_simple_card_get_dai_id(struct device_node *ep)
+{
+ struct device_node *node;
+ struct device_node *endpoint;
+ int i, id;
+ int ret;
+
+ ret = snd_soc_get_dai_id(ep);
+ if (ret != -ENOTSUPP)
+ return ret;
+
+ node = of_graph_get_port_parent(ep);
+
+ /*
+ * Non HDMI sound case, counting port/endpoint on its DT
+ * is enough. Let's count it.
+ */
+ i = 0;
+ id = -1;
+ for_each_endpoint_of_node(node, endpoint) {
+ if (endpoint == ep)
+ id = i;
+ i++;
+ }
+ if (id < 0)
+ return -ENODEV;
+
+ return id;
+}
+
+int asoc_simple_card_parse_graph_dai(struct device_node *ep,
+ struct device_node **dai_of_node,
+ const char **dai_name)
+{
+ struct device_node *node;
+ struct of_phandle_args args;
+ int ret;
+
+ if (!ep)
+ return 0;
+ if (!dai_name)
+ return 0;
+
+ /*
+ * of_graph_get_port_parent() will call
+ * of_node_put(). So, call of_node_get() here
+ */
+ of_node_get(ep);
+ node = of_graph_get_port_parent(ep);
+
+ /* Get dai->name */
+ args.np = node;
+ args.args[0] = asoc_simple_card_get_dai_id(ep);
+ args.args_count = (of_graph_get_endpoint_count(node) > 1);
+
+ ret = snd_soc_get_dai_name(&args, dai_name);
+ if (ret < 0)
+ return ret;
+
+ *dai_of_node = node;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai);
+
int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
struct asoc_simple_dai *simple_dai)
{
@@ -236,6 +375,47 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
+int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
+ char *prefix,
+ int optional)
+{
+ struct device_node *node = card->dev->of_node;
+ char prop[128];
+
+ if (!prefix)
+ prefix = "";
+
+ snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
+
+ if (!of_property_read_bool(node, prop)) {
+ if (optional)
+ return 0;
+ return -EINVAL;
+ }
+
+ return snd_soc_of_parse_audio_routing(card, prop);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing);
+
+int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
+ char *prefix)
+{
+ struct device_node *node = card->dev->of_node;
+ char prop[128];
+
+ if (!prefix)
+ prefix = "";
+
+ snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
+
+ if (of_property_read_bool(node, prop))
+ return snd_soc_of_parse_audio_simple_widgets(card, prop);
+
+ /* no widgets is not error */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
+
/* Module information */
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");