diff mbox

[17/20] ASoC: rsnd: add Synchronous SRC mode

Message ID 87ioi183sc.wl%kuninori.morimoto.gx@renesas.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kuninori Morimoto Nov. 27, 2014, 8:07 a.m. UTC
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

Renesas R-Car sound SRC (= Sampling Rate Converter) has
Asynchronous/Synchronous SRC mode. Asynchronous mode is already
supported. This patch adds Synchronous mode.

The condition of enabling Synchronous mode are
 - SoC is clock master
 - sound uses SRC
 - sound is playback or sound is capture without DVC

amixer set "SRC Playback Sync Convert Rate" on
aplay xxx.wav &
amixer set "SRC Playback Sync Convert Rate" 44100

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 sound/soc/sh/rcar/src.c |  126 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 121 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index eede3ac..1482772 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -16,11 +16,13 @@  struct rsnd_src {
 	struct rsnd_src_platform_info *info; /* rcar_snd.h */
 	struct rsnd_mod mod;
 	struct clk *clk;
+	struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
+	struct rsnd_kctrl_cfg_s sync; /* sync convert */
 };
 
 #define RSND_SRC_NAME_SIZE 16
 
-#define rsnd_src_convert_rate(p) ((p)->info->convert_rate)
+#define rsnd_enable_sync_convert(src) ((src)->sen.val)
 #define rsnd_mod_to_src(_mod)				\
 	container_of((_mod), struct rsnd_src, mod)
 #define rsnd_src_dma_available(src) \
@@ -216,6 +218,30 @@  int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
 	return 0;
 }
 
+u32 rsnd_src_convert_rate(struct rsnd_src *src)
+{
+	struct rsnd_mod *mod = &src->mod;
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	u32 convert_rate;
+
+	if (!runtime)
+		return 0;
+
+	if (!rsnd_enable_sync_convert(src))
+		return src->info->convert_rate;
+
+	convert_rate = src->sync.val;
+
+	if (!convert_rate)
+		convert_rate = src->info->convert_rate;
+
+	if (!convert_rate)
+		convert_rate = runtime->rate;
+
+	return convert_rate;
+}
+
 unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
 				   struct rsnd_dai_stream *io,
 				   struct snd_pcm_runtime *runtime)
@@ -280,6 +306,9 @@  static int rsnd_src_init(struct rsnd_mod *mod,
 
 	clk_prepare_enable(src->clk);
 
+	/* reset sync convert_rate */
+	src->sync.val = 0;
+
 	/*
 	 * Initialize the operation of the SRC internal circuits
 	 * see rsnd_src_start()
@@ -296,6 +325,9 @@  static int rsnd_src_quit(struct rsnd_mod *mod,
 
 	clk_disable_unprepare(src->clk);
 
+	/* reset sync convert_rate */
+	src->sync.val = 0;
+
 	return 0;
 }
 
@@ -519,6 +551,7 @@  static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	u32 convert_rate = rsnd_src_convert_rate(src);
+	u32 cr, route;
 	uint ratio;
 	int ret;
 
@@ -539,13 +572,21 @@  static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
 	if (ret < 0)
 		return ret;
 
-	rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
-
+	cr	= 0x00011110;
+	route	= 0x0;
 	if (convert_rate) {
-		/* Gen1/Gen2 are not compatible */
-		rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+		route	= 0x1;
+
+		if (rsnd_enable_sync_convert(src)) {
+			cr |= 0x1;
+			route |= rsnd_dai_is_play(rdai, io) ?
+				(0x1 << 24) : (0x1 << 25);
+		}
 	}
 
+	rsnd_mod_write(mod, SRC_SRCCR, cr);
+	rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+
 	switch (rsnd_mod_id(mod)) {
 	case 5:
 	case 6:
@@ -658,6 +699,80 @@  static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
 	return rsnd_src_stop(mod);
 }
 
+static void rsnd_src_reconvert_update(struct rsnd_mod *mod)
+{
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	struct rsnd_src *src = rsnd_mod_to_src(mod);
+	u32 convert_rate = rsnd_src_convert_rate(src);
+	u32 fsrate = 0;
+
+	if (!rsnd_enable_sync_convert(src))
+		return;
+
+	if (!convert_rate)
+		return;
+
+	fsrate = 0x0400000 / convert_rate * runtime->rate;
+
+	/* update IFS */
+	rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+}
+
+static int rsnd_src_pcm_new(struct rsnd_mod *mod,
+			    struct rsnd_dai *rdai,
+			    struct snd_soc_pcm_runtime *rtd)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct rsnd_src *src = rsnd_mod_to_src(mod);
+	int ret;
+
+	/*
+	 * enable SRC sync convert if possible
+	 */
+
+	/*
+	 * Gen1 is not supported
+	 */
+	if (rsnd_is_gen1(priv))
+		return 0;
+
+	/*
+	 * SRC sync convert needs clock master
+	 */
+	if (!rsnd_dai_is_clk_master(rdai))
+		return 0;
+
+	/*
+	 * We can't use SRC sync convert
+	 * if it has DVC
+	 */
+	if (rsnd_io_to_mod_dvc(io))
+		return 0;
+
+	/*
+	 * enable sync convert
+	 */
+	ret = rsnd_kctrl_new_s(mod, rdai, rtd,
+			       rsnd_dai_is_play(rdai, io) ?
+			       "SRC Playback Sync Convert Rate Switch" :
+			       "SRC Capture Sync Convert Rate Switch",
+			       rsnd_src_reconvert_update,
+			       &src->sen, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = rsnd_kctrl_new_s(mod, rdai, rtd,
+			       rsnd_dai_is_play(rdai, io) ?
+			       "SRC Playback Sync Convert Rate" :
+			       "SRC Capture Sync Convert Rate",
+			       rsnd_src_reconvert_update,
+			       &src->sync, 192000);
+
+	return ret;
+}
+
 static struct rsnd_mod_ops rsnd_src_gen2_ops = {
 	.name	= SRC_NAME,
 	.probe	= rsnd_src_probe_gen2,
@@ -666,6 +781,7 @@  static struct rsnd_mod_ops rsnd_src_gen2_ops = {
 	.quit	= rsnd_src_quit,
 	.start	= rsnd_src_start_gen2,
 	.stop	= rsnd_src_stop_gen2,
+	.pcm_new = rsnd_src_pcm_new,
 };
 
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)