mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 12:21:22 -05:00
ASoC: fsl_asrc: define functions for memory to memory usage
ASRC can be used on memory to memory case, define several functions for m2m usage. m2m_prepare: prepare for the start step m2m_start: the start step m2m_unprepare: unprepare for stop step, optional m2m_stop: stop step m2m_check_format: check format is supported or not m2m_calc_out_len: calculate output length according to input length m2m_get_maxburst: burst size for dma m2m_pair_suspend: suspend function of pair, optional. m2m_pair_resume: resume function of pair get_output_fifo_size: get remaining data size in FIFO Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Acked-by: Jaroslav Kysela <perex@perex.cz> Link: https://patch.msgid.link/20241212074509.3445859-3-shengjiu.wang@nxp.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
committed by
Mark Brown
parent
f4425e3ab2
commit
8ea7d04a4e
@@ -1063,6 +1063,139 @@ static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
|
||||
return REG_ASRDx(dir, index);
|
||||
}
|
||||
|
||||
/* Get sample numbers in FIFO */
|
||||
static unsigned int fsl_asrc_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_ASRFST(index), &val);
|
||||
|
||||
val &= ASRFSTi_OUTPUT_FIFO_MASK;
|
||||
|
||||
return val >> ASRFSTi_OUTPUT_FIFO_SHIFT;
|
||||
}
|
||||
|
||||
static int fsl_asrc_m2m_prepare(struct fsl_asrc_pair *pair)
|
||||
{
|
||||
struct fsl_asrc_pair_priv *pair_priv = pair->private;
|
||||
struct fsl_asrc *asrc = pair->asrc;
|
||||
struct device *dev = &asrc->pdev->dev;
|
||||
struct asrc_config config;
|
||||
int ret;
|
||||
|
||||
/* fill config */
|
||||
config.pair = pair->index;
|
||||
config.channel_num = pair->channels;
|
||||
config.input_sample_rate = pair->rate[IN];
|
||||
config.output_sample_rate = pair->rate[OUT];
|
||||
config.input_format = pair->sample_format[IN];
|
||||
config.output_format = pair->sample_format[OUT];
|
||||
config.inclk = INCLK_NONE;
|
||||
config.outclk = OUTCLK_ASRCK1_CLK;
|
||||
|
||||
pair_priv->config = &config;
|
||||
ret = fsl_asrc_config_pair(pair, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to config pair: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pair->first_convert = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair)
|
||||
{
|
||||
if (pair->first_convert) {
|
||||
fsl_asrc_start_pair(pair);
|
||||
pair->first_convert = 0;
|
||||
}
|
||||
/*
|
||||
* Clear DMA request during the stall state of ASRC:
|
||||
* During STALL state, the remaining in input fifo would never be
|
||||
* smaller than the input threshold while the output fifo would not
|
||||
* be bigger than output one. Thus the DMA request would be cleared.
|
||||
*/
|
||||
fsl_asrc_set_watermarks(pair, ASRC_FIFO_THRESHOLD_MIN,
|
||||
ASRC_FIFO_THRESHOLD_MAX);
|
||||
|
||||
/* Update the real input threshold to raise DMA request */
|
||||
fsl_asrc_set_watermarks(pair, ASRC_M2M_INPUTFIFO_WML,
|
||||
ASRC_M2M_OUTPUTFIFO_WML);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_m2m_stop(struct fsl_asrc_pair *pair)
|
||||
{
|
||||
if (!pair->first_convert) {
|
||||
fsl_asrc_stop_pair(pair);
|
||||
pair->first_convert = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* calculate capture data length according to output data length and sample rate */
|
||||
static int fsl_asrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buffer_length)
|
||||
{
|
||||
unsigned int in_width, out_width;
|
||||
unsigned int channels = pair->channels;
|
||||
unsigned int in_samples, out_samples;
|
||||
unsigned int out_length;
|
||||
|
||||
in_width = snd_pcm_format_physical_width(pair->sample_format[IN]) / 8;
|
||||
out_width = snd_pcm_format_physical_width(pair->sample_format[OUT]) / 8;
|
||||
|
||||
in_samples = input_buffer_length / in_width / channels;
|
||||
out_samples = pair->rate[OUT] * in_samples / pair->rate[IN];
|
||||
out_length = (out_samples - ASRC_OUTPUT_LAST_SAMPLE) * out_width * channels;
|
||||
|
||||
return out_length;
|
||||
}
|
||||
|
||||
static int fsl_asrc_m2m_get_maxburst(u8 dir, struct fsl_asrc_pair *pair)
|
||||
{
|
||||
struct fsl_asrc *asrc = pair->asrc;
|
||||
struct fsl_asrc_priv *asrc_priv = asrc->private;
|
||||
int wml = (dir == IN) ? ASRC_M2M_INPUTFIFO_WML : ASRC_M2M_OUTPUTFIFO_WML;
|
||||
|
||||
if (!asrc_priv->soc->use_edma)
|
||||
return wml * pair->channels;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fsl_asrc_m2m_get_cap(struct fsl_asrc_m2m_cap *cap)
|
||||
{
|
||||
cap->fmt_in = FSL_ASRC_FORMATS;
|
||||
cap->fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8;
|
||||
|
||||
cap->rate_in = supported_asrc_rate;
|
||||
cap->rate_in_count = ARRAY_SIZE(supported_asrc_rate);
|
||||
cap->rate_out = supported_asrc_rate;
|
||||
cap->rate_out_count = ARRAY_SIZE(supported_asrc_rate);
|
||||
cap->chan_min = 1;
|
||||
cap->chan_max = 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_m2m_pair_resume(struct fsl_asrc_pair *pair)
|
||||
{
|
||||
struct fsl_asrc *asrc = pair->asrc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pair->channels * 4; i++)
|
||||
regmap_write(asrc->regmap, REG_ASRDI(pair->index), 0);
|
||||
|
||||
pair->first_convert = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_asrc_runtime_resume(struct device *dev);
|
||||
static int fsl_asrc_runtime_suspend(struct device *dev);
|
||||
|
||||
@@ -1147,6 +1280,15 @@ static int fsl_asrc_probe(struct platform_device *pdev)
|
||||
asrc->get_fifo_addr = fsl_asrc_get_fifo_addr;
|
||||
asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv);
|
||||
|
||||
asrc->m2m_prepare = fsl_asrc_m2m_prepare;
|
||||
asrc->m2m_start = fsl_asrc_m2m_start;
|
||||
asrc->m2m_stop = fsl_asrc_m2m_stop;
|
||||
asrc->get_output_fifo_size = fsl_asrc_get_output_fifo_size;
|
||||
asrc->m2m_calc_out_len = fsl_asrc_m2m_calc_out_len;
|
||||
asrc->m2m_get_maxburst = fsl_asrc_m2m_get_maxburst;
|
||||
asrc->m2m_pair_resume = fsl_asrc_m2m_pair_resume;
|
||||
asrc->m2m_get_cap = fsl_asrc_m2m_get_cap;
|
||||
|
||||
if (of_device_is_compatible(np, "fsl,imx35-asrc")) {
|
||||
asrc_priv->clk_map[IN] = input_clk_map_imx35;
|
||||
asrc_priv->clk_map[OUT] = output_clk_map_imx35;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
#include "fsl_asrc_common.h"
|
||||
|
||||
#define ASRC_M2M_INPUTFIFO_WML 0x4
|
||||
#define ASRC_M2M_OUTPUTFIFO_WML 0x2
|
||||
#define ASRC_DMA_BUFFER_NUM 2
|
||||
#define ASRC_INPUTFIFO_THRESHOLD 32
|
||||
#define ASRC_OUTPUTFIFO_THRESHOLD 32
|
||||
|
||||
@@ -21,6 +21,26 @@ enum asrc_pair_index {
|
||||
|
||||
#define PAIR_CTX_NUM 0x4
|
||||
|
||||
/**
|
||||
* struct fsl_asrc_m2m_cap - capability data
|
||||
* @fmt_in: input sample format
|
||||
* @fmt_out: output sample format
|
||||
* @chan_min: minimum channel number
|
||||
* @chan_max: maximum channel number
|
||||
* @rate_in: minimum rate
|
||||
* @rate_out: maximum rete
|
||||
*/
|
||||
struct fsl_asrc_m2m_cap {
|
||||
u64 fmt_in;
|
||||
u64 fmt_out;
|
||||
int chan_min;
|
||||
int chan_max;
|
||||
const unsigned int *rate_in;
|
||||
int rate_in_count;
|
||||
const unsigned int *rate_out;
|
||||
int rate_out_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* fsl_asrc_pair: ASRC Pair common data
|
||||
*
|
||||
@@ -34,6 +54,13 @@ enum asrc_pair_index {
|
||||
* @pos: hardware pointer position
|
||||
* @req_dma_chan: flag to release dev_to_dev chan
|
||||
* @private: pair private area
|
||||
* @complete: dma task complete
|
||||
* @sample_format: format of m2m
|
||||
* @rate: rate of m2m
|
||||
* @buf_len: buffer length of m2m
|
||||
* @dma_buffer: buffer pointers
|
||||
* @first_convert: start of conversion
|
||||
* @ratio_mod: ratio modification
|
||||
*/
|
||||
struct fsl_asrc_pair {
|
||||
struct fsl_asrc *asrc;
|
||||
@@ -49,6 +76,15 @@ struct fsl_asrc_pair {
|
||||
bool req_dma_chan;
|
||||
|
||||
void *private;
|
||||
|
||||
/* used for m2m */
|
||||
struct completion complete[2];
|
||||
snd_pcm_format_t sample_format[2];
|
||||
unsigned int rate[2];
|
||||
unsigned int buf_len[2];
|
||||
struct snd_dma_buffer dma_buffer[2];
|
||||
unsigned int first_convert;
|
||||
unsigned int ratio_mod;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -72,6 +108,17 @@ struct fsl_asrc_pair {
|
||||
* @request_pair: function pointer
|
||||
* @release_pair: function pointer
|
||||
* @get_fifo_addr: function pointer
|
||||
* @m2m_get_cap: function pointer
|
||||
* @m2m_prepare: function pointer
|
||||
* @m2m_start: function pointer
|
||||
* @m2m_unprepare: function pointer
|
||||
* @m2m_stop: function pointer
|
||||
* @m2m_calc_out_len: function pointer
|
||||
* @m2m_get_maxburst: function pointer
|
||||
* @m2m_pair_suspend: function pointer
|
||||
* @m2m_pair_resume: function pointer
|
||||
* @m2m_set_ratio_mod: function pointer
|
||||
* @get_output_fifo_size: function pointer
|
||||
* @pair_priv_size: size of pair private struct.
|
||||
* @private: private data structure
|
||||
*/
|
||||
@@ -97,6 +144,20 @@ struct fsl_asrc {
|
||||
int (*request_pair)(int channels, struct fsl_asrc_pair *pair);
|
||||
void (*release_pair)(struct fsl_asrc_pair *pair);
|
||||
int (*get_fifo_addr)(u8 dir, enum asrc_pair_index index);
|
||||
int (*m2m_get_cap)(struct fsl_asrc_m2m_cap *cap);
|
||||
|
||||
int (*m2m_prepare)(struct fsl_asrc_pair *pair);
|
||||
int (*m2m_start)(struct fsl_asrc_pair *pair);
|
||||
int (*m2m_unprepare)(struct fsl_asrc_pair *pair);
|
||||
int (*m2m_stop)(struct fsl_asrc_pair *pair);
|
||||
|
||||
int (*m2m_calc_out_len)(struct fsl_asrc_pair *pair, int input_buffer_length);
|
||||
int (*m2m_get_maxburst)(u8 dir, struct fsl_asrc_pair *pair);
|
||||
int (*m2m_pair_suspend)(struct fsl_asrc_pair *pair);
|
||||
int (*m2m_pair_resume)(struct fsl_asrc_pair *pair);
|
||||
int (*m2m_set_ratio_mod)(struct fsl_asrc_pair *pair, int val);
|
||||
|
||||
unsigned int (*get_output_fifo_size)(struct fsl_asrc_pair *pair);
|
||||
size_t pair_priv_size;
|
||||
|
||||
void *private;
|
||||
|
||||
Reference in New Issue
Block a user