Unverified Commit 27147695 authored by Shengjiu Wang's avatar Shengjiu Wang Committed by Mark Brown
Browse files

ASoC: fsl_easrc: define functions for memory to memory usage



ASRC can be used on memory to memory case, define several
functions for m2m usage and export them as function pointer.

Signed-off-by: default avatarShengjiu Wang <shengjiu.wang@nxp.com>
Acked-by: default avatarJaroslav Kysela <perex@perex.cz>
Link: https://patch.msgid.link/20241212074509.3445859-4-shengjiu.wang@nxp.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 8ea7d04a
Loading
Loading
Loading
Loading
+228 −0
Original line number Diff line number Diff line
@@ -1861,6 +1861,224 @@ static int fsl_easrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
	return REG_EASRC_FIFO(dir, index);
}

/* Get sample numbers in FIFO */
static unsigned int fsl_easrc_get_output_fifo_size(struct fsl_asrc_pair *pair)
{
	struct fsl_asrc *asrc = pair->asrc;
	enum asrc_pair_index index = pair->index;
	u32 val;

	regmap_read(asrc->regmap, REG_EASRC_SFS(index), &val);
	val &= EASRC_SFS_NSGO_MASK;

	return val >> EASRC_SFS_NSGO_SHIFT;
}

static int fsl_easrc_m2m_prepare(struct fsl_asrc_pair *pair)
{
	struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
	struct fsl_asrc *asrc = pair->asrc;
	struct device *dev = &asrc->pdev->dev;
	int ret;

	ctx_priv->in_params.sample_rate = pair->rate[IN];
	ctx_priv->in_params.sample_format = pair->sample_format[IN];
	ctx_priv->out_params.sample_rate = pair->rate[OUT];
	ctx_priv->out_params.sample_format = pair->sample_format[OUT];

	ctx_priv->in_params.fifo_wtmk = FSL_EASRC_INPUTFIFO_WML;
	ctx_priv->out_params.fifo_wtmk = FSL_EASRC_OUTPUTFIFO_WML;
	/* Fill the right half of the re-sampler with zeros */
	ctx_priv->rs_init_mode = 0x2;
	/* Zero fill the right half of the prefilter */
	ctx_priv->pf_init_mode = 0x2;

	ret = fsl_easrc_set_ctx_format(pair,
				       &ctx_priv->in_params.sample_format,
				       &ctx_priv->out_params.sample_format);
	if (ret) {
		dev_err(dev, "failed to set context format: %d\n", ret);
		return ret;
	}

	ret = fsl_easrc_config_context(asrc, pair->index);
	if (ret) {
		dev_err(dev, "failed to config context %d\n", ret);
		return ret;
	}

	ctx_priv->in_params.iterations = 1;
	ctx_priv->in_params.group_len = pair->channels;
	ctx_priv->in_params.access_len = pair->channels;
	ctx_priv->out_params.iterations = 1;
	ctx_priv->out_params.group_len = pair->channels;
	ctx_priv->out_params.access_len = pair->channels;

	ret = fsl_easrc_set_ctx_organziation(pair);
	if (ret) {
		dev_err(dev, "failed to set fifo organization\n");
		return ret;
	}

	/* The context start flag */
	pair->first_convert = 1;
	return 0;
}

static int fsl_easrc_m2m_start(struct fsl_asrc_pair *pair)
{
	/* start context once */
	if (pair->first_convert) {
		fsl_easrc_start_context(pair);
		pair->first_convert = 0;
	}

	return 0;
}

static int fsl_easrc_m2m_stop(struct fsl_asrc_pair *pair)
{
	/* Stop pair/context */
	if (!pair->first_convert) {
		fsl_easrc_stop_context(pair);
		pair->first_convert = 1;
	}

	return 0;
}

/* calculate capture data length according to output data length and sample rate */
static int fsl_easrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buffer_length)
{
	struct fsl_asrc *easrc = pair->asrc;
	struct fsl_easrc_priv *easrc_priv = easrc->private;
	struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
	unsigned int in_rate = ctx_priv->in_params.norm_rate;
	unsigned int out_rate = ctx_priv->out_params.norm_rate;
	unsigned int channels = pair->channels;
	unsigned int in_samples, out_samples;
	unsigned int in_width, out_width;
	unsigned int out_length;
	unsigned int frac_bits;
	u64 val1, val2;

	switch (easrc_priv->rs_num_taps) {
	case EASRC_RS_32_TAPS:
		/* integer bits = 5; */
		frac_bits = 39;
		break;
	case EASRC_RS_64_TAPS:
		/* integer bits = 6; */
		frac_bits = 38;
		break;
	case EASRC_RS_128_TAPS:
		/* integer bits = 7; */
		frac_bits = 37;
		break;
	default:
		return -EINVAL;
	}

	val1 = (u64)in_rate << frac_bits;
	do_div(val1, out_rate);
	val1 += (s64)ctx_priv->ratio_mod << (frac_bits - 31);

	in_width = snd_pcm_format_physical_width(ctx_priv->in_params.sample_format) / 8;
	out_width = snd_pcm_format_physical_width(ctx_priv->out_params.sample_format) / 8;

	ctx_priv->in_filled_len += input_buffer_length;
	if (ctx_priv->in_filled_len <= ctx_priv->in_filled_sample * in_width * channels) {
		out_length = 0;
	} else {
		in_samples = ctx_priv->in_filled_len / (in_width * channels) -
			     ctx_priv->in_filled_sample;

		/* right shift 12 bit to make ratio in 32bit space */
		val2 = (u64)in_samples << (frac_bits - 12);
		val1 = val1 >> 12;
		do_div(val2, val1);
		out_samples = val2;

		out_length = out_samples * out_width * channels;
		ctx_priv->in_filled_len = ctx_priv->in_filled_sample * in_width * channels;
	}

	return out_length;
}

static int fsl_easrc_m2m_get_maxburst(u8 dir, struct fsl_asrc_pair *pair)
{
	struct fsl_easrc_ctx_priv *ctx_priv = pair->private;

	if (dir == IN)
		return ctx_priv->in_params.fifo_wtmk * pair->channels;
	else
		return ctx_priv->out_params.fifo_wtmk * pair->channels;
}

static int fsl_easrc_m2m_pair_suspend(struct fsl_asrc_pair *pair)
{
	fsl_easrc_stop_context(pair);

	return 0;
}

static int fsl_easrc_m2m_pair_resume(struct fsl_asrc_pair *pair)
{
	struct fsl_easrc_ctx_priv *ctx_priv = pair->private;

	pair->first_convert = 1;
	ctx_priv->in_filled_len = 0;

	return 0;
}

/* val is Q31 */
static int fsl_easrc_m2m_set_ratio_mod(struct fsl_asrc_pair *pair, int val)
{
	struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
	struct fsl_asrc *easrc = pair->asrc;
	struct fsl_easrc_priv *easrc_priv = easrc->private;
	unsigned int frac_bits;

	ctx_priv->ratio_mod += val;

	switch (easrc_priv->rs_num_taps) {
	case EASRC_RS_32_TAPS:
		/* integer bits = 5; */
		frac_bits = 39;
		break;
	case EASRC_RS_64_TAPS:
		/* integer bits = 6; */
		frac_bits = 38;
		break;
	case EASRC_RS_128_TAPS:
		/* integer bits = 7; */
		frac_bits = 37;
		break;
	default:
		return -EINVAL;
	}

	val <<= (frac_bits - 31);
	regmap_write(easrc->regmap, REG_EASRC_RUC(pair->index), EASRC_RSUC_RS_RM(val));

	return 0;
}

static int fsl_easrc_m2m_get_cap(struct fsl_asrc_m2m_cap *cap)
{
	cap->fmt_in = FSL_EASRC_FORMATS;
	cap->fmt_out = FSL_EASRC_FORMATS | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
	cap->rate_in = easrc_rates;
	cap->rate_in_count = ARRAY_SIZE(easrc_rates);
	cap->rate_out = easrc_rates;
	cap->rate_out_count = ARRAY_SIZE(easrc_rates);
	cap->chan_min = 1;
	cap->chan_max = 32;
	return 0;
}

static const struct of_device_id fsl_easrc_dt_ids[] = {
	{ .compatible = "fsl,imx8mn-easrc",},
	{}
@@ -1926,6 +2144,16 @@ static int fsl_easrc_probe(struct platform_device *pdev)
	easrc->release_pair = fsl_easrc_release_context;
	easrc->get_fifo_addr = fsl_easrc_get_fifo_addr;
	easrc->pair_priv_size = sizeof(struct fsl_easrc_ctx_priv);
	easrc->m2m_prepare = fsl_easrc_m2m_prepare;
	easrc->m2m_start = fsl_easrc_m2m_start;
	easrc->m2m_stop = fsl_easrc_m2m_stop;
	easrc->get_output_fifo_size = fsl_easrc_get_output_fifo_size;
	easrc->m2m_calc_out_len = fsl_easrc_m2m_calc_out_len;
	easrc->m2m_get_maxburst = fsl_easrc_m2m_get_maxburst;
	easrc->m2m_pair_suspend = fsl_easrc_m2m_pair_suspend;
	easrc->m2m_pair_resume = fsl_easrc_m2m_pair_resume;
	easrc->m2m_set_ratio_mod = fsl_easrc_m2m_set_ratio_mod;
	easrc->m2m_get_cap = fsl_easrc_m2m_get_cap;

	easrc_priv->rs_num_taps = EASRC_RS_32_TAPS;
	easrc_priv->const_coeff = 0x3FF0000000000000;
+4 −0
Original line number Diff line number Diff line
@@ -601,6 +601,8 @@ struct fsl_easrc_slot {
 * @out_missed_sample: sample missed in output
 * @st1_addexp: exponent added for stage1
 * @st2_addexp: exponent added for stage2
 * @ratio_mod: update ratio
 * @in_filled_len: input filled length
 */
struct fsl_easrc_ctx_priv {
	struct fsl_easrc_io_params in_params;
@@ -618,6 +620,8 @@ struct fsl_easrc_ctx_priv {
	int out_missed_sample;
	int st1_addexp;
	int st2_addexp;
	int ratio_mod;
	unsigned int in_filled_len;
};

/**