diff options
Diffstat (limited to 'sound/soc/generic/simple-card-utils.c')
-rw-r--r-- | sound/soc/generic/simple-card-utils.c | 198 |
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"); |