Skip to content

Commit

Permalink
ASoC: rsnd: adjust convert rate limitation
Browse files Browse the repository at this point in the history
Current rsnd driver supports Synchronous SRC Mode, but HW allow to update
rate only within 1% from current rate. Adjust to it.

Becially, this feature is used to fine-tune subtle difference that occur
during sampling rate conversion in SRC. So, it should be called within 1%
margin of rate difference.

If there was difference over 1%, it will apply with 1% increments by using
loop without indicating error message.

Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Link: https://patch.msgid.link/871pwd2qe8.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Kuninori Morimoto authored and Mark Brown committed Feb 5, 2025
1 parent c3fc002 commit 89f9cf1
Showing 1 changed file with 76 additions and 22 deletions.
98 changes: 76 additions & 22 deletions sound/soc/renesas/rcar/src.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct rsnd_src {
struct rsnd_mod *dma;
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
struct rsnd_kctrl_cfg_s sync; /* sync convert */
u32 current_sync_rate;
int irq;
};

Expand Down Expand Up @@ -100,7 +101,7 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
if (!rsnd_src_sync_is_enabled(mod))
return rsnd_io_converted_rate(io);

convert_rate = src->sync.val;
convert_rate = src->current_sync_rate;

if (!convert_rate)
convert_rate = rsnd_io_converted_rate(io);
Expand Down Expand Up @@ -201,13 +202,73 @@ static const u32 chan222222[] = {
static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 fin, fout, new_rate;
int inc, cnt, rate;
u64 base, val;

if (!runtime)
return;

if (!rsnd_src_sync_is_enabled(mod))
return;

fin = rsnd_src_get_in_rate(priv, io);
fout = rsnd_src_get_out_rate(priv, io);

new_rate = src->sync.val;

if (!new_rate)
new_rate = fout;

/* Do nothing if no diff */
if (new_rate == src->current_sync_rate)
return;

/*
* SRCm_IFSVR::INTIFS can change within 1%
* see
* SRCm_IFSVR::INTIFS Note
*/
inc = fout / 100;
cnt = abs(new_rate - fout) / inc;
if (fout > new_rate)
inc *= -1;

/*
* After start running SRC, we can update only SRC_IFSVR
* for Synchronous Mode
*/
base = (u64)0x0400000 * fin;
rate = fout;
for (int i = 0; i < cnt; i++) {
val = base;
rate += inc;
do_div(val, rate);

rsnd_mod_write(mod, SRC_IFSVR, val);
}
val = base;
do_div(val, new_rate);

rsnd_mod_write(mod, SRC_IFSVR, val);

/* update current_sync_rate */
src->current_sync_rate = new_rate;
}

static void rsnd_src_init_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
int is_play = rsnd_io_is_play(io);
int use_src = 0;
u32 fin, fout;
u32 ifscr, fsrate, adinr;
u32 ifscr, adinr;
u32 cr, route;
u32 i_busif, o_busif, tmp;
const u32 *bsdsr_table;
Expand Down Expand Up @@ -245,26 +306,15 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
adinr = rsnd_get_adinr_bit(mod, io) | chan;

/*
* SRC_IFSCR / SRC_IFSVR
*/
ifscr = 0;
fsrate = 0;
if (use_src) {
u64 n;

ifscr = 1;
n = (u64)0x0400000 * fin;
do_div(n, fout);
fsrate = n;
}

/*
* SRC_IFSCR
* SRC_SRCCR / SRC_ROUTE_MODE0
*/
ifscr = 0;
cr = 0x00011110;
route = 0x0;
if (use_src) {
route = 0x1;
ifscr = 0x1;

if (rsnd_src_sync_is_enabled(mod)) {
cr |= 0x1;
Expand Down Expand Up @@ -335,7 +385,6 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */
rsnd_mod_write(mod, SRC_ADINR, adinr);
rsnd_mod_write(mod, SRC_IFSCR, ifscr);
rsnd_mod_write(mod, SRC_IFSVR, fsrate);
rsnd_mod_write(mod, SRC_SRCCR, cr);
rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
Expand All @@ -348,6 +397,9 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,

rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);

/* update SRC_IFSVR */
rsnd_src_set_convert_rate(io, mod);

return;

convert_rate_err:
Expand Down Expand Up @@ -467,15 +519,16 @@ static int rsnd_src_init(struct rsnd_mod *mod,
int ret;

/* reset sync convert_rate */
src->sync.val = 0;
src->sync.val =
src->current_sync_rate = 0;

ret = rsnd_mod_power_on(mod);
if (ret < 0)
return ret;

rsnd_src_activation(mod);

rsnd_src_set_convert_rate(io, mod);
rsnd_src_init_convert_rate(io, mod);

rsnd_src_status_clear(mod);

Expand All @@ -493,7 +546,8 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
rsnd_mod_power_off(mod);

/* reset sync convert_rate */
src->sync.val = 0;
src->sync.val =
src->current_sync_rate = 0;

return 0;
}
Expand Down Expand Up @@ -601,7 +655,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
"SRC Out Rate Switch" :
"SRC In Rate Switch",
rsnd_kctrl_accept_anytime,
rsnd_src_set_convert_rate,
rsnd_src_init_convert_rate,
&src->sen, 1);
if (ret < 0)
return ret;
Expand Down

0 comments on commit 89f9cf1

Please sign in to comment.