Skip to content

Commit

Permalink
ASoC: rsnd: add SRC (Sampling Rate Converter) support
Browse files Browse the repository at this point in the history
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 <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Kuninori Morimoto authored and Mark Brown committed Dec 31, 2013
1 parent adcf7d5 commit ef74940
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 8 deletions.
1 change: 1 addition & 0 deletions include/sound/rcar_snd.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct rsnd_ssi_platform_info {

struct rsnd_scu_platform_info {
u32 flags;
u32 convert_rate; /* sampling rate convert */
};

/*
Expand Down
73 changes: 73 additions & 0 deletions sound/soc/sh/rcar/adg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions sound/soc/sh/rcar/gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
18 changes: 18 additions & 0 deletions sound/soc/sh/rcar/rsnd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)

/*
Expand Down
Loading

0 comments on commit ef74940

Please sign in to comment.