Unverified Commit b9cb90a5 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: rsnd: adjust convert rate in 1%

Merge series from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>:

Renesas Synchronous SRC Mode has HW limitation to be used in 1% rate
difference, but driver didn't care it. This patch-set adjust to it.

Link: https://lore.kernel.org/r/87o6zi32ry.wl-kuninori.morimoto.gx@renesas.com
parents 0b060007 89f9cf18
Loading
Loading
Loading
Loading
+0 −14
Original line number Diff line number Diff line
@@ -1770,20 +1770,6 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
	return 1;
}

int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
{
	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
	struct rsnd_priv *priv = rsnd_io_to_priv(io);
	struct device *dev = rsnd_priv_to_dev(priv);

	if (!runtime) {
		dev_warn(dev, "Can't update kctrl when idle\n");
		return 0;
	}

	return 1;
}

struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
{
	cfg->cfg.val = cfg->val;
+0 −1
Original line number Diff line number Diff line
@@ -742,7 +742,6 @@ struct rsnd_kctrl_cfg_s {
#define rsnd_kctrl_vals(x)	((x).val)	/* = (x).cfg.val[0] */

int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg);
struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg);
int rsnd_kctrl_new(struct rsnd_mod *mod,
+93 −23
Original line number Diff line number Diff line
@@ -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;
};

@@ -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);
@@ -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;
@@ -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;
@@ -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]);
@@ -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:
@@ -467,7 +519,8 @@ 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)
@@ -475,7 +528,7 @@ static int rsnd_src_init(struct rsnd_mod *mod,

	rsnd_src_activation(mod);

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

	rsnd_src_status_clear(mod);

@@ -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;
}
@@ -531,6 +585,22 @@ static irqreturn_t rsnd_src_interrupt(int irq, void *data)
	return IRQ_HANDLED;
}

static int rsnd_src_kctrl_accept_runtime(struct rsnd_dai_stream *io)
{
	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);

	if (!runtime) {
		struct rsnd_priv *priv = rsnd_io_to_priv(io);
		struct device *dev = rsnd_priv_to_dev(priv);

		dev_warn(dev, "\"SRC Out Rate\" can use during running\n");

		return 0;
	}

	return 1;
}

static int rsnd_src_probe_(struct rsnd_mod *mod,
			   struct rsnd_dai_stream *io,
			   struct rsnd_priv *priv)
@@ -585,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;
@@ -594,7 +664,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
			       rsnd_io_is_play(io) ?
			       "SRC Out Rate" :
			       "SRC In Rate",
			       rsnd_kctrl_accept_runtime,
			       rsnd_src_kctrl_accept_runtime,
			       rsnd_src_set_convert_rate,
			       &src->sync, 192000);

+2 −1
Original line number Diff line number Diff line
@@ -336,7 +336,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
	return 0;

rate_err:
	dev_err(dev, "unsupported clock rate\n");
	dev_err(dev, "unsupported clock rate (%d)\n", rate);

	return ret;
}