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 --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)