Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81af7261 authored by Mark Brown's avatar Mark Brown
Browse files

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

parents 60955521 4b9c75ea
Loading
Loading
Loading
Loading
+110 −0
Original line number Diff line number Diff line
Renesas Sampling Rate Convert Sound Card:
ASoC simple SCU Sound Card

Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC <-> codec.
Simple-Card specifies audio DAI connections of SoC <-> codec.

Required properties:

- compatible				: "renesas,rsrc-card{,<board>}"
					  Examples with boards are:
					    - "renesas,rsrc-card"
					    - "renesas,rsrc-card,lager"
					    - "renesas,rsrc-card,koelsch"
- compatible				: "simple-scu-audio-card"
					  "renesas,rsrc-card"

Optional properties:

- card_name				: User specified audio sound card name, one string
- simple-audio-card,name		: User specified audio sound card name, one string
					  property.
- cpu					: CPU   sub-node
- codec					: CODEC sub-node
- simple-audio-card,cpu			: CPU   sub-node
- simple-audio-card,codec		: CODEC sub-node

Optional subnode properties:

- format				: CPU/CODEC common audio format.
- simple-audio-card,format		: CPU/CODEC common audio format.
					  "i2s", "right_j", "left_j" , "dsp_a"
					  "dsp_b", "ac97", "pdm", "msb", "lsb"
- frame-master				: Indicates dai-link frame master.
- simple-audio-card,frame-master	: Indicates dai-link frame master.
					  phandle to a cpu or codec subnode.
- bitclock-master			: Indicates dai-link bit clock master.
- simple-audio-card,bitclock-master	: Indicates dai-link bit clock master.
					  phandle to a cpu or codec subnode.
- bitclock-inversion			: bool property. Add this if the
- simple-audio-card,bitclock-inversion	: bool property. Add this if the
					  dai-link uses bit clock inversion.
- frame-inversion			: bool property. Add this if the
- simple-audio-card,frame-inversion	: bool property. Add this if the
					  dai-link uses frame clock inversion.
- convert-rate				: platform specified sampling rate convert
- convert-channels			: platform specified converted channel size (2 - 8 ch)
- audio-prefix				: see audio-routing
- audio-routing				: A list of the connections between audio components.
- simple-audio-card,convert-rate	: platform specified sampling rate convert
- simple-audio-card,convert-channels	: platform specified converted channel size (2 - 8 ch)
- simple-audio-card,prefix		: see audio-routing
- simple-audio-card,routing		: A list of the connections between audio components.
					  Each entry is a pair of strings, the first being the connection's sink,
					  the second being the connection's source. Valid names for sources.
					  use audio-prefix if some components is using same sink/sources naming.
@@ -54,22 +52,59 @@ Optional CPU/CODEC subnodes properties:
					  clk_disable_unprepare() in dai
					  shutdown().

Example
Example 1. Sampling Rate Covert

sound {
	compatible = "renesas,rsrc-card,lager";
	compatible = "simple-scu-audio-card";

	card-name = "rsnd-ak4643";
	format = "left_j";
	bitclock-master = <&sndcodec>;
	frame-master = <&sndcodec>;
	simple-audio-card,name = "rsnd-ak4643";
	simple-audio-card,format = "left_j";
	simple-audio-card,format = "left_j";
	simple-audio-card,bitclock-master = <&sndcodec>;
	simple-audio-card,frame-master = <&sndcodec>;

	sndcpu: cpu {
	simple-audio-card,convert-rate = <48000>; /* see audio_clk_a */

	simple-audio-card,prefix = "ak4642";
	simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
			"DAI0 Capture", "ak4642 Capture";

	sndcpu: simple-audio-card,cpu {
		sound-dai = <&rcar_sound>;
	};

	sndcodec: codec {
	sndcodec: simple-audio-card,codec {
		sound-dai = <&ak4643>;
		system-clock-frequency = <11289600>;
	};
};

Example 2. 2 CPU 1 Codec

sound {
	compatible = "renesas,rsrc-card";

	card-name = "rsnd-ak4643";
	format = "left_j";
	bitclock-master = <&dpcmcpu>;
	frame-master = <&dpcmcpu>;

	convert-rate = <48000>;  /* see audio_clk_a */

	audio-prefix = "ak4642";
	audio-routing = "ak4642 Playback", "DAI0 Playback",
			"ak4642 Playback", "DAI1 Playback";

	dpcmcpu: cpu@0 {
		sound-dai = <&rcar_sound 0>;
	};

	cpu@1 {
		sound-dai = <&rcar_sound 1>;
	};

	codec {
		sound-dai = <&ak4643>;
		clocks = <&audio_clock>;
	};
};
+34 −0
Original line number Diff line number Diff line
@@ -33,4 +33,38 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
				     char *prefix);

#define asoc_simple_card_parse_clk_cpu(node, dai_link, simple_dai)		\
	asoc_simple_card_parse_clk(node, dai_link->cpu_of_node, simple_dai)
#define asoc_simple_card_parse_clk_codec(node, dai_link, simple_dai)		\
	asoc_simple_card_parse_clk(node, dai_link->codec_of_node, simple_dai)
int asoc_simple_card_parse_clk(struct device_node *node,
			       struct device_node *dai_of_node,
			       struct asoc_simple_dai *simple_dai);

#define asoc_simple_card_parse_cpu(node, dai_link,				\
				   list_name, cells_name, is_single_link)	\
	asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node,		\
		&dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
#define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name)	\
	asoc_simple_card_parse_dai(node, &dai_link->codec_of_node,		\
		&dai_link->codec_dai_name, list_name, cells_name, NULL)
#define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name)	\
	asoc_simple_card_parse_dai(node, &dai_link->platform_of_node,		\
		NULL, list_name, cells_name, NULL)
int asoc_simple_card_parse_dai(struct device_node *node,
				  struct device_node **endpoint_np,
				  const char **dai_name,
				  const char *list_name,
				  const char *cells_name,
				  int *is_single_links);

int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
			      struct asoc_simple_dai *simple_dai);

int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link);
void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
				      int is_single_links);

int asoc_simple_card_clean_reference(struct snd_soc_card *card);

#endif /* __SIMPLE_CARD_CORE_H */
+8 −0
Original line number Diff line number Diff line
@@ -6,3 +6,11 @@ config SND_SIMPLE_CARD
	select SND_SIMPLE_CARD_UTILS
	help
	  This option enables generic simple sound card support

config SND_SIMPLE_SCU_CARD
	tristate "ASoC Simple SCU sound card support"
	depends on OF
	select SND_SIMPLE_CARD_UTILS
	help
	  This option enables generic simple SCU sound card support.
	  It supports DPCM of multi CPU single Codec system.
+2 −0
Original line number Diff line number Diff line
snd-soc-simple-card-utils-objs	:= simple-card-utils.o
snd-soc-simple-card-objs	:= simple-card.o
snd-soc-simple-scu-card-objs	:= simple-scu-card.o

obj-$(CONFIG_SND_SIMPLE_CARD_UTILS)	+= snd-soc-simple-card-utils.o
obj-$(CONFIG_SND_SIMPLE_CARD)		+= snd-soc-simple-card.o
obj-$(CONFIG_SND_SIMPLE_SCU_CARD)	+= snd-soc-simple-scu-card.o
+141 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <sound/simple_card_utils.h>
@@ -97,6 +98,146 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);

int asoc_simple_card_parse_clk(struct device_node *node,
			       struct device_node *dai_of_node,
			       struct asoc_simple_dai *simple_dai)
{
	struct clk *clk;
	u32 val;

	/*
	 * Parse dai->sysclk come from "clocks = <&xxx>"
	 * (if system has common clock)
	 *  or "system-clock-frequency = <xxx>"
	 *  or device's module clock.
	 */
	clk = of_clk_get(node, 0);
	if (!IS_ERR(clk)) {
		simple_dai->sysclk = clk_get_rate(clk);
		simple_dai->clk = clk;
	} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
		simple_dai->sysclk = val;
	} else {
		clk = of_clk_get(dai_of_node, 0);
		if (!IS_ERR(clk))
			simple_dai->sysclk = clk_get_rate(clk);
	}

	return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk);

int asoc_simple_card_parse_dai(struct device_node *node,
				    struct device_node **dai_of_node,
				    const char **dai_name,
				    const char *list_name,
				    const char *cells_name,
				    int *is_single_link)
{
	struct of_phandle_args args;
	int ret;

	if (!node)
		return 0;

	/*
	 * Get node via "sound-dai = <&phandle port>"
	 * it will be used as xxx_of_node on soc_bind_dai_link()
	 */
	ret = of_parse_phandle_with_args(node, list_name, cells_name, 0, &args);
	if (ret)
		return ret;

	/* Get dai->name */
	if (dai_name) {
		ret = snd_soc_of_get_dai_name(node, dai_name);
		if (ret < 0)
			return ret;
	}

	*dai_of_node = args.np;

	if (is_single_link)
		*is_single_link = !args.args_count;

	return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai);

int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
			      struct asoc_simple_dai *simple_dai)
{
	int ret;

	if (simple_dai->sysclk) {
		ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, 0);
		if (ret && ret != -ENOTSUPP) {
			dev_err(dai->dev, "simple-card: set_sysclk error\n");
			return ret;
		}
	}

	if (simple_dai->slots) {
		ret = snd_soc_dai_set_tdm_slot(dai,
					       simple_dai->tx_slot_mask,
					       simple_dai->rx_slot_mask,
					       simple_dai->slots,
					       simple_dai->slot_width);
		if (ret && ret != -ENOTSUPP) {
			dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
			return ret;
		}
	}

	return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);

int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
{
	if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
		return -EINVAL;

	/* Assumes platform == cpu */
	if (!dai_link->platform_of_node)
		dai_link->platform_of_node = dai_link->cpu_of_node;

	return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink);

void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
				       int is_single_links)
{
	/*
	 * In soc_bind_dai_link() will check cpu name after
	 * of_node matching if dai_link has cpu_dai_name.
	 * but, it will never match if name was created by
	 * fmt_single_name() remove cpu_dai_name if cpu_args
	 * was 0. See:
	 *	fmt_single_name()
	 *	fmt_multiple_name()
	 */
	if (is_single_links)
		dai_link->cpu_dai_name = NULL;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu);

int asoc_simple_card_clean_reference(struct snd_soc_card *card)
{
	struct snd_soc_dai_link *dai_link;
	int num_links;

	for (num_links = 0, dai_link = card->dai_link;
	     num_links < card->num_links;
	     num_links++, dai_link++) {
		of_node_put(dai_link->cpu_of_node);
		of_node_put(dai_link->codec_of_node);
	}
	return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);

/* Module information */
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
Loading