From 690ef81ebe02a43991b0fcb418d77b8420346cfd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Dec 2013 19:27:03 -0800 Subject: ASoC: rsnd: tidyup register naming Use correct register name which appears in the datasheet Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/scu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/sh/rcar/scu.c') diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 1ab1bce6be7f..187f7dc30369 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -115,7 +115,7 @@ static int rsnd_scu_set_mode(struct rsnd_priv *priv, if (rsnd_is_gen1(priv)) { val = (1 << id); - rsnd_mod_bset(mod, SRC_CTRL, val, val); + rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); } return 0; @@ -141,7 +141,7 @@ static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, } rsnd_mod_write(mod, BUSIF_MODE, 1); - rsnd_mod_write(mod, BUSIF_ADINR, adinr); + rsnd_mod_write(mod, SRC_ADINR, adinr); return 0; } -- cgit v1.2.3 From 2582718cb6bd620d37a54db885c75bfe4822db45 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Dec 2013 19:27:37 -0800 Subject: ASoC: rsnd: route setting is needed only Gen1 Renesas sound has SRC (= Sampling Rate Converter), but, the HW implementation depends on its generation. It was part of SRU on Gen1, and SCU on Gen2. This SCU needs DMA transfer to use it. Current rsnd driver is using it as DMA transfer buffer (= no rate convert), and Gen1 is only supported at this point. This patch cleanup it with focusing about SRC and Gen2 part. rsnd_scu_set_route() is needed only Gen1. This patch renames it to rsnd_scu_set_route_if_gen1() and it adds comment to rsnd_reg member in order to clarify it is used for Gen1. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 10 +++++----- sound/soc/sh/rcar/scu.c | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'sound/soc/sh/rcar/scu.c') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d5c0182c8e50..a14bc9274b3f 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -32,11 +32,11 @@ */ enum rsnd_reg { /* SRU/SCU/SSIU */ - RSND_REG_SRC_ROUTE_SEL, - RSND_REG_SRC_TMG_SEL0, - RSND_REG_SRC_TMG_SEL1, - RSND_REG_SRC_TMG_SEL2, - RSND_REG_SRC_ROUTE_CTRL, + RSND_REG_SRC_ROUTE_SEL, /* for Gen1 */ + RSND_REG_SRC_TMG_SEL0, /* for Gen1 */ + RSND_REG_SRC_TMG_SEL1, /* for Gen1 */ + RSND_REG_SRC_TMG_SEL2, /* for Gen1 */ + RSND_REG_SRC_ROUTE_CTRL, /* for Gen1 */ RSND_REG_SSI_MODE0, RSND_REG_SSI_MODE1, RSND_REG_BUSIF_MODE, diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 187f7dc30369..7642ec52b590 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -36,7 +36,8 @@ struct rsnd_scu { ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ i++) -static int rsnd_scu_set_route(struct rsnd_priv *priv, +/* Gen1 only */ +static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) @@ -174,7 +175,8 @@ static int rsnd_scu_start(struct rsnd_mod *mod, } /* it use DMA transter */ - ret = rsnd_scu_set_route(priv, mod, rdai, io); + + ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io); if (ret < 0) return ret; -- cgit v1.2.3 From af8a478821345fd264fd2294e80f5b0a28a518bc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Dec 2013 19:28:04 -0800 Subject: ASoC: rsnd: add rsnd_scu_transfer_start() Renesas sound has SRC (= Sampling Rate Converter), but, the HW implementation depends on its generation. It was part of SRU on Gen1, and SCU on Gen2. This SCU needs DMA transfer to use it. Current rsnd driver is using it as DMA transfer buffer (= no rate convert), and Gen1 is only supported at this point. This patch cleanup it with focusing about SRC and Gen2 part. SRC_CTRL/BUSIF_MODE are used for transfer start. This patch adds rsnd_scu_transfer_start() and merge these Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/scu.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'sound/soc/sh/rcar/scu.c') diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 7642ec52b590..3d8b57b1630b 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -106,22 +106,6 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, return 0; } -static int rsnd_scu_set_mode(struct rsnd_priv *priv, - struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) -{ - int id = rsnd_mod_id(mod); - u32 val; - - if (rsnd_is_gen1(priv)) { - val = (1 << id); - rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); - } - - return 0; -} - static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_dai *rdai, @@ -141,12 +125,29 @@ static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, return -EIO; } - rsnd_mod_write(mod, BUSIF_MODE, 1); rsnd_mod_write(mod, SRC_ADINR, adinr); return 0; } +static int rsnd_scu_transfer_start(struct rsnd_priv *priv, + struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct rsnd_dai_stream *io) +{ + int id = rsnd_mod_id(mod); + u32 val; + + if (rsnd_is_gen1(priv)) { + val = (1 << id); + rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); + } + + rsnd_mod_write(mod, BUSIF_MODE, 1); + + return 0; +} + bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod) { struct rsnd_scu *scu = rsnd_mod_to_scu(mod); @@ -180,11 +181,11 @@ static int rsnd_scu_start(struct rsnd_mod *mod, if (ret < 0) return ret; - ret = rsnd_scu_set_mode(priv, mod, rdai, io); + ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); if (ret < 0) return ret; - ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); + ret = rsnd_scu_transfer_start(priv, mod, rdai, io); if (ret < 0) return ret; -- cgit v1.2.3 From 99feec32f26a3c267f89ce48db4bd36650a95f7f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Dec 2013 19:28:31 -0800 Subject: ASoC: rsnd: scu cleanup: add rsnd_scu_rate_ctrl() Renesas sound has SRC (= Sampling Rate Converter), but, the HW implementation depends on its generation. It was part of SRU on Gen1, and SCU on Gen2. This SCU needs DMA transfer to use it. Current rsnd driver is using it as DMA transfer buffer (= no rate convert), and Gen1 is only supported at this point. This patch cleanup it with focusing about SRC and Gen2 part. rsnd_scu_set_hpbif() is renamed to rsnd_scu_rate_ctrl(), since its naming doesn't indicate the function meaning. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/scu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/sh/rcar/scu.c') diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 3d8b57b1630b..5f4f57206faf 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -106,7 +106,7 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, return 0; } -static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, +static int rsnd_scu_rate_ctrl(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) @@ -181,7 +181,7 @@ static int rsnd_scu_start(struct rsnd_mod *mod, if (ret < 0) return ret; - ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); + ret = rsnd_scu_rate_ctrl(priv, mod, rdai, io); if (ret < 0) return ret; -- cgit v1.2.3 From ef749400434cefd14fe02fe3de9e9f0125b2256d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Dec 2013 19:28:51 -0800 Subject: ASoC: rsnd: add SRC (Sampling Rate Converter) support This patch adds SRC support to Renesas sound driver. SRC converts sampling rate between codec <-> cpu. It needs special codec chip, or very simple DA/AD converter to use it. This patch was tested via ak4554 codec, and supports Gen1 only at this point. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/rcar_snd.h | 1 + sound/soc/sh/rcar/adg.c | 73 +++++++++++++++++++++++ sound/soc/sh/rcar/gen.c | 10 ++++ sound/soc/sh/rcar/rsnd.h | 18 ++++++ sound/soc/sh/rcar/scu.c | 152 ++++++++++++++++++++++++++++++++++++++++++++--- sound/soc/sh/rcar/ssi.c | 2 +- 6 files changed, 248 insertions(+), 8 deletions(-) (limited to 'sound/soc/sh/rcar/scu.c') diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index a818ff76b138..e147498abe50 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -58,6 +58,7 @@ struct rsnd_ssi_platform_info { struct rsnd_scu_platform_info { u32 flags; + u32 convert_rate; /* sampling rate convert */ }; /* diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2e71a7bda4c2..a53235c4d1b0 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -30,6 +30,79 @@ struct rsnd_adg { i++, (pos) = adg->clk[i]) #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) +static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, + struct rsnd_mod *mod, + unsigned int src_rate, + unsigned int dst_rate) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + int idx, sel, div, shift; + u32 mask, val; + int id = rsnd_mod_id(mod); + unsigned int sel_rate [] = { + clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */ + clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */ + clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */ + 0, /* 011: MLBCLK (not used) */ + adg->rbga_rate_for_441khz_div_6,/* 100: RBGA */ + adg->rbgb_rate_for_48khz_div_6, /* 101: RBGB */ + }; + + /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */ + for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { + for (div = 128, idx = 0; + div <= 2048; + div *= 2, idx++) { + if (src_rate == sel_rate[sel] / div) { + val = (idx << 4) | sel; + goto find_rate; + } + } + } + dev_err(dev, "can't find convert src clk\n"); + return -EINVAL; + +find_rate: + shift = (id % 4) * 8; + mask = 0xFF << shift; + val = val << shift; + + dev_dbg(dev, "adg convert src clk = %02x\n", val); + + switch (id / 4) { + case 0: + rsnd_mod_bset(mod, AUDIO_CLK_SEL3, mask, val); + break; + case 1: + rsnd_mod_bset(mod, AUDIO_CLK_SEL4, mask, val); + break; + case 2: + rsnd_mod_bset(mod, AUDIO_CLK_SEL5, mask, val); + break; + } + + /* + * Gen1 doesn't need dst_rate settings, + * since it uses SSI WS pin. + * see also rsnd_src_set_route_if_gen1() + */ + + return 0; +} + +int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, + struct rsnd_mod *mod, + unsigned int src_rate, + unsigned int dst_rate) +{ + if (rsnd_is_gen1(priv)) + return rsnd_adg_set_convert_clk_gen1(priv, mod, + src_rate, dst_rate); + + return -EINVAL; +} + static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val) { int id = rsnd_mod_id(mod); diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 862758d3ec06..add088bd4b2a 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -318,13 +318,23 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), + RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), + RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), RSND_GEN1_M_REG(gen, SRU, SRC_ADINR, 0x214, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_IFSCR, 0x21c, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_IFSVR, 0x220, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_SRCCR, 0x224, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_MNFSR, 0x228, 0x40), RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20), RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 3774dfcfaf0f..4ca66cd899c8 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -41,7 +41,14 @@ enum rsnd_reg { RSND_REG_SSI_MODE1, RSND_REG_BUSIF_MODE, RSND_REG_INT_ENABLE, /* for Gen2 */ + RSND_REG_SRC_ROUTE_MODE0, + RSND_REG_SRC_SWRSR, + RSND_REG_SRC_SRCIR, RSND_REG_SRC_ADINR, + RSND_REG_SRC_IFSCR, + RSND_REG_SRC_IFSVR, + RSND_REG_SRC_SRCCR, + RSND_REG_SRC_MNFSR, /* ADG */ RSND_REG_BRRA, @@ -50,6 +57,9 @@ enum rsnd_reg { RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, RSND_REG_AUDIO_CLK_SEL2, + RSND_REG_AUDIO_CLK_SEL3, /* for Gen1 */ + RSND_REG_AUDIO_CLK_SEL4, /* for Gen1 */ + RSND_REG_AUDIO_CLK_SEL5, /* for Gen1 */ /* SSI */ RSND_REG_SSICR, @@ -227,6 +237,10 @@ int rsnd_adg_probe(struct platform_device *pdev, struct rsnd_priv *priv); void rsnd_adg_remove(struct platform_device *pdev, struct rsnd_priv *priv); +int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, + struct rsnd_mod *mod, + unsigned int src_rate, + unsigned int dst_rate); /* * R-Car sound priv @@ -280,6 +294,10 @@ void rsnd_scu_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod); +unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, + struct rsnd_mod *ssi_mod, + struct snd_pcm_runtime *runtime); + #define rsnd_scu_nr(priv) ((priv)->scu_nr) /* diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 5f4f57206faf..1406dd8d9ed2 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -13,9 +13,13 @@ struct rsnd_scu { struct rsnd_scu_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; + struct clk *clk; }; #define rsnd_scu_mode_flags(p) ((p)->info->flags) +#define rsnd_scu_convert_rate(p) ((p)->info->convert_rate) + +#define RSND_SCU_NAME_SIZE 16 /* * ADINR @@ -26,6 +30,15 @@ struct rsnd_scu { #define OTBL_18 (6 << 16) #define OTBL_16 (8 << 16) +/* + * image of SRC (Sampling Rate Converter) + * + * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ + * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | + * 44.1kHz <-> +-----+ +-----+ +-------+ + * ... + * + */ #define rsnd_mod_to_scu(_mod) \ container_of((_mod), struct rsnd_scu, mod) @@ -56,7 +69,7 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, { 0x3, 28, }, /* 7 */ { 0x3, 30, }, /* 8 */ }; - + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); u32 mask; u32 val; int shift; @@ -86,9 +99,18 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, */ shift = (id % 4) * 8; mask = 0x1F << shift; - if (8 == id) /* SRU8 is very special */ + + /* + * ADG is used as source clock if SRC was used, + * then, SSI WS is used as destination clock. + * SSI WS is used as source clock if SRC is not used + * (when playback, source/destination become reverse when capture) + */ + if (rsnd_scu_convert_rate(scu)) /* use ADG */ + val = 0; + else if (8 == id) /* use SSI WS, but SRU8 is special */ val = id << shift; - else + else /* use SSI WS */ val = (id + 1) << shift; switch (id / 4) { @@ -106,14 +128,45 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, return 0; } -static int rsnd_scu_rate_ctrl(struct rsnd_priv *priv, +unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, + struct rsnd_mod *ssi_mod, + struct snd_pcm_runtime *runtime) +{ + struct rsnd_scu *scu; + unsigned int rate; + + /* this function is assuming SSI id = SCU id here */ + scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod))); + + /* + * return convert rate if SRC is used, + * otherwise, return runtime->rate as usual + */ + rate = rsnd_scu_convert_rate(scu); + if (!rate) + rate = runtime->rate; + + return rate; +} + +static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); + u32 convert_rate = rsnd_scu_convert_rate(scu); u32 adinr = runtime->channels; + /* set/clear soft reset */ + rsnd_mod_write(mod, SRC_SWRSR, 0); + rsnd_mod_write(mod, SRC_SWRSR, 1); + + /* Initialize the operation of the SRC internal circuits */ + rsnd_mod_write(mod, SRC_SRCIR, 1); + + /* Set channel number and output bit length */ switch (runtime->sample_bits) { case 16: adinr |= OTBL_16; @@ -124,9 +177,42 @@ static int rsnd_scu_rate_ctrl(struct rsnd_priv *priv, default: return -EIO; } - rsnd_mod_write(mod, SRC_ADINR, adinr); + if (convert_rate) { + u32 fsrate = 0x0400000 / convert_rate * runtime->rate; + int ret; + + /* Enable the initial value of IFS */ + rsnd_mod_write(mod, SRC_IFSCR, 1); + + /* Set initial value of IFS */ + rsnd_mod_write(mod, SRC_IFSVR, fsrate); + + /* Select SRC mode (fixed value) */ + rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); + + /* Set the restriction value of the FS ratio (98%) */ + rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98); + + if (rsnd_is_gen1(priv)) { + /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ + } + + /* set convert clock */ + ret = rsnd_adg_set_convert_clk(priv, mod, + runtime->rate, + convert_rate); + if (ret < 0) + return ret; + } + + /* Cancel the initialization and operate the SRC function */ + rsnd_mod_write(mod, SRC_SRCIR, 0); + + /* use DMA transfer */ + rsnd_mod_write(mod, BUSIF_MODE, 1); + return 0; } @@ -135,6 +221,7 @@ static int rsnd_scu_transfer_start(struct rsnd_priv *priv, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); int id = rsnd_mod_id(mod); u32 val; @@ -143,7 +230,28 @@ static int rsnd_scu_transfer_start(struct rsnd_priv *priv, rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); } - rsnd_mod_write(mod, BUSIF_MODE, 1); + if (rsnd_scu_convert_rate(scu)) + rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); + + return 0; +} + +static int rsnd_scu_transfer_stop(struct rsnd_priv *priv, + struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct rsnd_dai_stream *io) +{ + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); + int id = rsnd_mod_id(mod); + u32 mask; + + if (rsnd_is_gen1(priv)) { + mask = (1 << id); + rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0); + } + + if (rsnd_scu_convert_rate(scu)) + rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); return 0; } @@ -161,6 +269,7 @@ static int rsnd_scu_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); struct device *dev = rsnd_priv_to_dev(priv); int ret; @@ -175,13 +284,15 @@ static int rsnd_scu_start(struct rsnd_mod *mod, return 0; } + clk_enable(scu->clk); + /* it use DMA transter */ ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io); if (ret < 0) return ret; - ret = rsnd_scu_rate_ctrl(priv, mod, rdai, io); + ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io); if (ret < 0) return ret; @@ -194,9 +305,27 @@ static int rsnd_scu_start(struct rsnd_mod *mod, return 0; } +static int rsnd_scu_stop(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); + + if (!rsnd_scu_hpbif_is_enable(mod)) + return 0; + + rsnd_scu_transfer_stop(priv, mod, rdai, io); + + clk_disable(scu->clk); + + return 0; +} + static struct rsnd_mod_ops rsnd_scu_ops = { .name = "scu", .start = rsnd_scu_start, + .stop = rsnd_scu_stop, }; struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) @@ -212,6 +341,8 @@ int rsnd_scu_probe(struct platform_device *pdev, { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_scu *scu; + struct clk *clk; + char name[RSND_SCU_NAME_SIZE]; int i, nr; /* @@ -228,9 +359,16 @@ int rsnd_scu_probe(struct platform_device *pdev, priv->scu = scu; for_each_rsnd_scu(scu, priv, i) { + snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + rsnd_mod_init(priv, &scu->mod, &rsnd_scu_ops, i); scu->info = &info->scu_info[i]; + scu->clk = clk; dev_dbg(dev, "SCU%d probed\n", i); } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2db9711549f5..b7cd06be9436 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -200,7 +200,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, 1, 2, 4, 8, 16, 6, 12, }; unsigned int main_rate; - unsigned int rate = runtime->rate; + unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime); /* * Find best clock, and try to start ADG -- cgit v1.2.3