From 4715219ecef50cf79d7784545bf5bb4664bb800d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:23:08 +0000 Subject: ASoC: rsnd: remove un-needed parameter from rsnd_dma_init() It can get DMA direction via rsnd_dai_stream. Remove un-needed is_play from rsnd_dma_init(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 81c182b4bad5..7fb879871a8e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -713,7 +713,6 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, ret = rsnd_dma_init(priv, rsnd_mod_to_dma(mod), - rsnd_info_is_playback(priv, src), src->info->dma_id); if (ret) goto rsnd_src_probe_gen2_fail; -- cgit v1.2.1 From 9c706ab29f33b9562f570d1e99e21955d898dc85 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:23:39 +0000 Subject: ASoC: rsnd: remove unused rsnd_dma_available() rsnd_dma_available() is not used. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 7fb879871a8e..f12c8b3aa475 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -30,8 +30,6 @@ struct rsnd_src { #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) -#define rsnd_src_dma_available(src) \ - rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod)) #define for_each_rsnd_src(pos, priv, i) \ for ((i) = 0; \ -- cgit v1.2.1 From 8a2ff4262ca611c38b31fec0af65be656d934f52 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:24:06 +0000 Subject: ASoC: rsnd: remove un-needed parameter from rsnd_dma_quit() priv is not used on rsnd_dma_quit() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index f12c8b3aa475..e2792056ce24 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -730,7 +730,7 @@ rsnd_src_probe_gen2_fail: static int rsnd_src_remove_gen2(struct rsnd_mod *mod, struct rsnd_priv *priv) { - rsnd_dma_quit(priv, rsnd_mod_to_dma(mod)); + rsnd_dma_quit(rsnd_mod_to_dma(mod)); return 0; } -- cgit v1.2.1 From 82e76ed38edbdb338d64f5f2486fcd1482c8859a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:30:22 +0000 Subject: ASoC: rsnd: src: add rsnd_src_of_node() This patch adds rsnd_src_of_node() to get SRC subnode from DT. This is prepare for new DT bindings for 1st DMAC Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index e2792056ce24..5a601bed4154 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -28,6 +28,9 @@ struct rsnd_src { #define RSND_SRC_NAME_SIZE 16 #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) +#define rsnd_src_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") + #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) @@ -807,7 +810,7 @@ static void rsnd_of_parse_src(struct platform_device *pdev, if (!of_data) return; - src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); + src_node = rsnd_src_of_node(priv); if (!src_node) return; -- cgit v1.2.1 From 72adc61f4637aa3596c1db1129f84d768475a885 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:31:23 +0000 Subject: ASoC: rsnd: 1st DMAC dma-names cares subnode Renesas R-Car sound (= rsnd) needs 2 DMAC which are called as Audio DMAC (= 1st DMAC) and Audio DMAC peri peri (2nd DMAC). And rsnd had assumed that 1st / 2nd DMACs are implemented as DMAEngine. But, in result of DMA ML discussion, 2nd DMAC was concluded that it is not a general purpose DMAC (2nd DMAC is for Device to Device inside sound system). Additionally, current DMAEngine can't support Device to Device, and we don't have correct DT bindings for it at this point. So the easiest solution for it is that move it from DMAEngine to rsnd driver. dma-names on DT was implemented as no difference between 1st / 2nd DMAC's, since rsnd had assumed that both DMACs are implemented as DMAEngine. That style was "src_dst". But now, 2nd DMAC was implemented as non DMAEngine, and it doesn't need dma-names anymore. So, this dma-names rule is no longer needed. And additionally, dma-names was assumed that it has all (= SSI/SSIU/SRC/DVC) nodes under sound node. In upstream code, no SoC/platform is supporting DMA for rsnd driver yet. This means there is no compatible issue if this patch changes dma-names's rule of DT. This patch assumes dma-names for 1st DMAC are tx/rx base, and listed in each SSI/SRC/DVC subnode ex) rcar_sound,dvc { dvc0: dvc@0 { dmas = <&audma0 0xbc>; dma-names = "tx"; }; ... rcar_sound,src { src0: src@0 { ... dmas = <&audma0 0x85>, <&audma1 0x9a>; dma-names = "rx", "tx"; }; ... rcar_sound,ssi { ssi0: ssi@0 { ... dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>; dma-names = "rx", "tx", "rxu", "txu"; }; ... Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 5a601bed4154..6ce8985757c1 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -114,6 +114,17 @@ struct rsnd_src { /* * Gen1/Gen2 common functions */ +static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + int is_play = rsnd_io_is_play(io); + + return rsnd_dma_request_channel(rsnd_src_of_node(priv), + mod, + is_play ? "rx" : "tx"); +} + int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, int use_busif) { @@ -506,6 +517,7 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_src_gen1_ops = { .name = SRC_NAME, + .dma_req = rsnd_src_dma_req, .probe = rsnd_src_probe_gen1, .init = rsnd_src_init_gen1, .quit = rsnd_src_quit, @@ -780,6 +792,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_src_gen2_ops = { .name = SRC_NAME, + .dma_req = rsnd_src_dma_req, .probe = rsnd_src_probe_gen2, .remove = rsnd_src_remove_gen2, .init = rsnd_src_init_gen2, -- cgit v1.2.1 From 639b231f866c6cc6dcefc33bcaf31e7554697186 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Mar 2015 04:14:04 +0000 Subject: ASoC: rsnd: no more SRC restart when unusual situation It will be SRC interrupt endless loop f unusual situation happen. This patch adds restart limit for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 6ce8985757c1..cc93f32b0de0 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -620,13 +620,17 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) if (rsnd_src_error_record_gen2(mod)) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_src *src = rsnd_mod_to_src(mod); struct device *dev = rsnd_priv_to_dev(priv); - _rsnd_src_stop_gen2(mod); - _rsnd_src_start_gen2(mod); - dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); + + _rsnd_src_stop_gen2(mod); + if (src->err < 1024) + _rsnd_src_start_gen2(mod); + else + dev_warn(dev, "no more SRC restart\n"); } return IRQ_HANDLED; -- cgit v1.2.1 From 2f78dd7f40264697afed4c2ac0890df8f0588e49 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Mar 2015 04:02:09 +0000 Subject: ASoC: rsnd: call clk_prepare/unprepare() in probe/remove clk_prepare_enable()/clk_disable_unprepare() uses mutex inside, in concretely clk_prepare()/clk_unprepare().And it uses __schedule(). Then, raw_spin_lock/unlock_irq() is called, and it breaks Renesas sound driver's spin lock irq. This patch separates thesse into clk_prepare()/clk_unprepare() and clk_enable/clk_disable. And call clk_prepare()/clk_unprepare() from probe/remove function. Special thanks to Das Biju. Reported-by: Das Biju Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 81c182b4bad5..c77d059edc84 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -850,7 +850,7 @@ int rsnd_src_probe(struct platform_device *pdev, struct rsnd_mod_ops *ops; struct clk *clk; char name[RSND_SRC_NAME_SIZE]; - int i, nr; + int i, nr, ret; ops = NULL; if (rsnd_is_gen1(priv)) @@ -890,10 +890,23 @@ int rsnd_src_probe(struct platform_device *pdev, src->info = &info->src_info[i]; - rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); + ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); + if (ret) + return ret; dev_dbg(dev, "SRC%d probed\n", i); } return 0; } + +void rsnd_src_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_src *src; + int i; + + for_each_rsnd_src(src, priv, i) { + rsnd_mod_quit(&src->mod); + } +} -- cgit v1.2.1 From b543b52a44c4e45283cd17721af1299049405136 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Mar 2015 04:02:32 +0000 Subject: ASoC: rsnd: remove useless debug message This patch removes useless debug message. especially some kind of "probed" message will be printed from core.c if it has #define DEBUG Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 6099a8ee0007..83611fa450bf 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -460,17 +460,6 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod) return 0; } -static int rsnd_src_probe_gen1(struct rsnd_mod *mod, - struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - - dev_dbg(dev, "%s[%d] (Gen1) is probed\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - - return 0; -} - static int rsnd_src_init_gen1(struct rsnd_mod *mod, struct rsnd_priv *priv) { @@ -518,7 +507,6 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_src_gen1_ops = { .name = SRC_NAME, .dma_req = rsnd_src_dma_req, - .probe = rsnd_src_probe_gen1, .init = rsnd_src_init_gen1, .quit = rsnd_src_quit, .start = rsnd_src_start_gen1, @@ -725,23 +713,12 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, IRQF_SHARED, dev_name(dev), mod); if (ret) - goto rsnd_src_probe_gen2_fail; + return ret; } ret = rsnd_dma_init(priv, rsnd_mod_to_dma(mod), src->info->dma_id); - if (ret) - goto rsnd_src_probe_gen2_fail; - - dev_dbg(dev, "%s[%d] (Gen2) is probed\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - - return ret; - -rsnd_src_probe_gen2_fail: - dev_err(dev, "%s[%d] (Gen2) failed\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); return ret; } @@ -910,8 +887,6 @@ int rsnd_src_probe(struct platform_device *pdev, ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); if (ret) return ret; - - dev_dbg(dev, "SRC%d probed\n", i); } return 0; -- cgit v1.2.1 From 3b7843ff618f63d1776abd71de7eea9130987037 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Mar 2015 04:02:51 +0000 Subject: ASoC: rsnd: add DPCM based sampling rate convert This patch supports DPCM based sampling rate convert on Renesas sound driver. It assumes... 1. SRC is implemented as FE 2. BE dai_link supports .be_hw_params_fixup Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 83611fa450bf..a0a2bdac09d9 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -22,12 +22,13 @@ struct rsnd_src { struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; + u32 convert_rate; /* sampling rate convert */ int err; }; #define RSND_SRC_NAME_SIZE 16 -#define rsnd_src_convert_rate(p) ((p)->info->convert_rate) +#define rsnd_src_convert_rate(s) ((s)->convert_rate) #define rsnd_src_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") @@ -288,7 +289,43 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod) return 0; } -static int rsnd_src_init(struct rsnd_mod *mod) +static int rsnd_src_hw_params(struct rsnd_mod *mod, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *fe_params) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); + struct snd_soc_pcm_runtime *fe = substream->private_data; + + /* default value (mainly for non-DT) */ + src->convert_rate = src->info->convert_rate; + + /* + * SRC assumes that it is used under DPCM if user want to use + * sampling rate convert. Then, SRC should be FE. + * And then, this function will be called *after* BE settings. + * this means, each BE already has fixuped hw_params. + * see + * dpcm_fe_dai_hw_params() + * dpcm_be_dai_hw_params() + */ + if (fe->dai_link->dynamic) { + int stream = substream->stream; + struct snd_soc_dpcm *dpcm; + struct snd_pcm_hw_params *be_params; + + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + be_params = &dpcm->hw_params; + + if (params_rate(fe_params) != params_rate(be_params)) + src->convert_rate = params_rate(be_params); + } + } + + return 0; +} + +static int rsnd_src_init(struct rsnd_mod *mod, + struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); @@ -317,6 +354,8 @@ static int rsnd_src_quit(struct rsnd_mod *mod, dev_warn(dev, "%s[%d] under/over flow err = %d\n", rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); + src->convert_rate = 0; + return 0; } @@ -465,7 +504,7 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod, { int ret; - ret = rsnd_src_init(mod); + ret = rsnd_src_init(mod, priv); if (ret < 0) return ret; @@ -511,6 +550,7 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { .quit = rsnd_src_quit, .start = rsnd_src_start_gen1, .stop = rsnd_src_stop_gen1, + .hw_params = rsnd_src_hw_params, }; /* @@ -736,7 +776,7 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod, { int ret; - ret = rsnd_src_init(mod); + ret = rsnd_src_init(mod, priv); if (ret < 0) return ret; @@ -780,6 +820,7 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = { .quit = rsnd_src_quit, .start = rsnd_src_start_gen2, .stop = rsnd_src_stop_gen2, + .hw_params = rsnd_src_hw_params, }; struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) -- cgit v1.2.1 From 43cb6954f8c8a68fdc354226fa045ff43c7e4d39 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 1 Apr 2015 04:15:16 +0000 Subject: ASoC: rsnd: add Synchronous SRC mode Renesas R-Car sound SRC (= Sampling Rate Converter) has Asynchronous/Synchronous SRC mode. Asynchronous mode is already supported via DPCM. This patch adds Synchronous mode on it. The condition of enabling Synchronous mode are - SoC is clock master - Sound uses SRC - Sound doesn't use DVC - Sound card uses DPCM (= rsrc-card card) amixer set "SRC Out Rate" on aplay xxx.wav & amixer set "SRC Out Rate" 48000 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 5 deletions(-) (limited to 'sound/soc/sh/rcar/src.c') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index a0a2bdac09d9..3beb32eb412a 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -22,13 +22,15 @@ struct rsnd_src { struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; + struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ + struct rsnd_kctrl_cfg_s sync; /* sync convert */ u32 convert_rate; /* sampling rate convert */ int err; }; #define RSND_SRC_NAME_SIZE 16 -#define rsnd_src_convert_rate(s) ((s)->convert_rate) +#define rsnd_enable_sync_convert(src) ((src)->sen.val) #define rsnd_src_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") @@ -233,6 +235,30 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) return 0; } +static 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->convert_rate; + + convert_rate = src->sync.val; + + if (!convert_rate) + convert_rate = src->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) @@ -333,6 +359,9 @@ static int rsnd_src_init(struct rsnd_mod *mod, src->err = 0; + /* reset sync convert_rate */ + src->sync.val = 0; + /* * Initialize the operation of the SRC internal circuits * see rsnd_src_start() @@ -356,6 +385,9 @@ static int rsnd_src_quit(struct rsnd_mod *mod, src->convert_rate = 0; + /* reset sync convert_rate */ + src->sync.val = 0; + return 0; } @@ -672,6 +704,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; @@ -692,13 +725,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_io_is_play(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: @@ -811,6 +852,80 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, return ret; } +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; + + if (!runtime) + return; + + if (!convert_rate) + convert_rate = runtime->rate; + + 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 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_dai *rdai = rsnd_io_to_rdai(io); + 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_rdai_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, rtd, + rsnd_io_is_play(io) ? + "SRC Out Rate Switch" : + "SRC In Rate Switch", + rsnd_src_reconvert_update, + &src->sen, 1); + if (ret < 0) + return ret; + + ret = rsnd_kctrl_new_s(mod, rtd, + rsnd_io_is_play(io) ? + "SRC Out Rate" : + "SRC In Rate", + rsnd_src_reconvert_update, + &src->sync, 192000); + + return ret; +} + static struct rsnd_mod_ops rsnd_src_gen2_ops = { .name = SRC_NAME, .dma_req = rsnd_src_dma_req, @@ -821,6 +936,7 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = { .start = rsnd_src_start_gen2, .stop = rsnd_src_stop_gen2, .hw_params = rsnd_src_hw_params, + .pcm_new = rsnd_src_pcm_new, }; struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) -- cgit v1.2.1