mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
ASoC: rsnd: adjust convert rate limitation
[ Upstream commit 89f9cf185885d4358aa92b48e51d0f09b71775aa ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
1ffc9e9423
commit
17458c1193
@@ -34,6 +34,7 @@ struct rsnd_src {
|
|||||||
struct rsnd_mod *dma;
|
struct rsnd_mod *dma;
|
||||||
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
|
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
|
||||||
struct rsnd_kctrl_cfg_s sync; /* sync convert */
|
struct rsnd_kctrl_cfg_s sync; /* sync convert */
|
||||||
|
u32 current_sync_rate;
|
||||||
int irq;
|
int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,7 +100,7 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
|
|||||||
if (!rsnd_src_sync_is_enabled(mod))
|
if (!rsnd_src_sync_is_enabled(mod))
|
||||||
return rsnd_io_converted_rate(io);
|
return rsnd_io_converted_rate(io);
|
||||||
|
|
||||||
convert_rate = src->sync.val;
|
convert_rate = src->current_sync_rate;
|
||||||
|
|
||||||
if (!convert_rate)
|
if (!convert_rate)
|
||||||
convert_rate = rsnd_io_converted_rate(io);
|
convert_rate = rsnd_io_converted_rate(io);
|
||||||
@@ -200,13 +201,73 @@ static const u32 chan222222[] = {
|
|||||||
static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
|
static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
|
||||||
struct rsnd_mod *mod)
|
struct rsnd_mod *mod)
|
||||||
{
|
{
|
||||||
|
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||||
|
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||||
|
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 rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||||
struct device *dev = rsnd_priv_to_dev(priv);
|
struct device *dev = rsnd_priv_to_dev(priv);
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
|
||||||
int is_play = rsnd_io_is_play(io);
|
int is_play = rsnd_io_is_play(io);
|
||||||
int use_src = 0;
|
int use_src = 0;
|
||||||
u32 fin, fout;
|
u32 fin, fout;
|
||||||
u32 ifscr, fsrate, adinr;
|
u32 ifscr, adinr;
|
||||||
u32 cr, route;
|
u32 cr, route;
|
||||||
u32 i_busif, o_busif, tmp;
|
u32 i_busif, o_busif, tmp;
|
||||||
const u32 *bsdsr_table;
|
const u32 *bsdsr_table;
|
||||||
@@ -244,26 +305,15 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
|
|||||||
adinr = rsnd_get_adinr_bit(mod, io) | chan;
|
adinr = rsnd_get_adinr_bit(mod, io) | chan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SRC_IFSCR / SRC_IFSVR
|
* SRC_IFSCR
|
||||||
*/
|
|
||||||
ifscr = 0;
|
|
||||||
fsrate = 0;
|
|
||||||
if (use_src) {
|
|
||||||
u64 n;
|
|
||||||
|
|
||||||
ifscr = 1;
|
|
||||||
n = (u64)0x0400000 * fin;
|
|
||||||
do_div(n, fout);
|
|
||||||
fsrate = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SRC_SRCCR / SRC_ROUTE_MODE0
|
* SRC_SRCCR / SRC_ROUTE_MODE0
|
||||||
*/
|
*/
|
||||||
|
ifscr = 0;
|
||||||
cr = 0x00011110;
|
cr = 0x00011110;
|
||||||
route = 0x0;
|
route = 0x0;
|
||||||
if (use_src) {
|
if (use_src) {
|
||||||
route = 0x1;
|
route = 0x1;
|
||||||
|
ifscr = 0x1;
|
||||||
|
|
||||||
if (rsnd_src_sync_is_enabled(mod)) {
|
if (rsnd_src_sync_is_enabled(mod)) {
|
||||||
cr |= 0x1;
|
cr |= 0x1;
|
||||||
@@ -334,7 +384,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_SRCIR, 1); /* initialize */
|
||||||
rsnd_mod_write(mod, SRC_ADINR, adinr);
|
rsnd_mod_write(mod, SRC_ADINR, adinr);
|
||||||
rsnd_mod_write(mod, SRC_IFSCR, ifscr);
|
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_SRCCR, cr);
|
||||||
rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
|
rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
|
||||||
rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
|
rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
|
||||||
@@ -347,6 +396,9 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
|
|||||||
|
|
||||||
rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
|
rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
|
||||||
|
|
||||||
|
/* update SRC_IFSVR */
|
||||||
|
rsnd_src_set_convert_rate(io, mod);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
convert_rate_err:
|
convert_rate_err:
|
||||||
@@ -466,7 +518,8 @@ static int rsnd_src_init(struct rsnd_mod *mod,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* reset sync convert_rate */
|
/* reset sync convert_rate */
|
||||||
src->sync.val = 0;
|
src->sync.val =
|
||||||
|
src->current_sync_rate = 0;
|
||||||
|
|
||||||
ret = rsnd_mod_power_on(mod);
|
ret = rsnd_mod_power_on(mod);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@@ -474,7 +527,7 @@ static int rsnd_src_init(struct rsnd_mod *mod,
|
|||||||
|
|
||||||
rsnd_src_activation(mod);
|
rsnd_src_activation(mod);
|
||||||
|
|
||||||
rsnd_src_set_convert_rate(io, mod);
|
rsnd_src_init_convert_rate(io, mod);
|
||||||
|
|
||||||
rsnd_src_status_clear(mod);
|
rsnd_src_status_clear(mod);
|
||||||
|
|
||||||
@@ -492,7 +545,8 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
|
|||||||
rsnd_mod_power_off(mod);
|
rsnd_mod_power_off(mod);
|
||||||
|
|
||||||
/* reset sync convert_rate */
|
/* reset sync convert_rate */
|
||||||
src->sync.val = 0;
|
src->sync.val =
|
||||||
|
src->current_sync_rate = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -600,7 +654,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
|
|||||||
"SRC Out Rate Switch" :
|
"SRC Out Rate Switch" :
|
||||||
"SRC In Rate Switch",
|
"SRC In Rate Switch",
|
||||||
rsnd_kctrl_accept_anytime,
|
rsnd_kctrl_accept_anytime,
|
||||||
rsnd_src_set_convert_rate,
|
rsnd_src_init_convert_rate,
|
||||||
&src->sen, 1);
|
&src->sen, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user