[PATCH v6 0/7] ASoC: Add new module driver for new ASRC
Add new module driver for new ASRC in i.MX8MN, several commits are added for new property fsl,asrc-format
Shengjiu Wang (7): ASoC: fsl_asrc: rename asrc_priv to asrc ASoC: dt-bindings: fsl_asrc: Add new property fsl,asrc-format ASoC: fsl-asoc-card: Support new property fsl,asrc-format ASoC: fsl_asrc: Support new property fsl,asrc-format ASoC: fsl_asrc: Move common definition to fsl_asrc_common ASoC: dt-bindings: fsl_easrc: Add document for EASRC ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers
changes in v6 - updated according to Nicoin's and Rob's comments.
changes in v5 - Add new property fsl,asrc-format, rather than change fsl,asrc-width to fsl,asrc-formt. - code change for above change.
changes in v4 - Add several commit for changing DT binding asrc-width to asrc-format - rename asrc_priv to asrc
changes in v3 - add new commit "ASoC: fsl_asrc: Change asrc_width to asrc_format" - modify binding doc to yaml format - remove fsl_easrc_dma.c, make fsl_asrc_dma.c useable for easrc.
changes in v2 - change i.MX815 to i.MX8MN - Add changes in Kconfig and Makefile
.../devicetree/bindings/sound/fsl,asrc.txt | 4 + .../devicetree/bindings/sound/fsl,easrc.yaml | 101 + sound/soc/fsl/Kconfig | 11 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl-asoc-card.c | 21 +- sound/soc/fsl/fsl_asrc.c | 303 +-- sound/soc/fsl/fsl_asrc.h | 74 +- sound/soc/fsl/fsl_asrc_common.h | 105 + sound/soc/fsl/fsl_asrc_dma.c | 54 +- sound/soc/fsl/fsl_easrc.c | 2114 +++++++++++++++++ sound/soc/fsl/fsl_easrc.h | 651 +++++ 11 files changed, 3206 insertions(+), 234 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/fsl,easrc.yaml create mode 100644 sound/soc/fsl/fsl_asrc_common.h create mode 100644 sound/soc/fsl/fsl_easrc.c create mode 100644 sound/soc/fsl/fsl_easrc.h
In order to move common structure to fsl_asrc_common.h we change the name of asrc_priv to asrc, the asrc_priv will be used by new struct fsl_asrc_priv.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl_asrc.c | 298 +++++++++++++++++------------------ sound/soc/fsl/fsl_asrc.h | 4 +- sound/soc/fsl/fsl_asrc_dma.c | 24 +-- 3 files changed, 163 insertions(+), 163 deletions(-)
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 0dcebc24c312..4d3e51bfa949 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -21,10 +21,10 @@ #define IDEAL_RATIO_DECIMAL_DEPTH 26
#define pair_err(fmt, ...) \ - dev_err(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) + dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
#define pair_dbg(fmt, ...) \ - dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) + dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
/* Corresponding to process_option */ static unsigned int supported_asrc_rate[] = { @@ -157,15 +157,15 @@ static void fsl_asrc_sel_proc(int inrate, int outrate, int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) { enum asrc_pair_index index = ASRC_INVALID_PAIR; - struct fsl_asrc *asrc_priv = pair->asrc_priv; - struct device *dev = &asrc_priv->pdev->dev; + struct fsl_asrc *asrc = pair->asrc; + struct device *dev = &asrc->pdev->dev; unsigned long lock_flags; int i, ret = 0;
- spin_lock_irqsave(&asrc_priv->lock, lock_flags); + spin_lock_irqsave(&asrc->lock, lock_flags);
for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { - if (asrc_priv->pair[i] != NULL) + if (asrc->pair[i] != NULL) continue;
index = i; @@ -177,17 +177,17 @@ int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) if (index == ASRC_INVALID_PAIR) { dev_err(dev, "all pairs are busy now\n"); ret = -EBUSY; - } else if (asrc_priv->channel_avail < channels) { + } else if (asrc->channel_avail < channels) { dev_err(dev, "can't afford required channels: %d\n", channels); ret = -EINVAL; } else { - asrc_priv->channel_avail -= channels; - asrc_priv->pair[index] = pair; + asrc->channel_avail -= channels; + asrc->pair[index] = pair; pair->channels = channels; pair->index = index; }
- spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); + spin_unlock_irqrestore(&asrc->lock, lock_flags);
return ret; } @@ -195,25 +195,25 @@ int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) /** * Release ASRC pair * - * It clears the resource from asrc_priv and releases the occupied channels. + * It clears the resource from asrc and releases the occupied channels. */ void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) { - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; unsigned long lock_flags;
/* Make sure the pair is disabled */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_MASK(index), 0);
- spin_lock_irqsave(&asrc_priv->lock, lock_flags); + spin_lock_irqsave(&asrc->lock, lock_flags);
- asrc_priv->channel_avail += pair->channels; - asrc_priv->pair[index] = NULL; + asrc->channel_avail += pair->channels; + asrc->pair[index] = NULL; pair->error = 0;
- spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); + spin_unlock_irqrestore(&asrc->lock, lock_flags); }
/** @@ -221,10 +221,10 @@ void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) */ static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) { - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index;
- regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), + regmap_update_bits(asrc->regmap, REG_ASRMCR(index), ASRMCRi_EXTTHRSHi_MASK | ASRMCRi_INFIFO_THRESHOLD_MASK | ASRMCRi_OUTFIFO_THRESHOLD_MASK, @@ -257,7 +257,7 @@ static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, int inrate, int outrate) { - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; unsigned long ratio; int i; @@ -286,8 +286,8 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, break; }
- regmap_write(asrc_priv->regmap, REG_ASRIDRL(index), ratio); - regmap_write(asrc_priv->regmap, REG_ASRIDRH(index), ratio >> 24); + regmap_write(asrc->regmap, REG_ASRIDRL(index), ratio); + regmap_write(asrc->regmap, REG_ASRIDRH(index), ratio >> 24);
return 0; } @@ -309,7 +309,7 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) { struct asrc_config *config = pair->config; - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; enum asrc_word_width input_word_width; enum asrc_word_width output_word_width; @@ -392,11 +392,11 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) }
/* Validate input and output clock sources */ - clk_index[IN] = asrc_priv->clk_map[IN][config->inclk]; - clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk]; + clk_index[IN] = asrc->clk_map[IN][config->inclk]; + clk_index[OUT] = asrc->clk_map[OUT][config->outclk];
/* We only have output clock for ideal ratio mode */ - clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; + clk = asrc->asrck_clk[clk_index[ideal ? OUT : IN]];
clk_rate = clk_get_rate(clk); rem[IN] = do_div(clk_rate, inrate); @@ -417,7 +417,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
div[IN] = min_t(u32, 1024, div[IN]);
- clk = asrc_priv->asrck_clk[clk_index[OUT]]; + clk = asrc->asrck_clk[clk_index[OUT]]; clk_rate = clk_get_rate(clk); if (ideal && use_ideal_rate) rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE); @@ -437,22 +437,22 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) /* Set the channel number */ channels = config->channel_num;
- if (asrc_priv->soc->channel_bits < 4) + if (asrc->soc->channel_bits < 4) channels /= 2;
/* Update channels for current pair */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR, - ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits), - ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits)); + regmap_update_bits(asrc->regmap, REG_ASRCNCR, + ASRCNCR_ANCi_MASK(index, asrc->soc->channel_bits), + ASRCNCR_ANCi(index, channels, asrc->soc->channel_bits));
/* Default setting: Automatic selection for processing mode */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_USRi_MASK(index), 0);
/* Set the input and output clock sources */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCSR, + regmap_update_bits(asrc->regmap, REG_ASRCSR, ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), ASRCSR_AICS(index, clk_index[IN]) | ASRCSR_AOCS(index, clk_index[OUT])); @@ -462,19 +462,19 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]);
/* Suppose indiv and outdiv includes prescaler, so add its MASK too */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCDR(index), + regmap_update_bits(asrc->regmap, REG_ASRCDR(index), ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv));
/* Implement word_width configurations */ - regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index), + regmap_update_bits(asrc->regmap, REG_ASRMCR1(index), ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, ASRMCR1i_OW16(output_word_width) | ASRMCR1i_IWD(input_word_width));
/* Enable BUFFER STALL */ - regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), + regmap_update_bits(asrc->regmap, REG_ASRMCR(index), ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi);
/* Set default thresholds for input and output FIFO */ @@ -486,18 +486,18 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) return 0;
/* Clear ASTSx bit to use Ideal Ratio mode */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ATSi_MASK(index), 0);
/* Enable Ideal Ratio mode */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), ASRCTR_IDR(index) | ASRCTR_USR(index));
fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc);
/* Apply configurations for pre- and post-processing */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, + regmap_update_bits(asrc->regmap, REG_ASRCFG, ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), ASRCFG_PREMOD(index, pre_proc) | ASRCFG_POSTMOD(index, post_proc)); @@ -512,28 +512,28 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) */ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) { - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; int reg, retry = 10, i;
/* Enable the current pair */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index));
/* Wait for status of initialization */ do { udelay(5); - regmap_read(asrc_priv->regmap, REG_ASRCFG, ®); + regmap_read(asrc->regmap, REG_ASRCFG, ®); reg &= ASRCFG_INIRQi_MASK(index); } while (!reg && --retry);
/* Make the input fifo to ASRC STALL level */ - regmap_read(asrc_priv->regmap, REG_ASRCNCR, ®); + regmap_read(asrc->regmap, REG_ASRCNCR, ®); for (i = 0; i < pair->channels * 4; i++) - regmap_write(asrc_priv->regmap, REG_ASRDI(index), 0); + regmap_write(asrc->regmap, REG_ASRDI(index), 0);
/* Enable overload interrupt */ - regmap_write(asrc_priv->regmap, REG_ASRIER, ASRIER_AOLIE); + regmap_write(asrc->regmap, REG_ASRIER, ASRIER_AOLIE); }
/** @@ -541,11 +541,11 @@ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) */ static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) { - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index;
/* Stop the current pair */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_MASK(index), 0); }
@@ -554,23 +554,23 @@ static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) */ struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir) { - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; char name[4];
sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a');
- return dma_request_slave_channel(&asrc_priv->pdev->dev, name); + return dma_request_slave_channel(&asrc->pdev->dev, name); } EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel);
static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); + struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
/* Odd channel number is not valid for older ASRC (channel_bits==3) */ - if (asrc_priv->soc->channel_bits == 3) + if (asrc->soc->channel_bits == 3) snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
@@ -583,7 +583,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); + struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; unsigned int channels = params_channels(params); @@ -600,7 +600,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
pair->config = &config;
- if (asrc_priv->asrc_width == 16) + if (asrc->asrc_width == 16) format = SNDRV_PCM_FORMAT_S16_LE; else format = SNDRV_PCM_FORMAT_S24_LE; @@ -614,11 +614,11 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, config.input_format = params_format(params); config.output_format = format; config.input_sample_rate = rate; - config.output_sample_rate = asrc_priv->asrc_rate; + config.output_sample_rate = asrc->asrc_rate; } else { config.input_format = format; config.output_format = params_format(params); - config.input_sample_rate = asrc_priv->asrc_rate; + config.input_sample_rate = asrc->asrc_rate; config.output_sample_rate = rate; }
@@ -676,10 +676,10 @@ static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) { - struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); + struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
- snd_soc_dai_init_dma_data(dai, &asrc_priv->dma_params_tx, - &asrc_priv->dma_params_rx); + snd_soc_dai_init_dma_data(dai, &asrc->dma_params_tx, + &asrc->dma_params_rx);
return 0; } @@ -858,30 +858,30 @@ static const struct regmap_config fsl_asrc_regmap_config = { /** * Initialize ASRC registers with a default configurations */ -static int fsl_asrc_init(struct fsl_asrc *asrc_priv) +static int fsl_asrc_init(struct fsl_asrc *asrc) { /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ - regmap_write(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEN); + regmap_write(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN);
/* Disable interrupt by default */ - regmap_write(asrc_priv->regmap, REG_ASRIER, 0x0); + regmap_write(asrc->regmap, REG_ASRIER, 0x0);
/* Apply recommended settings for parameters from Reference Manual */ - regmap_write(asrc_priv->regmap, REG_ASRPM1, 0x7fffff); - regmap_write(asrc_priv->regmap, REG_ASRPM2, 0x255555); - regmap_write(asrc_priv->regmap, REG_ASRPM3, 0xff7280); - regmap_write(asrc_priv->regmap, REG_ASRPM4, 0xff7280); - regmap_write(asrc_priv->regmap, REG_ASRPM5, 0xff7280); + regmap_write(asrc->regmap, REG_ASRPM1, 0x7fffff); + regmap_write(asrc->regmap, REG_ASRPM2, 0x255555); + regmap_write(asrc->regmap, REG_ASRPM3, 0xff7280); + regmap_write(asrc->regmap, REG_ASRPM4, 0xff7280); + regmap_write(asrc->regmap, REG_ASRPM5, 0xff7280);
/* Base address for task queue FIFO. Set to 0x7C */ - regmap_update_bits(asrc_priv->regmap, REG_ASRTFR1, + regmap_update_bits(asrc->regmap, REG_ASRTFR1, ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc));
/* Set the processing clock for 76KHz to 133M */ - regmap_write(asrc_priv->regmap, REG_ASR76K, 0x06D6); + regmap_write(asrc->regmap, REG_ASR76K, 0x06D6);
/* Set the processing clock for 56KHz to 133M */ - return regmap_write(asrc_priv->regmap, REG_ASR56K, 0x0947); + return regmap_write(asrc->regmap, REG_ASR56K, 0x0947); }
/** @@ -889,15 +889,15 @@ static int fsl_asrc_init(struct fsl_asrc *asrc_priv) */ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) { - struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id; - struct device *dev = &asrc_priv->pdev->dev; + struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id; + struct device *dev = &asrc->pdev->dev; enum asrc_pair_index index; u32 status;
- regmap_read(asrc_priv->regmap, REG_ASRSTR, &status); + regmap_read(asrc->regmap, REG_ASRSTR, &status);
/* Clean overload error */ - regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE); + regmap_write(asrc->regmap, REG_ASRSTR, ASRSTR_AOLE);
/* * We here use dev_dbg() for all exceptions because ASRC itself does @@ -905,31 +905,31 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) * interrupt would result a ridged conversion. */ for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { - if (!asrc_priv->pair[index]) + if (!asrc->pair[index]) continue;
if (status & ASRSTR_ATQOL) { - asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; + asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); }
if (status & ASRSTR_AOOL(index)) { - asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; + asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; pair_dbg("Output Task Overload\n"); }
if (status & ASRSTR_AIOL(index)) { - asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; + asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; pair_dbg("Input Task Overload\n"); }
if (status & ASRSTR_AODO(index)) { - asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; + asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; pair_dbg("Output Data Buffer has overflowed\n"); }
if (status & ASRSTR_AIDU(index)) { - asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; + asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; pair_dbg("Input Data Buffer has underflowed\n"); } } @@ -940,18 +940,18 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) static int fsl_asrc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct fsl_asrc *asrc_priv; + struct fsl_asrc *asrc; struct resource *res; void __iomem *regs; int irq, ret, i; u32 map_idx; char tmp[16];
- asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); - if (!asrc_priv) + asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL); + if (!asrc) return -ENOMEM;
- asrc_priv->pdev = pdev; + asrc->pdev = pdev;
/* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -959,13 +959,13 @@ static int fsl_asrc_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs);
- asrc_priv->paddr = res->start; + asrc->paddr = res->start;
- asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, - &fsl_asrc_regmap_config); - if (IS_ERR(asrc_priv->regmap)) { + asrc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, + &fsl_asrc_regmap_config); + if (IS_ERR(asrc->regmap)) { dev_err(&pdev->dev, "failed to init regmap\n"); - return PTR_ERR(asrc_priv->regmap); + return PTR_ERR(asrc->regmap); }
irq = platform_get_irq(pdev, 0); @@ -973,49 +973,49 @@ static int fsl_asrc_probe(struct platform_device *pdev) return irq;
ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, - dev_name(&pdev->dev), asrc_priv); + dev_name(&pdev->dev), asrc); if (ret) { dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); return ret; }
- asrc_priv->mem_clk = devm_clk_get(&pdev->dev, "mem"); - if (IS_ERR(asrc_priv->mem_clk)) { + asrc->mem_clk = devm_clk_get(&pdev->dev, "mem"); + if (IS_ERR(asrc->mem_clk)) { dev_err(&pdev->dev, "failed to get mem clock\n"); - return PTR_ERR(asrc_priv->mem_clk); + return PTR_ERR(asrc->mem_clk); }
- asrc_priv->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(asrc_priv->ipg_clk)) { + asrc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(asrc->ipg_clk)) { dev_err(&pdev->dev, "failed to get ipg clock\n"); - return PTR_ERR(asrc_priv->ipg_clk); + return PTR_ERR(asrc->ipg_clk); }
- asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba"); - if (IS_ERR(asrc_priv->spba_clk)) + asrc->spba_clk = devm_clk_get(&pdev->dev, "spba"); + if (IS_ERR(asrc->spba_clk)) dev_warn(&pdev->dev, "failed to get spba clock\n");
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { sprintf(tmp, "asrck_%x", i); - asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); - if (IS_ERR(asrc_priv->asrck_clk[i])) { + asrc->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); + if (IS_ERR(asrc->asrck_clk[i])) { dev_err(&pdev->dev, "failed to get %s clock\n", tmp); - return PTR_ERR(asrc_priv->asrck_clk[i]); + return PTR_ERR(asrc->asrck_clk[i]); } }
- asrc_priv->soc = of_device_get_match_data(&pdev->dev); - if (!asrc_priv->soc) { + asrc->soc = of_device_get_match_data(&pdev->dev); + if (!asrc->soc) { dev_err(&pdev->dev, "failed to get soc data\n"); return -ENODEV; }
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; + asrc->clk_map[IN] = input_clk_map_imx35; + asrc->clk_map[OUT] = output_clk_map_imx35; } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { - asrc_priv->clk_map[IN] = input_clk_map_imx53; - asrc_priv->clk_map[OUT] = output_clk_map_imx53; + asrc->clk_map[IN] = input_clk_map_imx53; + asrc->clk_map[OUT] = output_clk_map_imx53; } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") || of_device_is_compatible(np, "fsl,imx8qxp-asrc")) { ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx); @@ -1029,44 +1029,44 @@ static int fsl_asrc_probe(struct platform_device *pdev) return -EINVAL; } if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) { - asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx]; - asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx]; + asrc->clk_map[IN] = clk_map_imx8qm[map_idx]; + asrc->clk_map[OUT] = clk_map_imx8qm[map_idx]; } else { - asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx]; - asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx]; + asrc->clk_map[IN] = clk_map_imx8qxp[map_idx]; + asrc->clk_map[OUT] = clk_map_imx8qxp[map_idx]; } }
- ret = fsl_asrc_init(asrc_priv); + ret = fsl_asrc_init(asrc); if (ret) { dev_err(&pdev->dev, "failed to init asrc %d\n", ret); return ret; }
- asrc_priv->channel_avail = 10; + asrc->channel_avail = 10;
ret = of_property_read_u32(np, "fsl,asrc-rate", - &asrc_priv->asrc_rate); + &asrc->asrc_rate); if (ret) { dev_err(&pdev->dev, "failed to get output rate\n"); return ret; }
ret = of_property_read_u32(np, "fsl,asrc-width", - &asrc_priv->asrc_width); + &asrc->asrc_width); if (ret) { dev_err(&pdev->dev, "failed to get output width\n"); return ret; }
- if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) { + if (asrc->asrc_width != 16 && asrc->asrc_width != 24) { dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); - asrc_priv->asrc_width = 24; + asrc->asrc_width = 24; }
- platform_set_drvdata(pdev, asrc_priv); + platform_set_drvdata(pdev, asrc); pm_runtime_enable(&pdev->dev); - spin_lock_init(&asrc_priv->lock); + spin_lock_init(&asrc->lock);
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, &fsl_asrc_dai, 1); @@ -1081,22 +1081,22 @@ static int fsl_asrc_probe(struct platform_device *pdev) #ifdef CONFIG_PM static int fsl_asrc_runtime_resume(struct device *dev) { - struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + struct fsl_asrc *asrc = dev_get_drvdata(dev); int i, ret;
- ret = clk_prepare_enable(asrc_priv->mem_clk); + ret = clk_prepare_enable(asrc->mem_clk); if (ret) return ret; - ret = clk_prepare_enable(asrc_priv->ipg_clk); + ret = clk_prepare_enable(asrc->ipg_clk); if (ret) goto disable_mem_clk; - if (!IS_ERR(asrc_priv->spba_clk)) { - ret = clk_prepare_enable(asrc_priv->spba_clk); + if (!IS_ERR(asrc->spba_clk)) { + ret = clk_prepare_enable(asrc->spba_clk); if (ret) goto disable_ipg_clk; } for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { - ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); + ret = clk_prepare_enable(asrc->asrck_clk[i]); if (ret) goto disable_asrck_clk; } @@ -1105,27 +1105,27 @@ static int fsl_asrc_runtime_resume(struct device *dev)
disable_asrck_clk: for (i--; i >= 0; i--) - clk_disable_unprepare(asrc_priv->asrck_clk[i]); - if (!IS_ERR(asrc_priv->spba_clk)) - clk_disable_unprepare(asrc_priv->spba_clk); + clk_disable_unprepare(asrc->asrck_clk[i]); + if (!IS_ERR(asrc->spba_clk)) + clk_disable_unprepare(asrc->spba_clk); disable_ipg_clk: - clk_disable_unprepare(asrc_priv->ipg_clk); + clk_disable_unprepare(asrc->ipg_clk); disable_mem_clk: - clk_disable_unprepare(asrc_priv->mem_clk); + clk_disable_unprepare(asrc->mem_clk); return ret; }
static int fsl_asrc_runtime_suspend(struct device *dev) { - struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + struct fsl_asrc *asrc = dev_get_drvdata(dev); int i;
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) - clk_disable_unprepare(asrc_priv->asrck_clk[i]); - if (!IS_ERR(asrc_priv->spba_clk)) - clk_disable_unprepare(asrc_priv->spba_clk); - clk_disable_unprepare(asrc_priv->ipg_clk); - clk_disable_unprepare(asrc_priv->mem_clk); + clk_disable_unprepare(asrc->asrck_clk[i]); + if (!IS_ERR(asrc->spba_clk)) + clk_disable_unprepare(asrc->spba_clk); + clk_disable_unprepare(asrc->ipg_clk); + clk_disable_unprepare(asrc->mem_clk);
return 0; } @@ -1134,37 +1134,37 @@ static int fsl_asrc_runtime_suspend(struct device *dev) #ifdef CONFIG_PM_SLEEP static int fsl_asrc_suspend(struct device *dev) { - struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + struct fsl_asrc *asrc = dev_get_drvdata(dev);
- regmap_read(asrc_priv->regmap, REG_ASRCFG, - &asrc_priv->regcache_cfg); + regmap_read(asrc->regmap, REG_ASRCFG, + &asrc->regcache_cfg);
- regcache_cache_only(asrc_priv->regmap, true); - regcache_mark_dirty(asrc_priv->regmap); + regcache_cache_only(asrc->regmap, true); + regcache_mark_dirty(asrc->regmap);
return 0; }
static int fsl_asrc_resume(struct device *dev) { - struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + struct fsl_asrc *asrc = dev_get_drvdata(dev); u32 asrctr;
/* Stop all pairs provisionally */ - regmap_read(asrc_priv->regmap, REG_ASRCTR, &asrctr); - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_read(asrc->regmap, REG_ASRCTR, &asrctr); + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_ALL_MASK, 0);
/* Restore all registers */ - regcache_cache_only(asrc_priv->regmap, false); - regcache_sync(asrc_priv->regmap); + regcache_cache_only(asrc->regmap, false); + regcache_sync(asrc->regmap);
- regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, + regmap_update_bits(asrc->regmap, REG_ASRCFG, ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | - ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); + ASRCFG_PREMODi_ALL_MASK, asrc->regcache_cfg);
/* Restart enabled pairs */ - regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_ALL_MASK, asrctr);
return 0; diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 8a821132d9d0..95d62c45afde 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -448,7 +448,7 @@ struct fsl_asrc_soc_data { /** * fsl_asrc_pair: ASRC Pair private data * - * @asrc_priv: pointer to its parent module + * @asrc: pointer to its parent module * @config: configuration profile * @error: error record * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C) @@ -460,7 +460,7 @@ struct fsl_asrc_soc_data { * @private: pair private area */ struct fsl_asrc_pair { - struct fsl_asrc *asrc_priv; + struct fsl_asrc *asrc; struct asrc_config *config; unsigned int error;
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index e7178817d7a7..5fe83aece25b 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -135,7 +135,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_dmaengine_dai_dma_data *dma_params_be = NULL; struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; - struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct fsl_asrc *asrc = pair->asrc; struct dma_slave_config config_fe, config_be; enum asrc_pair_index index = pair->index; struct device *dev = component->dev; @@ -170,7 +170,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
/* Override dma_data of the Front-End and config its dmaengine */ dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); - dma_params_fe->addr = asrc_priv->paddr + REG_ASRDx(!dir, index); + dma_params_fe->addr = asrc->paddr + REG_ASRDx(!dir, index); dma_params_fe->maxburst = dma_params_be->maxburst;
pair->dma_chan[!dir] = fsl_asrc_get_dma_channel(pair, !dir); @@ -203,7 +203,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, * need to configure dma_request and dma_request2, but get dma_chan via * dma_request_slave_channel directly with dma name of Front-End device */ - if (!asrc_priv->soc->use_edma) { + if (!asrc->soc->use_edma) { /* Get DMA request of Back-End */ tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); tmp_data = tmp_chan->private; @@ -230,7 +230,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, return -EINVAL; }
- if (asrc_priv->asrc_width == 16) + if (asrc->asrc_width == 16) buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; else buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -242,10 +242,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, config_be.dst_maxburst = dma_params_be->maxburst;
if (tx) { - config_be.src_addr = asrc_priv->paddr + REG_ASRDO(index); + config_be.src_addr = asrc->paddr + REG_ASRDO(index); config_be.dst_addr = dma_params_be->addr; } else { - config_be.dst_addr = asrc_priv->paddr + REG_ASRDI(index); + config_be.dst_addr = asrc->paddr + REG_ASRDI(index); config_be.src_addr = dma_params_be->addr; }
@@ -288,7 +288,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dmaengine_dai_dma_data *dma_data; struct device *dev = component->dev; - struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + struct fsl_asrc *asrc = dev_get_drvdata(dev); struct fsl_asrc_pair *pair; struct dma_chan *tmp_chan = NULL; u8 dir = tx ? OUT : IN; @@ -306,7 +306,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, if (!pair) return -ENOMEM;
- pair->asrc_priv = asrc_priv; + pair->asrc = asrc;
runtime->private_data = pair;
@@ -361,15 +361,15 @@ static int fsl_asrc_dma_shutdown(struct snd_soc_component *component, { struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; - struct fsl_asrc *asrc_priv; + struct fsl_asrc *asrc;
if (!pair) return 0;
- asrc_priv = pair->asrc_priv; + asrc = pair->asrc;
- if (asrc_priv->pair[pair->index] == pair) - asrc_priv->pair[pair->index] = NULL; + if (asrc->pair[pair->index] == pair) + asrc->pair[pair->index] = NULL;
kfree(pair);
On Wed, Apr 01, 2020 at 04:45:34PM +0800, Shengjiu Wang wrote:
In order to move common structure to fsl_asrc_common.h we change the name of asrc_priv to asrc, the asrc_priv will be used by new struct fsl_asrc_priv.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Acked-by: Nicolin Chen nicoleotsuka@gmail.com
In order to support new EASRC and simplify the code structure, We decide to share the common structure between them. This bring a problem that EASRC accept format directly from devicetree, but ASRC accept width from devicetree.
In order to align with new ESARC, we add new property fsl,asrc-format. The fsl,asrc-format can replace the fsl,asrc-width, then driver can accept format from devicetree, don't need to convert it to format through width.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- Documentation/devicetree/bindings/sound/fsl,asrc.txt | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt index cb9a25165503..998b4c8a7f78 100644 --- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt +++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt @@ -51,6 +51,10 @@ Optional properties: will be in use as default. Otherwise, the big endian mode will be in use for all the device registers.
+ - fsl,asrc-format : Defines a mutual sample format used by DPCM Back + Ends, which can replace the fsl,asrc-width. + The value is 2 (S16_LE), or 6 (S24_LE). + Example:
asrc: asrc@2034000 {
On Wed, Apr 01, 2020 at 04:45:35PM +0800, Shengjiu Wang wrote:
In order to support new EASRC and simplify the code structure, We decide to share the common structure between them. This bring a problem that EASRC accept format directly from devicetree, but ASRC accept width from devicetree.
In order to align with new ESARC, we add new property fsl,asrc-format. The fsl,asrc-format can replace the fsl,asrc-width, then driver can accept format from devicetree, don't need to convert it to format through width.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Once Rob has no objection: Acked-by: Nicolin Chen nicoleotsuka@gmail.com
Documentation/devicetree/bindings/sound/fsl,asrc.txt | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt index cb9a25165503..998b4c8a7f78 100644 --- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt +++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt @@ -51,6 +51,10 @@ Optional properties: will be in use as default. Otherwise, the big endian mode will be in use for all the device registers.
- fsl,asrc-format : Defines a mutual sample format used by DPCM Back
Ends, which can replace the fsl,asrc-width.
The value is 2 (S16_LE), or 6 (S24_LE).
Example:
asrc: asrc@2034000 {
2.21.0
On Wed, 1 Apr 2020 16:45:35 +0800, Shengjiu Wang wrote:
In order to support new EASRC and simplify the code structure, We decide to share the common structure between them. This bring a problem that EASRC accept format directly from devicetree, but ASRC accept width from devicetree.
In order to align with new ESARC, we add new property fsl,asrc-format. The fsl,asrc-format can replace the fsl,asrc-width, then driver can accept format from devicetree, don't need to convert it to format through width.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Documentation/devicetree/bindings/sound/fsl,asrc.txt | 4 ++++ 1 file changed, 4 insertions(+)
Acked-by: Rob Herring robh@kernel.org
In order to align with new ESARC, we add new property fsl,asrc-format. The fsl,asrc-format can replace the fsl,asrc-width, driver can accept format from devicetree, don't need to convert it to format through width.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl-asoc-card.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index bb33601fab84..a0f5eb27d61a 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -680,17 +680,20 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto asrc_fail; }
- ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); + ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &priv->asrc_format); if (ret) { - dev_err(&pdev->dev, "failed to get output rate\n"); - ret = -EINVAL; - goto asrc_fail; - } + /* Fallback to old binding; translate to asrc_format */ + ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); + if (ret) { + dev_err(&pdev->dev, "failed to get output width\n"); + return ret; + }
- if (width == 24) - priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; - else - priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; + if (width == 24) + priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + else + priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; + } }
/* Finish card registering */
On Wed, Apr 01, 2020 at 04:45:36PM +0800, Shengjiu Wang wrote:
In order to align with new ESARC, we add new property fsl,asrc-format. The fsl,asrc-format can replace the fsl,asrc-width, driver can accept format from devicetree, don't need to convert it to format through width.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Acked-by: Nicolin Chen nicoleotsuka@gmail.com
sound/soc/fsl/fsl-asoc-card.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index bb33601fab84..a0f5eb27d61a 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -680,17 +680,20 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto asrc_fail; }
ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
if (ret) {ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &priv->asrc_format);
dev_err(&pdev->dev, "failed to get output rate\n");
ret = -EINVAL;
goto asrc_fail;
}
/* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
if (ret) {
dev_err(&pdev->dev, "failed to get output width\n");
Should warn 'format' over 'width', since it's preferable.
return ret;
Should goto asrc_fail as we did prior to the change.
And some of lines are over 80 characters.
Let's try this: ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &priv->asrc_format); if (ret) { /* Fallback to old binding; translate to asrc_format */ ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); if (ret) { dev_err(&pdev->dev, "failed to decide output format\n"); goto asrc_fail; }
if (width == 24) priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; else priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; }
In order to align with new ESARC, we add new property fsl,asrc-format. The fsl,asrc-format can replace the fsl,asrc-width, driver can accept format from devicetree, don't need to convert it to format through width.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl_asrc.c | 40 ++++++++++++++++++++++-------------- sound/soc/fsl/fsl_asrc.h | 4 ++-- sound/soc/fsl/fsl_asrc_dma.c | 15 +++++++++++--- 3 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 4d3e51bfa949..eea19e2b723b 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -589,7 +589,6 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); struct asrc_config config; - snd_pcm_format_t format; int ret;
ret = fsl_asrc_request_pair(channels, pair); @@ -600,11 +599,6 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
pair->config = &config;
- if (asrc->asrc_width == 16) - format = SNDRV_PCM_FORMAT_S16_LE; - else - format = SNDRV_PCM_FORMAT_S24_LE; - config.pair = pair->index; config.channel_num = channels; config.inclk = INCLK_NONE; @@ -612,11 +606,11 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { config.input_format = params_format(params); - config.output_format = format; + config.output_format = asrc->asrc_format; config.input_sample_rate = rate; config.output_sample_rate = asrc->asrc_rate; } else { - config.input_format = format; + config.input_format = asrc->asrc_format; config.output_format = params_format(params); config.input_sample_rate = asrc->asrc_rate; config.output_sample_rate = rate; @@ -946,6 +940,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) int irq, ret, i; u32 map_idx; char tmp[16]; + u32 width;
asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL); if (!asrc) @@ -1052,16 +1047,31 @@ static int fsl_asrc_probe(struct platform_device *pdev) return ret; }
- ret = of_property_read_u32(np, "fsl,asrc-width", - &asrc->asrc_width); + ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format); if (ret) { - dev_err(&pdev->dev, "failed to get output width\n"); - return ret; + ret = of_property_read_u32(np, "fsl,asrc-width", &width); + if (ret) { + dev_err(&pdev->dev, "failed to get output width\n"); + return ret; + } + + switch (width) { + case 16: + asrc->asrc_format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 24: + asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + break; + default: + dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); + asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + break; + } }
- if (asrc->asrc_width != 16 && asrc->asrc_width != 24) { - dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); - asrc->asrc_width = 24; + if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) { + dev_warn(&pdev->dev, "unsupported format, switching to S24_LE\n"); + asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; }
platform_set_drvdata(pdev, asrc); diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 95d62c45afde..3b0f156af2c3 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -493,7 +493,7 @@ struct fsl_asrc_pair { * @channel_avail: non-occupied channel numbers * @clk_map: clock map for input/output clock * @asrc_rate: default sample rate for ASoC Back-Ends - * @asrc_width: default sample width for ASoC Back-Ends + * @asrc_format: default sample format for ASoC Back-Ends * @regcache_cfg: store register value of REG_ASRCFG */ struct fsl_asrc { @@ -514,7 +514,7 @@ struct fsl_asrc { unsigned char *clk_map[2];
int asrc_rate; - int asrc_width; + snd_pcm_format_t asrc_format;
u32 regcache_cfg; }; diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 5fe83aece25b..b15946e03380 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -146,7 +146,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct device *dev_be; u8 dir = tx ? OUT : IN; dma_cap_mask_t mask; - int ret; + int ret, bits;
/* Fetch the Back-End dma_data from DPCM */ for_each_dpcm_be(rtd, stream, dpcm) { @@ -230,10 +230,19 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, return -EINVAL; }
- if (asrc->asrc_width == 16) + bits = snd_pcm_format_physical_width(asrc->asrc_format); + if (bits < 8 || bits > 64) + return -EINVAL; + else if (bits == 8) + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + else if (bits == 16) buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; - else + else if (bits == 24) + buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES; + else if (bits <= 32) buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + else + buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
config_be.direction = DMA_DEV_TO_DEV; config_be.src_addr_width = buswidth;
Just some small comments.
On Wed, Apr 01, 2020 at 04:45:37PM +0800, Shengjiu Wang wrote:
In order to align with new ESARC, we add new property fsl,asrc-format. The fsl,asrc-format can replace the fsl,asrc-width, driver can accept format from devicetree, don't need to convert it to format through width.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
sound/soc/fsl/fsl_asrc.c | 40 ++++++++++++++++++++++-------------- sound/soc/fsl/fsl_asrc.h | 4 ++-- sound/soc/fsl/fsl_asrc_dma.c | 15 +++++++++++--- 3 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 4d3e51bfa949..eea19e2b723b 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1052,16 +1047,31 @@ static int fsl_asrc_probe(struct platform_device *pdev) return ret; }
- ret = of_property_read_u32(np, "fsl,asrc-width",
&asrc->asrc_width);
- ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format); if (ret) {
dev_err(&pdev->dev, "failed to get output width\n");
return ret;
ret = of_property_read_u32(np, "fsl,asrc-width", &width);
if (ret) {
dev_err(&pdev->dev, "failed to get output width\n");
Similar to the comments against sound card driver: "failed to decide output format"
return ret;
}
switch (width) {
case 16:
asrc->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
break;
case 24:
asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
break;
default:
dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n");
Should match what the code does after the change: + dev_warn(&pdev->dev, + "unsupported width, use default S24_LE\n");
asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
break;
}}
- if (asrc->asrc_width != 16 && asrc->asrc_width != 24) {
dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n");
asrc->asrc_width = 24;
- if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) {
dev_warn(&pdev->dev, "unsupported format, switching to S24_LE\n");
Could fit 80 characters: + dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n");
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 5fe83aece25b..b15946e03380 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -230,10 +230,19 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, return -EINVAL; }
- if (asrc->asrc_width == 16)
- bits = snd_pcm_format_physical_width(asrc->asrc_format);
Can we just use 'width' to match the function name?
There is a new ASRC included in i.MX serial platform, there are some common definition can be shared with each other. So move the common definition to a separate header file.
And add fsl_asrc_pair_priv and fsl_asrc_priv for the variable specific for the module, which can be used internally.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl_asrc.c | 81 +++++++++++++++--------- sound/soc/fsl/fsl_asrc.h | 74 ++-------------------- sound/soc/fsl/fsl_asrc_common.h | 105 ++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_asrc_dma.c | 25 ++++---- 4 files changed, 176 insertions(+), 109 deletions(-) create mode 100644 sound/soc/fsl/fsl_asrc_common.h
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index eea19e2b723b..d0b554e818fd 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -308,8 +308,10 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, */ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) { - struct asrc_config *config = pair->config; + struct fsl_asrc_pair_priv *pair_priv = pair->private; + struct asrc_config *config = pair_priv->config; struct fsl_asrc *asrc = pair->asrc; + struct fsl_asrc_priv *asrc_priv = asrc->private; enum asrc_pair_index index = pair->index; enum asrc_word_width input_word_width; enum asrc_word_width output_word_width; @@ -392,11 +394,11 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) }
/* Validate input and output clock sources */ - clk_index[IN] = asrc->clk_map[IN][config->inclk]; - clk_index[OUT] = asrc->clk_map[OUT][config->outclk]; + clk_index[IN] = asrc_priv->clk_map[IN][config->inclk]; + clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk];
/* We only have output clock for ideal ratio mode */ - clk = asrc->asrck_clk[clk_index[ideal ? OUT : IN]]; + clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]];
clk_rate = clk_get_rate(clk); rem[IN] = do_div(clk_rate, inrate); @@ -417,7 +419,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
div[IN] = min_t(u32, 1024, div[IN]);
- clk = asrc->asrck_clk[clk_index[OUT]]; + clk = asrc_priv->asrck_clk[clk_index[OUT]]; clk_rate = clk_get_rate(clk); if (ideal && use_ideal_rate) rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE); @@ -437,13 +439,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) /* Set the channel number */ channels = config->channel_num;
- if (asrc->soc->channel_bits < 4) + if (asrc_priv->soc->channel_bits < 4) channels /= 2;
/* Update channels for current pair */ regmap_update_bits(asrc->regmap, REG_ASRCNCR, - ASRCNCR_ANCi_MASK(index, asrc->soc->channel_bits), - ASRCNCR_ANCi(index, channels, asrc->soc->channel_bits)); + ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits), + ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits));
/* Default setting: Automatic selection for processing mode */ regmap_update_bits(asrc->regmap, REG_ASRCTR, @@ -568,9 +570,10 @@ static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); + struct fsl_asrc_priv *asrc_priv = asrc->private;
/* Odd channel number is not valid for older ASRC (channel_bits==3) */ - if (asrc->soc->channel_bits == 3) + if (asrc_priv->soc->channel_bits == 3) snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
@@ -586,6 +589,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; + struct fsl_asrc_pair_priv *pair_priv = pair->private; unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); struct asrc_config config; @@ -597,7 +601,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, return ret; }
- pair->config = &config; + pair_priv->config = &config;
config.pair = pair->index; config.channel_num = channels; @@ -931,10 +935,16 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) return IRQ_HANDLED; }
+static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) +{ + return REG_ASRDx(dir, index); +} + static int fsl_asrc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct fsl_asrc *asrc; + struct fsl_asrc_priv *asrc_priv; struct resource *res; void __iomem *regs; int irq, ret, i; @@ -946,7 +956,12 @@ static int fsl_asrc_probe(struct platform_device *pdev) if (!asrc) return -ENOMEM;
+ asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); + if (!asrc_priv) + return -ENOMEM; + asrc->pdev = pdev; + asrc->private = asrc_priv;
/* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -992,25 +1007,31 @@ static int fsl_asrc_probe(struct platform_device *pdev)
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { sprintf(tmp, "asrck_%x", i); - asrc->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); - if (IS_ERR(asrc->asrck_clk[i])) { + asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); + if (IS_ERR(asrc_priv->asrck_clk[i])) { dev_err(&pdev->dev, "failed to get %s clock\n", tmp); - return PTR_ERR(asrc->asrck_clk[i]); + return PTR_ERR(asrc_priv->asrck_clk[i]); } }
- asrc->soc = of_device_get_match_data(&pdev->dev); - if (!asrc->soc) { + asrc_priv->soc = of_device_get_match_data(&pdev->dev); + if (!asrc_priv->soc) { dev_err(&pdev->dev, "failed to get soc data\n"); return -ENODEV; }
+ asrc->use_edma = asrc_priv->soc->use_edma; + asrc->get_dma_channel = fsl_asrc_get_dma_channel; + asrc->request_pair = fsl_asrc_request_pair; + asrc->release_pair = fsl_asrc_release_pair; + asrc->get_fifo_addr = fsl_asrc_get_fifo_addr; + if (of_device_is_compatible(np, "fsl,imx35-asrc")) { - asrc->clk_map[IN] = input_clk_map_imx35; - asrc->clk_map[OUT] = output_clk_map_imx35; + asrc_priv->clk_map[IN] = input_clk_map_imx35; + asrc_priv->clk_map[OUT] = output_clk_map_imx35; } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { - asrc->clk_map[IN] = input_clk_map_imx53; - asrc->clk_map[OUT] = output_clk_map_imx53; + asrc_priv->clk_map[IN] = input_clk_map_imx53; + asrc_priv->clk_map[OUT] = output_clk_map_imx53; } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") || of_device_is_compatible(np, "fsl,imx8qxp-asrc")) { ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx); @@ -1024,11 +1045,11 @@ static int fsl_asrc_probe(struct platform_device *pdev) return -EINVAL; } if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) { - asrc->clk_map[IN] = clk_map_imx8qm[map_idx]; - asrc->clk_map[OUT] = clk_map_imx8qm[map_idx]; + asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx]; + asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx]; } else { - asrc->clk_map[IN] = clk_map_imx8qxp[map_idx]; - asrc->clk_map[OUT] = clk_map_imx8qxp[map_idx]; + asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx]; + asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx]; } }
@@ -1092,6 +1113,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) static int fsl_asrc_runtime_resume(struct device *dev) { struct fsl_asrc *asrc = dev_get_drvdata(dev); + struct fsl_asrc_priv *asrc_priv = asrc->private; int i, ret;
ret = clk_prepare_enable(asrc->mem_clk); @@ -1106,7 +1128,7 @@ static int fsl_asrc_runtime_resume(struct device *dev) goto disable_ipg_clk; } for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { - ret = clk_prepare_enable(asrc->asrck_clk[i]); + ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); if (ret) goto disable_asrck_clk; } @@ -1115,7 +1137,7 @@ static int fsl_asrc_runtime_resume(struct device *dev)
disable_asrck_clk: for (i--; i >= 0; i--) - clk_disable_unprepare(asrc->asrck_clk[i]); + clk_disable_unprepare(asrc_priv->asrck_clk[i]); if (!IS_ERR(asrc->spba_clk)) clk_disable_unprepare(asrc->spba_clk); disable_ipg_clk: @@ -1128,10 +1150,11 @@ static int fsl_asrc_runtime_resume(struct device *dev) static int fsl_asrc_runtime_suspend(struct device *dev) { struct fsl_asrc *asrc = dev_get_drvdata(dev); + struct fsl_asrc_priv *asrc_priv = asrc->private; int i;
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) - clk_disable_unprepare(asrc->asrck_clk[i]); + clk_disable_unprepare(asrc_priv->asrck_clk[i]); if (!IS_ERR(asrc->spba_clk)) clk_disable_unprepare(asrc->spba_clk); clk_disable_unprepare(asrc->ipg_clk); @@ -1145,9 +1168,10 @@ static int fsl_asrc_runtime_suspend(struct device *dev) static int fsl_asrc_suspend(struct device *dev) { struct fsl_asrc *asrc = dev_get_drvdata(dev); + struct fsl_asrc_priv *asrc_priv = asrc->private;
regmap_read(asrc->regmap, REG_ASRCFG, - &asrc->regcache_cfg); + &asrc_priv->regcache_cfg);
regcache_cache_only(asrc->regmap, true); regcache_mark_dirty(asrc->regmap); @@ -1158,6 +1182,7 @@ static int fsl_asrc_suspend(struct device *dev) static int fsl_asrc_resume(struct device *dev) { struct fsl_asrc *asrc = dev_get_drvdata(dev); + struct fsl_asrc_priv *asrc_priv = asrc->private; u32 asrctr;
/* Stop all pairs provisionally */ @@ -1171,7 +1196,7 @@ static int fsl_asrc_resume(struct device *dev)
regmap_update_bits(asrc->regmap, REG_ASRCFG, ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | - ASRCFG_PREMODi_ALL_MASK, asrc->regcache_cfg); + ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
/* Restart enabled pairs */ regmap_update_bits(asrc->regmap, REG_ASRCTR, diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 3b0f156af2c3..86d2422ad606 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -10,8 +10,7 @@ #ifndef _FSL_ASRC_H #define _FSL_ASRC_H
-#define IN 0 -#define OUT 1 +#include "fsl_asrc_common.h"
#define ASRC_DMA_BUFFER_NUM 2 #define ASRC_INPUTFIFO_THRESHOLD 32 @@ -283,14 +282,6 @@ #define ASRMCR1i_OW16_MASK (1 << ASRMCR1i_OW16_SHIFT) #define ASRMCR1i_OW16(v) ((v) << ASRMCR1i_OW16_SHIFT)
- -enum asrc_pair_index { - ASRC_INVALID_PAIR = -1, - ASRC_PAIR_A = 0, - ASRC_PAIR_B = 1, - ASRC_PAIR_C = 2, -}; - #define ASRC_PAIR_MAX_NUM (ASRC_PAIR_C + 1)
enum asrc_inclk { @@ -446,83 +437,28 @@ struct fsl_asrc_soc_data { };
/** - * fsl_asrc_pair: ASRC Pair private data + * fsl_asrc_pair_priv: ASRC Pair private data * - * @asrc: pointer to its parent module * @config: configuration profile - * @error: error record - * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C) - * @channels: occupied channel number - * @desc: input and output dma descriptors - * @dma_chan: inputer and output DMA channels - * @dma_data: private dma data - * @pos: hardware pointer position - * @private: pair private area */ -struct fsl_asrc_pair { - struct fsl_asrc *asrc; +struct fsl_asrc_pair_priv { struct asrc_config *config; - unsigned int error; - - enum asrc_pair_index index; - unsigned int channels; - - struct dma_async_tx_descriptor *desc[2]; - struct dma_chan *dma_chan[2]; - struct imx_dma_data dma_data; - unsigned int pos; - - void *private; };
/** - * fsl_asrc_pair: ASRC private data + * fsl_asrc_priv: ASRC private data * - * @dma_params_rx: DMA parameters for receive channel - * @dma_params_tx: DMA parameters for transmit channel - * @pdev: platform device pointer - * @regmap: regmap handler - * @paddr: physical address to the base address of registers - * @mem_clk: clock source to access register - * @ipg_clk: clock source to drive peripheral - * @spba_clk: SPBA clock (optional, depending on SoC design) * @asrck_clk: clock sources to driver ASRC internal logic - * @lock: spin lock for resource protection - * @pair: pair pointers * @soc: soc specific data - * @channel_avail: non-occupied channel numbers * @clk_map: clock map for input/output clock - * @asrc_rate: default sample rate for ASoC Back-Ends - * @asrc_format: default sample format for ASoC Back-Ends * @regcache_cfg: store register value of REG_ASRCFG */ -struct fsl_asrc { - struct snd_dmaengine_dai_dma_data dma_params_rx; - struct snd_dmaengine_dai_dma_data dma_params_tx; - struct platform_device *pdev; - struct regmap *regmap; - unsigned long paddr; - struct clk *mem_clk; - struct clk *ipg_clk; - struct clk *spba_clk; +struct fsl_asrc_priv { struct clk *asrck_clk[ASRC_CLK_MAX_NUM]; - spinlock_t lock; - - struct fsl_asrc_pair *pair[ASRC_PAIR_MAX_NUM]; const struct fsl_asrc_soc_data *soc; - unsigned int channel_avail; unsigned char *clk_map[2];
- int asrc_rate; - snd_pcm_format_t asrc_format; - u32 regcache_cfg; };
-#define DRV_NAME "fsl-asrc-dai" -extern struct snd_soc_component_driver fsl_asrc_component; -struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir); -int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair); -void fsl_asrc_release_pair(struct fsl_asrc_pair *pair); - #endif /* _FSL_ASRC_H */ diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h new file mode 100644 index 000000000000..5c93ccdfc30a --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_common.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 NXP + * + */ + +#ifndef _FSL_ASRC_COMMON_H +#define _FSL_ASRC_COMMON_H + +/* directions */ +#define IN 0 +#define OUT 1 + +enum asrc_pair_index { + ASRC_INVALID_PAIR = -1, + ASRC_PAIR_A = 0, + ASRC_PAIR_B = 1, + ASRC_PAIR_C = 2, + ASRC_PAIR_D = 3, +}; + +#define PAIR_CTX_NUM 0x4 +#define PAIR_PRIVAT_SIZE 0x400 + +/** + * fsl_asrc_pair: ASRC Pair common data + * + * @asrc: pointer to its parent module + * @error: error record + * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C) + * @channels: occupied channel number + * @desc: input and output dma descriptors + * @dma_chan: inputer and output DMA channels + * @dma_data: private dma data + * @pos: hardware pointer position + * @private: pair private area + */ +struct fsl_asrc_pair { + struct fsl_asrc *asrc; + unsigned int error; + + enum asrc_pair_index index; + unsigned int channels; + + struct dma_async_tx_descriptor *desc[2]; + struct dma_chan *dma_chan[2]; + struct imx_dma_data dma_data; + unsigned int pos; + + void *private; +}; + +/** + * fsl_asrc_pair: ASRC common data + * + * @dma_params_rx: DMA parameters for receive channel + * @dma_params_tx: DMA parameters for transmit channel + * @pdev: platform device pointer + * @regmap: regmap handler + * @paddr: physical address to the base address of registers + * @mem_clk: clock source to access register + * @ipg_clk: clock source to drive peripheral + * @spba_clk: SPBA clock (optional, depending on SoC design) + * @lock: spin lock for resource protection + * @pair: pair pointers + * @channel_avail: non-occupied channel numbers + * @asrc_rate: default sample rate for ASoC Back-Ends + * @asrc_format: default sample format for ASoC Back-Ends + * @use_edma: edma is used + * @get_dma_channel: function pointer + * @request_pair: function pointer + * @release_pair: function pointer + * @get_fifo_addr: function pointer + * @private: private data structure + */ +struct fsl_asrc { + struct snd_dmaengine_dai_dma_data dma_params_rx; + struct snd_dmaengine_dai_dma_data dma_params_tx; + struct platform_device *pdev; + struct regmap *regmap; + unsigned long paddr; + struct clk *mem_clk; + struct clk *ipg_clk; + struct clk *spba_clk; + spinlock_t lock; /* spin lock for resource protection */ + + struct fsl_asrc_pair *pair[PAIR_CTX_NUM]; + unsigned int channel_avail; + + int asrc_rate; + snd_pcm_format_t asrc_format; + bool use_edma; + + struct dma_chan *(*get_dma_channel)(struct fsl_asrc_pair *pair, bool dir); + 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); + + void *private; +}; + +#define DRV_NAME "fsl-asrc-dai" +extern struct snd_soc_component_driver fsl_asrc_component; + +#endif /* _FSL_ASRC_COMMON_H */ diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index b15946e03380..5cf0468ce6e3 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -12,7 +12,7 @@ #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h>
-#include "fsl_asrc.h" +#include "fsl_asrc_common.h"
#define FSL_ASRC_DMABUF_SIZE (256 * 1024)
@@ -170,10 +170,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
/* Override dma_data of the Front-End and config its dmaengine */ dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); - dma_params_fe->addr = asrc->paddr + REG_ASRDx(!dir, index); + dma_params_fe->addr = asrc->paddr + asrc->get_fifo_addr(!dir, index); dma_params_fe->maxburst = dma_params_be->maxburst;
- pair->dma_chan[!dir] = fsl_asrc_get_dma_channel(pair, !dir); + pair->dma_chan[!dir] = asrc->get_dma_channel(pair, !dir); if (!pair->dma_chan[!dir]) { dev_err(dev, "failed to request DMA channel\n"); return -EINVAL; @@ -203,7 +203,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, * need to configure dma_request and dma_request2, but get dma_chan via * dma_request_slave_channel directly with dma name of Front-End device */ - if (!asrc->soc->use_edma) { + if (!asrc->use_edma) { /* Get DMA request of Back-End */ tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); tmp_data = tmp_chan->private; @@ -211,7 +211,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, dma_release_channel(tmp_chan);
/* Get DMA request of Front-End */ - tmp_chan = fsl_asrc_get_dma_channel(pair, dir); + tmp_chan = asrc->get_dma_channel(pair, dir); tmp_data = tmp_chan->private; pair->dma_data.dma_request2 = tmp_data->dma_request; pair->dma_data.peripheral_type = tmp_data->peripheral_type; @@ -222,7 +222,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, dma_request_channel(mask, filter, &pair->dma_data); } else { pair->dma_chan[dir] = - fsl_asrc_get_dma_channel(pair, dir); + asrc->get_dma_channel(pair, dir); }
if (!pair->dma_chan[dir]) { @@ -251,10 +251,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, config_be.dst_maxburst = dma_params_be->maxburst;
if (tx) { - config_be.src_addr = asrc->paddr + REG_ASRDO(index); + config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index); config_be.dst_addr = dma_params_be->addr; } else { - config_be.dst_addr = asrc->paddr + REG_ASRDI(index); + config_be.dst_addr = asrc->paddr + asrc->get_fifo_addr(IN, index); config_be.src_addr = dma_params_be->addr; }
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, return ret; }
- pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL); + pair = kzalloc(sizeof(struct fsl_asrc_pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL); if (!pair) return -ENOMEM;
pair->asrc = asrc; + pair->private = (void *)pair + sizeof(struct fsl_asrc_pair);
runtime->private_data = pair;
@@ -323,14 +324,14 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, * Request pair function needs channel num as input, for this * dummy pair, we just request "1" channel temporarily. */ - ret = fsl_asrc_request_pair(1, pair); + ret = asrc->request_pair(1, pair); if (ret < 0) { dev_err(dev, "failed to request asrc pair\n"); goto req_pair_err; }
/* Request a dummy dma channel, which will be released later. */ - tmp_chan = fsl_asrc_get_dma_channel(pair, dir); + tmp_chan = asrc->get_dma_channel(pair, dir); if (!tmp_chan) { dev_err(dev, "failed to get dma channel\n"); ret = -EINVAL; @@ -356,7 +357,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, dma_release_channel(tmp_chan);
dma_chan_err: - fsl_asrc_release_pair(pair); + asrc->release_pair(pair);
req_pair_err: if (release_pair)
On Wed, Apr 01, 2020 at 04:45:38PM +0800, Shengjiu Wang wrote:
static int fsl_asrc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct fsl_asrc *asrc;
- struct fsl_asrc_priv *asrc_priv;
Could we move it before "struct fsl_asrc *asrc;"?
diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h new file mode 100644 index 000000000000..5c93ccdfc30a --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_common.h
+#define PAIR_CTX_NUM 0x4 +#define PAIR_PRIVAT_SIZE 0x400
"PRIVAT_" => "PRIVATE_"
+/**
- fsl_asrc_pair: ASRC common data
"fsl_asrc_pair" => "fsl_asrc"
- */
+struct fsl_asrc {
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index b15946e03380..5cf0468ce6e3 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, return ret; }
- pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
- pair = kzalloc(sizeof(struct fsl_asrc_pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
If we only use the PAIR_PRIVATE_SIZE here, maybe we can put the define in this file too, rather than in the header file.
And could fit 80 characters:
+ pair = kzalloc(sizeof(*pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
Hi
On Tue, Apr 7, 2020 at 7:50 AM Nicolin Chen nicoleotsuka@gmail.com wrote:
On Wed, Apr 01, 2020 at 04:45:38PM +0800, Shengjiu Wang wrote:
static int fsl_asrc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct fsl_asrc *asrc;
struct fsl_asrc_priv *asrc_priv;
Could we move it before "struct fsl_asrc *asrc;"?
diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h new file mode 100644 index 000000000000..5c93ccdfc30a --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_common.h
+#define PAIR_CTX_NUM 0x4 +#define PAIR_PRIVAT_SIZE 0x400
"PRIVAT_" => "PRIVATE_"
+/**
- fsl_asrc_pair: ASRC common data
"fsl_asrc_pair" => "fsl_asrc"
- */
+struct fsl_asrc {
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index b15946e03380..5cf0468ce6e3 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, return ret; }
pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
pair = kzalloc(sizeof(struct fsl_asrc_pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
If we only use the PAIR_PRIVATE_SIZE here, maybe we can put the define in this file too, rather than in the header file.
And could fit 80 characters:
pair = kzalloc(sizeof(*pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
I will use a function pointer int (*get_pair_priv_size)(void) to avoid definition of PAIR_PRIVATE_SIZE. which is not safe.
best regards wang shengjiu
On Sat, Apr 11, 2020 at 01:49:43PM +0800, Shengjiu Wang wrote:
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index b15946e03380..5cf0468ce6e3 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, return ret; }
pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
pair = kzalloc(sizeof(struct fsl_asrc_pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
If we only use the PAIR_PRIVATE_SIZE here, maybe we can put the define in this file too, rather than in the header file.
And could fit 80 characters:
pair = kzalloc(sizeof(*pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
I will use a function pointer int (*get_pair_priv_size)(void)
Since it's the size of pair or cts structure, could be just a size_t variable?
On Sun, Apr 12, 2020 at 10:08 AM Nicolin Chen nicoleotsuka@gmail.com wrote:
On Sat, Apr 11, 2020 at 01:49:43PM +0800, Shengjiu Wang wrote:
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index b15946e03380..5cf0468ce6e3 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, return ret; }
pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
pair = kzalloc(sizeof(struct fsl_asrc_pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
If we only use the PAIR_PRIVATE_SIZE here, maybe we can put the define in this file too, rather than in the header file.
And could fit 80 characters:
pair = kzalloc(sizeof(*pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
I will use a function pointer int (*get_pair_priv_size)(void)
Since it's the size of pair or cts structure, could be just a size_t variable?
Yes, should be "size_t (*get_pair_priv_size)(void)"
best regards wang shengjiu
On Mon, Apr 13, 2020 at 11:16:31AM +0800, Shengjiu Wang wrote:
On Sun, Apr 12, 2020 at 10:08 AM Nicolin Chen nicoleotsuka@gmail.com wrote:
On Sat, Apr 11, 2020 at 01:49:43PM +0800, Shengjiu Wang wrote:
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index b15946e03380..5cf0468ce6e3 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, return ret; }
pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
pair = kzalloc(sizeof(struct fsl_asrc_pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
If we only use the PAIR_PRIVATE_SIZE here, maybe we can put the define in this file too, rather than in the header file.
And could fit 80 characters:
pair = kzalloc(sizeof(*pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
I will use a function pointer int (*get_pair_priv_size)(void)
Since it's the size of pair or cts structure, could be just a size_t variable?
Yes, should be "size_t (*get_pair_priv_size)(void)"
Does it have to be a function? -- how about this:
struct pair { ... size_t private_size; void *private; };
probe/or-somewhere() { ... pair->private = pair_priv; pair->private_size = sizeof(*pair_priv); ... }
On Mon, Apr 13, 2020 at 12:31 PM Nicolin Chen nicoleotsuka@gmail.com wrote:
On Mon, Apr 13, 2020 at 11:16:31AM +0800, Shengjiu Wang wrote:
On Sun, Apr 12, 2020 at 10:08 AM Nicolin Chen nicoleotsuka@gmail.com wrote:
On Sat, Apr 11, 2020 at 01:49:43PM +0800, Shengjiu Wang wrote:
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index b15946e03380..5cf0468ce6e3 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component, return ret; }
pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
pair = kzalloc(sizeof(struct fsl_asrc_pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
If we only use the PAIR_PRIVATE_SIZE here, maybe we can put the define in this file too, rather than in the header file.
And could fit 80 characters:
pair = kzalloc(sizeof(*pair) + PAIR_PRIVAT_SIZE, GFP_KERNEL);
I will use a function pointer int (*get_pair_priv_size)(void)
Since it's the size of pair or cts structure, could be just a size_t variable?
Yes, should be "size_t (*get_pair_priv_size)(void)"
Does it have to be a function? -- how about this:
struct pair { ... size_t private_size; void *private; };
probe/or-somewhere() { ... pair->private = pair_priv;
we need to know the size of pair_priv before allocate memory.
pair->private_size = sizeof(*pair_priv); ...
}
In fsl_asrc_dma_startup, we need to allocate memory for pair and pair->private,but we don't know the object, so we don't know the size of private, so function pointer is better.
best regards wang shengjiu
EASRC (Enhanced Asynchronous Sample Rate Converter) is a new IP module found on i.MX8MN.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- .../devicetree/bindings/sound/fsl,easrc.yaml | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,easrc.yaml
diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml new file mode 100644 index 000000000000..14ea60084420 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,easrc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP Asynchronous Sample Rate Converter (ASRC) Controller + +maintainers: + - Shengjiu Wang shengjiu.wang@nxp.com + +properties: + $nodename: + pattern: "^easrc@.*" + + compatible: + const: fsl,imx8mn-easrc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Peripheral clock + + clock-names: + items: + - const: mem + + dmas: + maxItems: 8 + + dma-names: + items: + - const: ctx0_rx + - const: ctx0_tx + - const: ctx1_rx + - const: ctx1_tx + - const: ctx2_rx + - const: ctx2_tx + - const: ctx3_rx + - const: ctx3_tx + + firmware-name: + allOf: + - $ref: /schemas/types.yaml#/definitions/string + - const: imx/easrc/easrc-imx8mn.bin + description: The coefficient table for the filters + + fsl,asrc-rate: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 8000 + - maximum: 192000 + description: Defines a mutual sample rate used by DPCM Back Ends + + fsl,asrc-format: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - enum: [2, 6, 10, 32, 36] + default: 2 + description: + Defines a mutual sample format used by DPCM Back Ends + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - dmas + - dma-names + - firmware-name + - fsl,asrc-rate + - fsl,asrc-format + +examples: + - | + #include <dt-bindings/clock/imx8mn-clock.h> + + easrc: easrc@300C0000 { + compatible = "fsl,imx8mn-easrc"; + reg = <0x0 0x300C0000 0x0 0x10000>; + interrupts = <0x0 122 0x4>; + clocks = <&clk IMX8MN_CLK_ASRC_ROOT>; + clock-names = "mem"; + dmas = <&sdma2 16 23 0> , <&sdma2 17 23 0>, + <&sdma2 18 23 0> , <&sdma2 19 23 0>, + <&sdma2 20 23 0> , <&sdma2 21 23 0>, + <&sdma2 22 23 0> , <&sdma2 23 23 0>; + dma-names = "ctx0_rx", "ctx0_tx", + "ctx1_rx", "ctx1_tx", + "ctx2_rx", "ctx2_tx", + "ctx3_rx", "ctx3_tx"; + firmware-name = "imx/easrc/easrc-imx8mn.bin"; + fsl,asrc-rate = <8000>; + fsl,asrc-format = <2>; + };
On Wed, Apr 01, 2020 at 04:45:39PM +0800, Shengjiu Wang wrote:
EASRC (Enhanced Asynchronous Sample Rate Converter) is a new IP module found on i.MX8MN.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
.../devicetree/bindings/sound/fsl,easrc.yaml | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,easrc.yaml
diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml new file mode 100644 index 000000000000..14ea60084420 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,easrc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: NXP Asynchronous Sample Rate Converter (ASRC) Controller
+maintainers:
- Shengjiu Wang shengjiu.wang@nxp.com
+properties:
- $nodename:
- pattern: "^easrc@.*"
- compatible:
- const: fsl,imx8mn-easrc
- reg:
- maxItems: 1
- interrupts:
- maxItems: 1
- clocks:
- items:
- description: Peripheral clock
- clock-names:
- items:
- const: mem
- dmas:
- maxItems: 8
- dma-names:
- items:
- const: ctx0_rx
- const: ctx0_tx
- const: ctx1_rx
- const: ctx1_tx
- const: ctx2_rx
- const: ctx2_tx
- const: ctx3_rx
- const: ctx3_tx
- firmware-name:
- allOf:
- $ref: /schemas/types.yaml#/definitions/string
- const: imx/easrc/easrc-imx8mn.bin
- description: The coefficient table for the filters
- fsl,asrc-rate:
fsl,asrc-rate-hz
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
And then you can drop this.
- minimum: 8000
- maximum: 192000
- description: Defines a mutual sample rate used by DPCM Back Ends
- fsl,asrc-format:
- allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [2, 6, 10, 32, 36]
default: 2
- description:
Defines a mutual sample format used by DPCM Back Ends
+required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- dmas
- dma-names
- firmware-name
- fsl,asrc-rate
- fsl,asrc-format
+examples:
- |
- #include <dt-bindings/clock/imx8mn-clock.h>
- easrc: easrc@300C0000 {
Lowercase hex
compatible = "fsl,imx8mn-easrc";
reg = <0x0 0x300C0000 0x0 0x10000>;
interrupts = <0x0 122 0x4>;
clocks = <&clk IMX8MN_CLK_ASRC_ROOT>;
clock-names = "mem";
dmas = <&sdma2 16 23 0> , <&sdma2 17 23 0>,
<&sdma2 18 23 0> , <&sdma2 19 23 0>,
<&sdma2 20 23 0> , <&sdma2 21 23 0>,
<&sdma2 22 23 0> , <&sdma2 23 23 0>;
dma-names = "ctx0_rx", "ctx0_tx",
"ctx1_rx", "ctx1_tx",
"ctx2_rx", "ctx2_tx",
"ctx3_rx", "ctx3_tx";
firmware-name = "imx/easrc/easrc-imx8mn.bin";
fsl,asrc-rate = <8000>;
fsl,asrc-format = <2>;
- };
-- 2.21.0
Hi Rob
On Tue, Apr 14, 2020 at 11:49 PM Rob Herring robh@kernel.org wrote:
On Wed, Apr 01, 2020 at 04:45:39PM +0800, Shengjiu Wang wrote:
EASRC (Enhanced Asynchronous Sample Rate Converter) is a new IP module found on i.MX8MN.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
.../devicetree/bindings/sound/fsl,easrc.yaml | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,easrc.yaml
diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml new file mode 100644 index 000000000000..14ea60084420 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,easrc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: NXP Asynchronous Sample Rate Converter (ASRC) Controller
+maintainers:
- Shengjiu Wang shengjiu.wang@nxp.com
+properties:
- $nodename:
- pattern: "^easrc@.*"
- compatible:
- const: fsl,imx8mn-easrc
- reg:
- maxItems: 1
- interrupts:
- maxItems: 1
- clocks:
- items:
- description: Peripheral clock
- clock-names:
- items:
- const: mem
- dmas:
- maxItems: 8
- dma-names:
- items:
- const: ctx0_rx
- const: ctx0_tx
- const: ctx1_rx
- const: ctx1_tx
- const: ctx2_rx
- const: ctx2_tx
- const: ctx3_rx
- const: ctx3_tx
- firmware-name:
- allOf:
- $ref: /schemas/types.yaml#/definitions/string
- const: imx/easrc/easrc-imx8mn.bin
- description: The coefficient table for the filters
- fsl,asrc-rate:
fsl,asrc-rate-hz
Can we keep "fsl,asrc-rate", because I want this property align with the one in fsl,asrc.txt. These two asrc modules can share same property name.
best regards wang shengjiu
On Tue, Apr 14, 2020 at 9:56 PM Shengjiu Wang shengjiu.wang@gmail.com wrote:
Hi Rob
On Tue, Apr 14, 2020 at 11:49 PM Rob Herring robh@kernel.org wrote:
On Wed, Apr 01, 2020 at 04:45:39PM +0800, Shengjiu Wang wrote:
EASRC (Enhanced Asynchronous Sample Rate Converter) is a new IP module found on i.MX8MN.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
.../devicetree/bindings/sound/fsl,easrc.yaml | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,easrc.yaml
diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml new file mode 100644 index 000000000000..14ea60084420 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,easrc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: NXP Asynchronous Sample Rate Converter (ASRC) Controller
+maintainers:
- Shengjiu Wang shengjiu.wang@nxp.com
+properties:
- $nodename:
- pattern: "^easrc@.*"
- compatible:
- const: fsl,imx8mn-easrc
- reg:
- maxItems: 1
- interrupts:
- maxItems: 1
- clocks:
- items:
- description: Peripheral clock
- clock-names:
- items:
- const: mem
- dmas:
- maxItems: 8
- dma-names:
- items:
- const: ctx0_rx
- const: ctx0_tx
- const: ctx1_rx
- const: ctx1_tx
- const: ctx2_rx
- const: ctx2_tx
- const: ctx3_rx
- const: ctx3_tx
- firmware-name:
- allOf:
- $ref: /schemas/types.yaml#/definitions/string
- const: imx/easrc/easrc-imx8mn.bin
- description: The coefficient table for the filters
- fsl,asrc-rate:
fsl,asrc-rate-hz
Can we keep "fsl,asrc-rate", because I want this property align with the one in fsl,asrc.txt. These two asrc modules can share same property name.
Oh, yes.
So with the example fixed:
Reviewed-by: Rob Herring robh@kernel.org
EASRC (Enhanced Asynchronous Sample Rate Converter) is a new IP module found on i.MX8MN. It is different with old ASRC module.
The primary features for the EASRC are as follows: - 4 Contexts - groups of channels with an independent time base - Fully independent and concurrent context control - Simultaneous processing of up to 32 audio channels - Programmable filter charachteristics for each context - 32, 24, 20, and 16-bit fixed point audio sample support - 32-bit floating point audio sample support - 8kHz to 384kHz sample rate - 1/16 to 8x sample rate conversion ratio
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com Signed-off-by: Cosmin-Gabriel Samoila cosmin.samoila@nxp.com --- sound/soc/fsl/Kconfig | 11 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_easrc.c | 2114 +++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_easrc.h | 651 ++++++++++++ 4 files changed, 2778 insertions(+) create mode 100644 sound/soc/fsl/fsl_easrc.c create mode 100644 sound/soc/fsl/fsl_easrc.h
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 65e8cd4be930..ea7b4787a8af 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -84,6 +84,17 @@ config SND_SOC_FSL_MICFIL Say Y if you want to add Pulse Density Modulation microphone interface (MICFIL) support for NXP.
+config SND_SOC_FSL_EASRC + tristate "Enhanced Asynchronous Sample Rate Converter (EASRC) module support" + depends on SND_SOC_FSL_ASRC + select REGMAP_MMIO + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y if you want to add Enhanced ASRC support for NXP. The ASRC is + a digital module that converts audio from a source sample rate to a + destination sample rate. It is a new design module compare with the + old ASRC. + config SND_SOC_FSL_UTILS tristate
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8cde88c72d93..b835eebf8825 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -24,6 +24,7 @@ snd-soc-fsl-micfil-objs := fsl_micfil.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o snd-soc-fsl-mqs-objs := fsl_mqs.o +snd-soc-fsl-easrc-objs := fsl_easrc.o
obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o +obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
# MPC5200 Platform Support diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c new file mode 100644 index 000000000000..809041981700 --- /dev/null +++ b/sound/soc/fsl/fsl_easrc.c @@ -0,0 +1,2114 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2019 NXP + +#include <linux/atomic.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/firmware.h> +#include <linux/interrupt.h> +#include <linux/kobject.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/miscdevice.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/sched/signal.h> +#include <linux/sysfs.h> +#include <linux/types.h> +#include <linux/gcd.h> +#include <sound/dmaengine_pcm.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include <sound/core.h> + +#include "fsl_easrc.h" +#include "imx-pcm.h" + +#define FSL_EASRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_U24_3LE | \ + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_U32_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_U20_3LE | \ + SNDRV_PCM_FMTBIT_FLOAT_LE) + +static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp); + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + unsigned int regval = ucontrol->value.integer.value[0]; + + easrc_priv->bps_iec958[mc->regbase] = regval; + + return 0; +} + +static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp); + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + + ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; +} + +static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + unsigned int regval; + int ret; + + ret = snd_soc_component_read(component, mc->regbase, ®val); + if (ret < 0) + return ret; + + ucontrol->value.integer.value[0] = regval; + + return 0; +} + +static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + + ret = snd_soc_component_write(component, mc->regbase, regval); + if (ret < 0) + return ret; + + return 0; +} + +#define SOC_SINGLE_REG_RW(xname, xreg) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ + .invert = 0, .min = 0, .max = 0xffffffff, } } + +#define SOC_SINGLE_VAL_RW(xname, xreg) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_soc_info_xr_sx, .get = fsl_easrc_iec958_get_bits, \ + .put = fsl_easrc_iec958_put_bits, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ + .invert = 0, .min = 0, .max = 2, } } + +static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE("Context 0 Dither Switch", REG_EASRC_COC(0), 0, 1, 0), + SOC_SINGLE("Context 1 Dither Switch", REG_EASRC_COC(1), 0, 1, 0), + SOC_SINGLE("Context 2 Dither Switch", REG_EASRC_COC(2), 0, 1, 0), + SOC_SINGLE("Context 3 Dither Switch", REG_EASRC_COC(3), 0, 1, 0), + + SOC_SINGLE("Context 0 IEC958 Validity", REG_EASRC_COC(0), 2, 1, 0), + SOC_SINGLE("Context 1 IEC958 Validity", REG_EASRC_COC(1), 2, 1, 0), + SOC_SINGLE("Context 2 IEC958 Validity", REG_EASRC_COC(2), 2, 1, 0), + SOC_SINGLE("Context 3 IEC958 Validity", REG_EASRC_COC(3), 2, 1, 0), + + SOC_SINGLE_VAL_RW("Context 0 IEC958 Bits Per Sample", 0), + SOC_SINGLE_VAL_RW("Context 1 IEC958 Bits Per Sample", 1), + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + + SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), + SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), + SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), + SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), + SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), + SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), + SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), + SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), + SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), + SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), + SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), + SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), + SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), + SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), + SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), + SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), + SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), + SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), + SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), + SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), + SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), + SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), + SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), + SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), +}; + +/* + * fsl_easrc_set_rs_ratio + * + * According to the resample taps, calculate the resample ratio + * ratio = in_rate / out_rate + */ +static int fsl_easrc_set_rs_ratio(struct fsl_asrc_pair *ctx) +{ + struct fsl_asrc *easrc = ctx->asrc; + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; + unsigned int in_rate = ctx_priv->in_params.norm_rate; + unsigned int out_rate = ctx_priv->out_params.norm_rate; + unsigned int int_bits; + unsigned int frac_bits; + u64 val; + u32 *r; + + switch (easrc_priv->rs_num_taps) { + case EASRC_RS_32_TAPS: + int_bits = 5; + frac_bits = 39; + break; + case EASRC_RS_64_TAPS: + int_bits = 6; + frac_bits = 38; + break; + case EASRC_RS_128_TAPS: + int_bits = 7; + frac_bits = 37; + break; + default: + return -EINVAL; + } + + val = (u64)in_rate << frac_bits; + do_div(val, out_rate); + r = (uint32_t *)&val; + + if (r[1] & 0xFFFFF000) { + dev_err(&easrc->pdev->dev, "ratio exceed range\n"); + return -EINVAL; + } + + regmap_write(easrc->regmap, REG_EASRC_RRL(ctx->index), + EASRC_RRL_RS_RL(r[0])); + regmap_write(easrc->regmap, REG_EASRC_RRH(ctx->index), + EASRC_RRH_RS_RH(r[1])); + + return 0; +} + +/* Normalize input and output sample rates */ +static void fsl_easrc_normalize_rates(struct fsl_asrc_pair *ctx) +{ + struct fsl_easrc_ctx_priv *ctx_priv; + int a, b; + + if (!ctx) + return; + + ctx_priv = ctx->private; + + a = ctx_priv->in_params.sample_rate; + b = ctx_priv->out_params.sample_rate; + + a = gcd(a, b); + + /* Divide by gcd to normalize the rate */ + ctx_priv->in_params.norm_rate = ctx_priv->in_params.sample_rate / a; + ctx_priv->out_params.norm_rate = ctx_priv->out_params.sample_rate / a; +} + +/* Resets the pointer of the coeff memory pointers */ +static int fsl_easrc_coeff_mem_ptr_reset(struct fsl_asrc *easrc, + unsigned int ctx_id, int mem_type) +{ + struct device *dev; + u32 reg, mask, val; + + if (!easrc) + return -ENODEV; + + dev = &easrc->pdev->dev; + + switch (mem_type) { + case EASRC_PF_COEFF_MEM: + /* This resets the prefilter memory pointer addr */ + if (ctx_id >= EASRC_CTX_MAX_NUM) { + dev_err(dev, "Invalid context id[%d]\n", ctx_id); + return -EINVAL; + } + + reg = REG_EASRC_CCE1(ctx_id); + mask = EASRC_CCE1_COEF_MEM_RST_MASK; + val = EASRC_CCE1_COEF_MEM_RST; + break; + case EASRC_RS_COEFF_MEM: + /* This resets the resampling memory pointer addr */ + reg = REG_EASRC_CRCC; + mask = EASRC_CRCC_RS_CPR_MASK; + val = EASRC_CRCC_RS_CPR; + break; + default: + dev_err(dev, "Unknown memory type\n"); + return -EINVAL; + } + + /* + * To reset the write pointer back to zero, the register field + * ASRC_CTX_CTRL_EXT1x[PF_COEFF_MEM_RST] can be toggled from + * 0x0 to 0x1 to 0x0. + */ + regmap_update_bits(easrc->regmap, reg, mask, 0); + regmap_update_bits(easrc->regmap, reg, mask, val); + regmap_update_bits(easrc->regmap, reg, mask, 0); + + return 0; +} + +static inline uint32_t bits_taps_to_val(unsigned int t) +{ + switch (t) { + case EASRC_RS_32_TAPS: + return 32; + case EASRC_RS_64_TAPS: + return 64; + case EASRC_RS_128_TAPS: + return 128; + } + + return 0; +} + +static int fsl_easrc_resampler_config(struct fsl_asrc *easrc) +{ + struct device *dev = &easrc->pdev->dev; + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct asrc_firmware_hdr *hdr = easrc_priv->firmware_hdr; + struct interp_params *interp = easrc_priv->interp; + struct interp_params *selected_interp = NULL; + unsigned int num_coeff; + unsigned int i; + u64 *coef; + u32 *r; + int ret; + + if (!hdr) { + dev_err(dev, "firmware not loaded!\n"); + return -ENODEV; + } + + for (i = 0; i < hdr->interp_scen; i++) { + if ((interp[i].num_taps - 1) != + bits_taps_to_val(easrc_priv->rs_num_taps)) + continue; + + coef = interp[i].coeff; + selected_interp = &interp[i]; + dev_dbg(dev, "Selected interp_filter: %u taps - %u phases\n", + selected_interp->num_taps, + selected_interp->num_phases); + break; + } + + if (!selected_interp) { + dev_err(dev, "failed to get interpreter configuration\n"); + return -EINVAL; + } + + /* + * RS_LOW - first half of center tap of the sinc function + * RS_HIGH - second half of center tap of the sinc function + * This is due to the fact the resampling function must be + * symetrical - i.e. odd number of taps + */ + r = (uint32_t *)&selected_interp->center_tap; + regmap_write(easrc->regmap, REG_EASRC_RCTCL, EASRC_RCTCL_RS_CL(r[0])); + regmap_write(easrc->regmap, REG_EASRC_RCTCH, EASRC_RCTCH_RS_CH(r[1])); + + /* + * Write Number of Resampling Coefficient Taps + * 00b - 32-Tap Resampling Filter + * 01b - 64-Tap Resampling Filter + * 10b - 128-Tap Resampling Filter + * 11b - N/A + */ + regmap_update_bits(easrc->regmap, REG_EASRC_CRCC, + EASRC_CRCC_RS_TAPS_MASK, + EASRC_CRCC_RS_TAPS(easrc_priv->rs_num_taps)); + + /* Reset prefilter coefficient pointer back to 0 */ + ret = fsl_easrc_coeff_mem_ptr_reset(easrc, 0, EASRC_RS_COEFF_MEM); + if (ret) + return ret; + + /* + * When the filter is programmed to run in: + * 32-tap mode, 16-taps, 128-phases 4-coefficients per phase + * 64-tap mode, 32-taps, 64-phases 4-coefficients per phase + * 128-tap mode, 64-taps, 32-phases 4-coefficients per phase + * This means the number of writes is constant no matter + * the mode we are using + */ + num_coeff = 16 * 128 * 4; + + for (i = 0; i < num_coeff; i++) { + r = (uint32_t *)&coef[i]; + regmap_write(easrc->regmap, REG_EASRC_CRCM, + EASRC_CRCM_RS_CWD(r[0])); + regmap_write(easrc->regmap, REG_EASRC_CRCM, + EASRC_CRCM_RS_CWD(r[1])); + } + + return 0; +} + +/** + * Scale filter coefficients (64 bits float) + * For input float32 normalized range (1.0,-1.0) -> output int[16,24,32]: + * scale it by multiplying filter coefficients by 2^31 + * For input int[16, 24, 32] -> output float32 + * scale it by multiplying filter coefficients by 2^-15, 2^-23, 2^-31 + * input: + * asrc: Structure pointer of fsl_asrc + * infilter : Pointer to non-scaled input filter + * shift: The multiply factor + * output: + * outfilter: scaled filter + */ +static int fsl_easrc_normalize_filter(struct fsl_asrc *easrc, + u64 *infilter, + u64 *outfilter, + int shift) +{ + struct device *dev = &easrc->pdev->dev; + u64 coef = *infilter; + s64 exp = (coef & 0x7ff0000000000000ll) >> 52; + u64 outcoef; + + /* + * If exponent is zero (value == 0), or 7ff (value == NaNs) + * dont touch the content + */ + if (exp == 0 || exp == 0x7ff) { + *outfilter = coef; + return 0; + } + + /* coef * 2^shift ==> exp + shift */ + exp += shift; + + if ((shift > 0 && exp >= 2047) || + (shift < 0 && exp <= 0)) { + dev_err(dev, "coef out of range\n"); + return -EINVAL; + } + + outcoef = (u64)(coef & 0x800FFFFFFFFFFFFFll) + ((u64)exp << 52); + *outfilter = outcoef; + + return 0; +} + +static int fsl_easrc_write_pf_coeff_mem(struct fsl_asrc *easrc, int ctx_id, + u64 *coef, int n_taps, int shift) +{ + struct device *dev = &easrc->pdev->dev; + int ret = 0; + int i; + u32 *r; + u64 tmp; + + /* If STx_NUM_TAPS is set to 0x0 then return */ + if (!n_taps) + return 0; + + if (!coef) { + dev_err(dev, "coef table is NULL\n"); + return -EINVAL; + } + + /* + * When switching between stages, the address pointer + * should be reset back to 0x0 before performing a write + */ + ret = fsl_easrc_coeff_mem_ptr_reset(easrc, ctx_id, EASRC_PF_COEFF_MEM); + if (ret) + return ret; + + for (i = 0; i < (n_taps + 1) / 2; i++) { + ret = fsl_easrc_normalize_filter(easrc, &coef[i], &tmp, shift); + if (ret) + return ret; + + r = (uint32_t *)&tmp; + regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id), + EASRC_PCF_CD(r[0])); + regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id), + EASRC_PCF_CD(r[1])); + } + + return 0; +} + +static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc, + unsigned int ctx_id) +{ + struct prefil_params *prefil, *selected_prefil = NULL; + struct fsl_easrc_ctx_priv *ctx_priv; + struct fsl_easrc_priv *easrc_priv; + struct asrc_firmware_hdr *hdr; + struct fsl_asrc_pair *ctx; + struct device *dev; + u32 inrate, outrate, offset = 0; + u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt; + int ret, i; + + if (!easrc) + return -ENODEV; + + dev = &easrc->pdev->dev; + + if (ctx_id >= EASRC_CTX_MAX_NUM) { + dev_err(dev, "Invalid context id[%d]\n", ctx_id); + return -EINVAL; + } + + easrc_priv = easrc->private; + + ctx = easrc->pair[ctx_id]; + ctx_priv = ctx->private; + + in_s_rate = ctx_priv->in_params.sample_rate; + out_s_rate = ctx_priv->out_params.sample_rate; + in_s_fmt = ctx_priv->in_params.sample_format; + out_s_fmt = ctx_priv->out_params.sample_format; + + ctx_priv->in_filled_sample = bits_taps_to_val(easrc_priv->rs_num_taps) / 2; + ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate; + + ctx_priv->st1_num_taps = 0; + ctx_priv->st2_num_taps = 0; + + regmap_write(easrc->regmap, REG_EASRC_CCE1(ctx_id), 0); + regmap_write(easrc->regmap, REG_EASRC_CCE2(ctx_id), 0); + + /* + * The audio float point data range is (-1, 1), the asrc would output + * all zero for float point input and integer output case, that is to + * drop the fractional part of the data directly. + * + * In order to support float to int conversion or int to float + * conversion we need to do special operation on the coefficient to + * enlarge/reduce the data to the expected range. + * + * For float to int case: + * Up sampling: + * 1. Create a 1 tap filter with center tap (only tap) of 2^31 + * in 64 bits floating point. + * double value = (double)(((uint64_t)1) << 31) + * 2. Program 1 tap prefilter with center tap above. + * + * Down sampling, + * 1. If the filter is single stage filter, add "shift" to the exponent + * of stage 1 coefficients. + * 2. If the filter is two stage filter , add "shift" to the exponent + * of stage 2 coefficients. + * + * The "shift" is 31, same for int16, int24, int32 case. + * + * For int to float case: + * Up sampling: + * 1. Create a 1 tap filter with center tap (only tap) of 2^-31 + * in 64 bits floating point. + * 2. Program 1 tap prefilter with center tap above. + * + * Down sampling, + * 1. If the filter is single stage filter, subtract "shift" to the + * exponent of stage 1 coefficients. + * 2. If the filter is two stage filter , subtract "shift" to the + * exponent of stage 2 coefficients. + * + * The "shift" is 15,23,31, different for int16, int24, int32 case. + * + */ + if (out_s_rate >= in_s_rate) { + if (out_s_rate == in_s_rate) + regmap_update_bits(easrc->regmap, + REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_RS_BYPASS_MASK, + EASRC_CCE1_RS_BYPASS); + + ctx_priv->st1_num_taps = 1; + ctx_priv->st1_coeff = &easrc_priv->const_coeff; + ctx_priv->st1_num_exp = 1; + ctx_priv->st2_num_taps = 0; + + if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE && + out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE) + ctx_priv->st1_addexp = 31; + else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE && + out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE) + ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp; + } else { + inrate = ctx_priv->in_params.norm_rate; + outrate = ctx_priv->out_params.norm_rate; + + hdr = easrc_priv->firmware_hdr; + prefil = easrc_priv->prefil; + + for (i = 0; i < hdr->prefil_scen; i++) { + if (inrate == prefil[i].insr && + outrate == prefil[i].outsr) { + selected_prefil = &prefil[i]; + dev_dbg(dev, "Selected prefilter: %u insr, %u outsr, %u st1_taps, %u st2_taps\n", + selected_prefil->insr, + selected_prefil->outsr, + selected_prefil->st1_taps, + selected_prefil->st2_taps); + break; + } + } + + if (!selected_prefil) { + dev_err(dev, "Conversion from in ratio %u(%u) to out ratio %u(%u) is not supported\n", + in_s_rate, inrate, + out_s_rate, outrate); + return -EINVAL; + } + + /* + * In prefilter coeff array, first st1_num_taps represent the + * stage1 prefilter coefficients followed by next st2_num_taps + * representing stage 2 coefficients + */ + ctx_priv->st1_num_taps = selected_prefil->st1_taps; + ctx_priv->st1_coeff = selected_prefil->coeff; + ctx_priv->st1_num_exp = selected_prefil->st1_exp; + + offset = ((selected_prefil->st1_taps + 1) / 2); + ctx_priv->st2_num_taps = selected_prefil->st2_taps; + ctx_priv->st2_coeff = selected_prefil->coeff + offset; + + if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE && + out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE) { + /* only change stage2 coefficient for 2 stage case */ + if (ctx_priv->st2_num_taps > 0) + ctx_priv->st2_addexp = 31; + else + ctx_priv->st1_addexp = 31; + } else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE && + out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE) { + if (ctx_priv->st2_num_taps > 0) + ctx_priv->st2_addexp -= ctx_priv->in_params.fmt.addexp; + else + ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp; + } + } + + ctx_priv->in_filled_sample += (ctx_priv->st1_num_taps / 2) * ctx_priv->st1_num_exp + + ctx_priv->st2_num_taps / 2; + ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate; + + if (ctx_priv->in_filled_sample * out_s_rate % in_s_rate != 0) + ctx_priv->out_missed_sample += 1; + /* + * To modify the value of a prefilter coefficient, the user must + * perform a write to the register ASRC_PRE_COEFF_FIFOn[COEFF_DATA] + * while the respective context RUN_EN bit is set to 0b0 + */ + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id), + EASRC_CC_EN_MASK, 0); + + if (ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) { + dev_err(dev, "ST1 taps [%d] mus be lower than %d\n", + ctx_priv->st1_num_taps, EASRC_MAX_PF_TAPS); + ret = -EINVAL; + goto ctx_error; + } + + /* Update ctx ST1_NUM_TAPS in Context Control Extended 2 register */ + regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id), + EASRC_CCE2_ST1_TAPS_MASK, + EASRC_CCE2_ST1_TAPS(ctx_priv->st1_num_taps - 1)); + + /* Prefilter Coefficient Write Select to write in ST1 coeff */ + regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_COEF_WS_MASK, + EASRC_PF_ST1_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT); + + ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id, + ctx_priv->st1_coeff, + ctx_priv->st1_num_taps, + ctx_priv->st1_addexp); + if (ret) + goto ctx_error; + + if (ctx_priv->st2_num_taps > 0) { + if (ctx_priv->st2_num_taps + ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) { + dev_err(dev, "ST2 taps [%d] mus be lower than %d\n", + ctx_priv->st2_num_taps, EASRC_MAX_PF_TAPS); + ret = -EINVAL; + goto ctx_error; + } + + regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_PF_TSEN_MASK, + EASRC_CCE1_PF_TSEN); + /* + * Enable prefilter stage1 writeback floating point + * which is used for FLOAT_LE case + */ + regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_PF_ST1_WBFP_MASK, + EASRC_CCE1_PF_ST1_WBFP); + + regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_PF_EXP_MASK, + EASRC_CCE1_PF_EXP(ctx_priv->st1_num_exp - 1)); + + /* Update ctx ST2_NUM_TAPS in Context Control Extended 2 reg */ + regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id), + EASRC_CCE2_ST2_TAPS_MASK, + EASRC_CCE2_ST2_TAPS(ctx_priv->st2_num_taps - 1)); + + /* Prefilter Coefficient Write Select to write in ST2 coeff */ + regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_COEF_WS_MASK, + EASRC_PF_ST2_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT); + + ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id, + ctx_priv->st2_coeff, + ctx_priv->st2_num_taps, + ctx_priv->st2_addexp); + if (ret) + goto ctx_error; + } + + return 0; + +ctx_error: + return ret; +} + +static int fsl_easrc_max_ch_for_slot(struct fsl_asrc_pair *ctx, + struct fsl_easrc_slot *slot) +{ + struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; + int st1_mem_alloc = 0, st2_mem_alloc = 0; + int pf_mem_alloc = 0; + int max_channels = 8 - slot->num_channel; + int channels = 0; + + if (ctx_priv->st1_num_taps > 0) { + if (ctx_priv->st2_num_taps > 0) + st1_mem_alloc = + (ctx_priv->st1_num_taps - 1) * ctx_priv->st1_num_exp + 1; + else + st1_mem_alloc = ctx_priv->st1_num_taps; + } + + if (ctx_priv->st2_num_taps > 0) + st2_mem_alloc = ctx_priv->st2_num_taps; + + pf_mem_alloc = st1_mem_alloc + st2_mem_alloc; + + if (pf_mem_alloc != 0) + channels = (6144 - slot->pf_mem_used) / pf_mem_alloc; + else + channels = 8; + + if (channels < max_channels) + max_channels = channels; + + return max_channels; +} + +static int fsl_easrc_config_one_slot(struct fsl_asrc_pair *ctx, + struct fsl_easrc_slot *slot, + unsigned int slot_ctx_idx, + unsigned int *req_channels, + unsigned int *start_channel, + unsigned int *avail_channel) +{ + struct fsl_asrc *easrc = ctx->asrc; + struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; + int st1_chanxexp, st1_mem_alloc = 0, st2_mem_alloc = 0; + unsigned int reg0, reg1, reg2, reg3; + unsigned int addr; + + if (slot->slot_index == 0) { + reg0 = REG_EASRC_DPCS0R0(slot_ctx_idx); + reg1 = REG_EASRC_DPCS0R1(slot_ctx_idx); + reg2 = REG_EASRC_DPCS0R2(slot_ctx_idx); + reg3 = REG_EASRC_DPCS0R3(slot_ctx_idx); + } else { + reg0 = REG_EASRC_DPCS1R0(slot_ctx_idx); + reg1 = REG_EASRC_DPCS1R1(slot_ctx_idx); + reg2 = REG_EASRC_DPCS1R2(slot_ctx_idx); + reg3 = REG_EASRC_DPCS1R3(slot_ctx_idx); + } + + if (*req_channels <= *avail_channel) { + slot->num_channel = *req_channels; + *req_channels = 0; + } else { + slot->num_channel = *avail_channel; + *req_channels -= *avail_channel; + } + + slot->min_channel = *start_channel; + slot->max_channel = *start_channel + slot->num_channel - 1; + slot->ctx_index = ctx->index; + slot->busy = true; + *start_channel += slot->num_channel; + + regmap_update_bits(easrc->regmap, reg0, + EASRC_DPCS0R0_MAXCH_MASK, + EASRC_DPCS0R0_MAXCH(slot->max_channel)); + + regmap_update_bits(easrc->regmap, reg0, + EASRC_DPCS0R0_MINCH_MASK, + EASRC_DPCS0R0_MINCH(slot->min_channel)); + + regmap_update_bits(easrc->regmap, reg0, + EASRC_DPCS0R0_NUMCH_MASK, + EASRC_DPCS0R0_NUMCH(slot->num_channel - 1)); + + regmap_update_bits(easrc->regmap, reg0, + EASRC_DPCS0R0_CTXNUM_MASK, + EASRC_DPCS0R0_CTXNUM(slot->ctx_index)); + + if (ctx_priv->st1_num_taps > 0) { + if (ctx_priv->st2_num_taps > 0) + st1_mem_alloc = + (ctx_priv->st1_num_taps - 1) * slot->num_channel * + ctx_priv->st1_num_exp + slot->num_channel; + else + st1_mem_alloc = ctx_priv->st1_num_taps * slot->num_channel; + + slot->pf_mem_used = st1_mem_alloc; + regmap_update_bits(easrc->regmap, reg2, + EASRC_DPCS0R2_ST1_MA_MASK, + EASRC_DPCS0R2_ST1_MA(st1_mem_alloc)); + + if (slot->slot_index == 1) + addr = PREFILTER_MEM_LEN - st1_mem_alloc; + else + addr = 0; + + regmap_update_bits(easrc->regmap, reg2, + EASRC_DPCS0R2_ST1_SA_MASK, + EASRC_DPCS0R2_ST1_SA(addr)); + } + + if (ctx_priv->st2_num_taps > 0) { + st1_chanxexp = slot->num_channel * (ctx_priv->st1_num_exp - 1); + + regmap_update_bits(easrc->regmap, reg1, + EASRC_DPCS0R1_ST1_EXP_MASK, + EASRC_DPCS0R1_ST1_EXP(st1_chanxexp)); + + st2_mem_alloc = slot->num_channel * ctx_priv->st2_num_taps; + slot->pf_mem_used += st2_mem_alloc; + regmap_update_bits(easrc->regmap, reg3, + EASRC_DPCS0R3_ST2_MA_MASK, + EASRC_DPCS0R3_ST2_MA(st2_mem_alloc)); + + if (slot->slot_index == 1) + addr = PREFILTER_MEM_LEN - st1_mem_alloc - st2_mem_alloc; + else + addr = st1_mem_alloc; + + regmap_update_bits(easrc->regmap, reg3, + EASRC_DPCS0R3_ST2_SA_MASK, + EASRC_DPCS0R3_ST2_SA(addr)); + } + + regmap_update_bits(easrc->regmap, reg0, + EASRC_DPCS0R0_EN_MASK, EASRC_DPCS0R0_EN); + + return 0; +} + +/* + * fsl_easrc_config_slot + * + * A single context can be split amongst any of the 4 context processing pipes + * in the design. + * The total number of channels consumed within the context processor must be + * less than or equal to 8. if a single context is configured to contain more + * than 8 channels then it must be distributed across multiple context + * processing pipe slots. + * + */ +static int fsl_easrc_config_slot(struct fsl_asrc *easrc, unsigned int ctx_id) +{ + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct fsl_asrc_pair *ctx = easrc->pair[ctx_id]; + int req_channels = ctx->channels; + int start_channel = 0, avail_channel; + struct fsl_easrc_slot *slot0, *slot1; + struct fsl_easrc_slot *slota, *slotb; + int i, ret; + + if (req_channels <= 0) + return -EINVAL; + + for (i = 0; i < EASRC_CTX_MAX_NUM; i++) { + slot0 = &easrc_priv->slot[i][0]; + slot1 = &easrc_priv->slot[i][1]; + + if (slot0->busy && slot1->busy) { + continue; + } else if ((slot0->busy && slot0->ctx_index == ctx->index) || + (slot1->busy && slot1->ctx_index == ctx->index)) { + continue; + } else if (!slot0->busy) { + slota = slot0; + slotb = slot1; + slota->slot_index = 0; + } else if (!slot1->busy) { + slota = slot1; + slotb = slot0; + slota->slot_index = 1; + } + + if (!slota || !slotb) + continue; + + avail_channel = fsl_easrc_max_ch_for_slot(ctx, slotb); + if (avail_channel <= 0) + continue; + + ret = fsl_easrc_config_one_slot(ctx, slota, i, &req_channels, + &start_channel, &avail_channel); + if (ret) + return ret; + + if (req_channels > 0) + continue; + else + break; + } + + if (req_channels > 0) { + dev_err(&easrc->pdev->dev, "no avail slot.\n"); + return -EINVAL; + } + + return 0; +} + +/* + * fsl_easrc_release_slot + * + * Clear the slot configuration + */ +static int fsl_easrc_release_slot(struct fsl_asrc *easrc, unsigned int ctx_id) +{ + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct fsl_asrc_pair *ctx = easrc->pair[ctx_id]; + int i; + + for (i = 0; i < EASRC_CTX_MAX_NUM; i++) { + if (easrc_priv->slot[i][0].busy && + easrc_priv->slot[i][0].ctx_index == ctx->index) { + easrc_priv->slot[i][0].busy = false; + easrc_priv->slot[i][0].num_channel = 0; + easrc_priv->slot[i][0].pf_mem_used = 0; + /* set registers */ + regmap_write(easrc->regmap, REG_EASRC_DPCS0R0(i), 0); + regmap_write(easrc->regmap, REG_EASRC_DPCS0R1(i), 0); + regmap_write(easrc->regmap, REG_EASRC_DPCS0R2(i), 0); + regmap_write(easrc->regmap, REG_EASRC_DPCS0R3(i), 0); + } + + if (easrc_priv->slot[i][1].busy && + easrc_priv->slot[i][1].ctx_index == ctx->index) { + easrc_priv->slot[i][1].busy = false; + easrc_priv->slot[i][1].num_channel = 0; + easrc_priv->slot[i][1].pf_mem_used = 0; + /* set registers */ + regmap_write(easrc->regmap, REG_EASRC_DPCS1R0(i), 0); + regmap_write(easrc->regmap, REG_EASRC_DPCS1R1(i), 0); + regmap_write(easrc->regmap, REG_EASRC_DPCS1R2(i), 0); + regmap_write(easrc->regmap, REG_EASRC_DPCS1R3(i), 0); + } + } + + return 0; +} + +/* + * fsl_easrc_config_context + * + * Configure the register relate with context. + */ +int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id) +{ + struct fsl_easrc_ctx_priv *ctx_priv; + struct fsl_asrc_pair *ctx; + struct device *dev; + unsigned long lock_flags; + int ret; + + if (!easrc) + return -ENODEV; + + dev = &easrc->pdev->dev; + + if (ctx_id >= EASRC_CTX_MAX_NUM) { + dev_err(dev, "Invalid context id[%d]\n", ctx_id); + return -EINVAL; + } + + ctx = easrc->pair[ctx_id]; + + ctx_priv = ctx->private; + + fsl_easrc_normalize_rates(ctx); + + ret = fsl_easrc_set_rs_ratio(ctx); + if (ret) + return ret; + + /* Initialize the context coeficients */ + ret = fsl_easrc_prefilter_config(easrc, ctx->index); + if (ret) + return ret; + + spin_lock_irqsave(&easrc->lock, lock_flags); + ret = fsl_easrc_config_slot(easrc, ctx->index); + spin_unlock_irqrestore(&easrc->lock, lock_flags); + if (ret) + return ret; + + /* + * Both prefilter and resampling filters can use following + * initialization modes: + * 2 - zero-fil mode + * 1 - replication mode + * 0 - software control + */ + regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_RS_INIT_MASK, + EASRC_CCE1_RS_INIT(ctx_priv->rs_init_mode)); + + regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), + EASRC_CCE1_PF_INIT_MASK, + EASRC_CCE1_PF_INIT(ctx_priv->pf_init_mode)); + + /* + * Context Input FIFO Watermark + * DMA request is generated when input FIFO < FIFO_WTMK + */ + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id), + EASRC_CC_FIFO_WTMK_MASK, + EASRC_CC_FIFO_WTMK(ctx_priv->in_params.fifo_wtmk)); + + /* + * Context Output FIFO Watermark + * DMA request is generated when output FIFO > FIFO_WTMK + * So we set fifo_wtmk -1 to register. + */ + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx_id), + EASRC_COC_FIFO_WTMK_MASK, + EASRC_COC_FIFO_WTMK(ctx_priv->out_params.fifo_wtmk - 1)); + + /* Number of channels */ + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id), + EASRC_CC_CHEN_MASK, + EASRC_CC_CHEN(ctx->channels - 1)); + return 0; +} + +static int fsl_easrc_process_format(struct fsl_asrc_pair *ctx, + struct fsl_easrc_data_fmt *fmt, + snd_pcm_format_t raw_fmt) +{ + struct fsl_asrc *easrc = ctx->asrc; + struct fsl_easrc_priv *easrc_priv = easrc->private; + int ret; + + if (!fmt) + return -EINVAL; + + /* + * Context Input Floating Point Format + * 0 - Integer Format + * 1 - Single Precision FP Format + */ + fmt->floating_point = !snd_pcm_format_linear(raw_fmt); + fmt->sample_pos = 0; + fmt->iec958 = 0; + + /* Get the data width */ + switch (snd_pcm_format_width(raw_fmt)) { + case 16: + fmt->width = EASRC_WIDTH_16_BIT; + fmt->addexp = 15; + break; + case 20: + fmt->width = EASRC_WIDTH_20_BIT; + fmt->addexp = 19; + break; + case 24: + fmt->width = EASRC_WIDTH_24_BIT; + fmt->addexp = 23; + break; + case 32: + fmt->width = EASRC_WIDTH_32_BIT; + fmt->addexp = 31; + break; + default: + return -EINVAL; + } + + switch (raw_fmt) { + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + fmt->width = easrc_priv->bps_iec958[ctx->index]; + fmt->iec958 = 1; + fmt->floating_point = 0; + if (fmt->width == EASRC_WIDTH_16_BIT) { + fmt->sample_pos = 12; + fmt->addexp = 15; + } else if (fmt->width == EASRC_WIDTH_20_BIT) { + fmt->sample_pos = 8; + fmt->addexp = 19; + } else if (fmt->width == EASRC_WIDTH_24_BIT) { + fmt->sample_pos = 4; + fmt->addexp = 23; + } + break; + default: + break; + } + + /* + * Data Endianness + * 0 - Little-Endian + * 1 - Big-Endian + */ + ret = snd_pcm_format_big_endian(raw_fmt); + if (ret < 0) + return ret; + + fmt->endianness = ret; + + /* + * Input Data sign + * 0b - Signed Format + * 1b - Unsigned Format + */ + fmt->unsign = snd_pcm_format_unsigned(raw_fmt) > 0 ? 1 : 0; + + return 0; +} + +int fsl_easrc_set_ctx_format(struct fsl_asrc_pair *ctx, + snd_pcm_format_t *in_raw_format, + snd_pcm_format_t *out_raw_format) +{ + struct fsl_asrc *easrc = ctx->asrc; + struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; + struct fsl_easrc_data_fmt *in_fmt = &ctx_priv->in_params.fmt; + struct fsl_easrc_data_fmt *out_fmt = &ctx_priv->out_params.fmt; + int ret; + + /* Get the bitfield values for input data format */ + if (in_raw_format && out_raw_format) { + ret = fsl_easrc_process_format(ctx, in_fmt, *in_raw_format); + if (ret) + return ret; + } + + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_BPS_MASK, + EASRC_CC_BPS(in_fmt->width)); + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_ENDIANNESS_MASK, + in_fmt->endianness << EASRC_CC_ENDIANNESS_SHIFT); + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_FMT_MASK, + in_fmt->floating_point << EASRC_CC_FMT_SHIFT); + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_INSIGN_MASK, + in_fmt->unsign << EASRC_CC_INSIGN_SHIFT); + + /* In Sample Position */ + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_SAMPLE_POS_MASK, + EASRC_CC_SAMPLE_POS(in_fmt->sample_pos)); + + /* Get the bitfield values for input data format */ + if (in_raw_format && out_raw_format) { + ret = fsl_easrc_process_format(ctx, out_fmt, *out_raw_format); + if (ret) + return ret; + } + + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_BPS_MASK, + EASRC_COC_BPS(out_fmt->width)); + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_ENDIANNESS_MASK, + out_fmt->endianness << EASRC_COC_ENDIANNESS_SHIFT); + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_FMT_MASK, + out_fmt->floating_point << EASRC_COC_FMT_SHIFT); + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_OUTSIGN_MASK, + out_fmt->unsign << EASRC_COC_OUTSIGN_SHIFT); + + /* Out Sample Position */ + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_SAMPLE_POS_MASK, + EASRC_COC_SAMPLE_POS(out_fmt->sample_pos)); + + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_IEC_EN_MASK, + out_fmt->iec958 << EASRC_COC_IEC_EN_SHIFT); + + return ret; +} + +/* + * The ASRC provides interleaving support in hardware to ensure that a + * variety of sample sources can be internally combined + * to conform with this format. Interleaving parameters are accessed + * through the ASRC_CTRL_IN_ACCESSa and ASRC_CTRL_OUT_ACCESSa registers + */ +int fsl_easrc_set_ctx_organziation(struct fsl_asrc_pair *ctx) +{ + struct fsl_easrc_ctx_priv *ctx_priv; + struct device *dev; + struct fsl_asrc *easrc; + + if (!ctx) + return -ENODEV; + + easrc = ctx->asrc; + ctx_priv = ctx->private; + dev = &easrc->pdev->dev; + + /* input interleaving parameters */ + regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index), + EASRC_CIA_ITER_MASK, + EASRC_CIA_ITER(ctx_priv->in_params.iterations)); + regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index), + EASRC_CIA_GRLEN_MASK, + EASRC_CIA_GRLEN(ctx_priv->in_params.group_len)); + regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index), + EASRC_CIA_ACCLEN_MASK, + EASRC_CIA_ACCLEN(ctx_priv->in_params.access_len)); + + /* output interleaving parameters */ + regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index), + EASRC_COA_ITER_MASK, + EASRC_COA_ITER(ctx_priv->out_params.iterations)); + regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index), + EASRC_COA_GRLEN_MASK, + EASRC_COA_GRLEN(ctx_priv->out_params.group_len)); + regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index), + EASRC_COA_ACCLEN_MASK, + EASRC_COA_ACCLEN(ctx_priv->out_params.access_len)); + + return 0; +} + +/* + * Request one of the available contexts + * + * Returns a negative number on error and >=0 as context id + * on success + */ +int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) +{ + enum asrc_pair_index index = ASRC_INVALID_PAIR; + struct fsl_asrc *easrc = ctx->asrc; + struct device *dev; + unsigned long lock_flags; + int ret = 0; + int i; + + dev = &easrc->pdev->dev; + + spin_lock_irqsave(&easrc->lock, lock_flags); + + for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) { + if (easrc->pair[i]) + continue; + + index = i; + break; + } + + if (index == ASRC_INVALID_PAIR) { + dev_err(dev, "all contexts are busy\n"); + ret = -EBUSY; + } else if (channels > easrc->channel_avail) { + dev_err(dev, "can't give the required channels: %d\n", + channels); + ret = -EINVAL; + } else { + ctx->index = index; + ctx->channels = channels; + easrc->pair[index] = ctx; + easrc->channel_avail -= channels; + } + + spin_unlock_irqrestore(&easrc->lock, lock_flags); + + return ret; +} + +/* + * Release the context + * + * This funciton is mainly doing the revert thing in request context + */ +void fsl_easrc_release_context(struct fsl_asrc_pair *ctx) +{ + unsigned long lock_flags; + struct fsl_asrc *easrc; + struct device *dev; + + if (!ctx) + return; + + easrc = ctx->asrc; + dev = &easrc->pdev->dev; + + spin_lock_irqsave(&easrc->lock, lock_flags); + + fsl_easrc_release_slot(easrc, ctx->index); + + easrc->channel_avail += ctx->channels; + easrc->pair[ctx->index] = NULL; + + spin_unlock_irqrestore(&easrc->lock, lock_flags); +} + +/* + * Start the context + * + * Enable the DMA request and context + */ +int fsl_easrc_start_context(struct fsl_asrc_pair *ctx) +{ + struct fsl_asrc *easrc = ctx->asrc; + + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_FWMDE_MASK, EASRC_CC_FWMDE); + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_FWMDE_MASK, EASRC_COC_FWMDE); + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_EN_MASK, EASRC_CC_EN); + return 0; +} + +/* + * Stop the context + * + * Disable the DMA request and context + */ +int fsl_easrc_stop_context(struct fsl_asrc_pair *ctx) +{ + struct fsl_asrc *easrc = ctx->asrc; + int val, i; + int size = 0; + int retry = 200; + + regmap_read(easrc->regmap, REG_EASRC_CC(ctx->index), &val); + + if (val & EASRC_CC_EN_MASK) { + regmap_update_bits(easrc->regmap, + REG_EASRC_CC(ctx->index), + EASRC_CC_STOP_MASK, EASRC_CC_STOP); + do { + regmap_read(easrc->regmap, REG_EASRC_SFS(ctx->index), &val); + val &= EASRC_SFS_NSGO_MASK; + size = val >> EASRC_SFS_NSGO_SHIFT; + + /* Read FIFO, drop the data */ + for (i = 0; i < size * ctx->channels; i++) + regmap_read(easrc->regmap, REG_EASRC_RDFIFO(ctx->index), &val); + /* Check RUN_STOP_DONE */ + regmap_read(easrc->regmap, REG_EASRC_IRQF, &val); + if (val & EASRC_IRQF_RSD(1 << ctx->index)) { + /*Clear RUN_STOP_DONE*/ + regmap_write_bits(easrc->regmap, + REG_EASRC_IRQF, + EASRC_IRQF_RSD(1 << ctx->index), + EASRC_IRQF_RSD(1 << ctx->index)); + break; + } + udelay(100); + } while (--retry); + + if (retry == 0) + dev_warn(&easrc->pdev->dev, "RUN STOP fail\n"); + } + + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_EN_MASK | EASRC_CC_STOP_MASK, 0); + regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), + EASRC_CC_FWMDE_MASK, 0); + regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), + EASRC_COC_FWMDE_MASK, 0); + return 0; +} + +struct dma_chan *fsl_easrc_get_dma_channel(struct fsl_asrc_pair *ctx, + bool dir) +{ + struct fsl_asrc *easrc = ctx->asrc; + enum asrc_pair_index index = ctx->index; + char name[8]; + + /* Example of dma name: ctx0_rx */ + sprintf(name, "ctx%c_%cx", index + '0', dir == IN ? 'r' : 't'); + + return dma_request_slave_channel(&easrc->pdev->dev, name); +}; +EXPORT_SYMBOL_GPL(fsl_easrc_get_dma_channel); + +static const unsigned int easrc_rates[] = { + 8000, 11025, 12000, 16000, + 22050, 24000, 32000, 44100, + 48000, 64000, 88200, 96000, + 128000, 176400, 192000, 256000, + 352800, 384000, 705600, 768000, +}; + +static const struct snd_pcm_hw_constraint_list easrc_rate_constraints = { + .count = ARRAY_SIZE(easrc_rates), + .list = easrc_rates, +}; + +static int fsl_easrc_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &easrc_rate_constraints); +} + +static int fsl_easrc_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *ctx = runtime->private_data; + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = fsl_easrc_start_context(ctx); + if (ret) + return ret; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = fsl_easrc_stop_context(ctx); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int fsl_easrc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsl_asrc *easrc = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *runtime = substream->runtime; + struct device *dev = &easrc->pdev->dev; + struct fsl_asrc_pair *ctx = runtime->private_data; + struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + snd_pcm_format_t format = params_format(params); + int ret; + + ret = fsl_easrc_request_context(channels, ctx); + if (ret) { + dev_err(dev, "failed to request context\n"); + return ret; + } + + ctx_priv->ctx_streams |= BIT(substream->stream); + + /* + * Set the input and output ratio so we can compute + * the resampling ratio in RS_LOW/HIGH + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ctx_priv->in_params.sample_rate = rate; + ctx_priv->in_params.sample_format = format; + ctx_priv->out_params.sample_rate = easrc->asrc_rate; + ctx_priv->out_params.sample_format = easrc->asrc_format; + } else { + ctx_priv->out_params.sample_rate = rate; + ctx_priv->out_params.sample_format = format; + ctx_priv->in_params.sample_rate = easrc->asrc_rate; + ctx_priv->in_params.sample_format = easrc->asrc_format; + } + + ctx->channels = channels; + ctx_priv->in_params.fifo_wtmk = 0x20; + ctx_priv->out_params.fifo_wtmk = 0x20; + + /* + * Do only rate conversion and keep the same format for input + * and output data + */ + ret = fsl_easrc_set_ctx_format(ctx, + &ctx_priv->in_params.sample_format, + &ctx_priv->out_params.sample_format); + if (ret) { + dev_err(dev, "failed to set format %d", ret); + return ret; + } + + ret = fsl_easrc_config_context(easrc, ctx->index); + if (ret) { + dev_err(dev, "failed to config context\n"); + return ret; + } + + ctx_priv->in_params.iterations = 1; + ctx_priv->in_params.group_len = ctx->channels; + ctx_priv->in_params.access_len = ctx->channels; + ctx_priv->out_params.iterations = 1; + ctx_priv->out_params.group_len = ctx->channels; + ctx_priv->out_params.access_len = ctx->channels; + + ret = fsl_easrc_set_ctx_organziation(ctx); + if (ret) { + dev_err(dev, "failed to set fifo organization\n"); + return ret; + } + + return 0; +} + +static int fsl_easrc_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *ctx = runtime->private_data; + struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; + + if (ctx && (ctx_priv->ctx_streams & BIT(substream->stream))) { + ctx_priv->ctx_streams &= ~BIT(substream->stream); + fsl_easrc_release_context(ctx); + } + + return 0; +} + +static struct snd_soc_dai_ops fsl_easrc_dai_ops = { + .startup = fsl_easrc_startup, + .trigger = fsl_easrc_trigger, + .hw_params = fsl_easrc_hw_params, + .hw_free = fsl_easrc_hw_free, +}; + +static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) +{ + struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev); + + snd_soc_dai_init_dma_data(cpu_dai, + &easrc->dma_params_tx, + &easrc->dma_params_rx); + return 0; +} + +static struct snd_soc_dai_driver fsl_easrc_dai = { + .probe = fsl_easrc_dai_probe, + .playback = { + .stream_name = "ASRC-Playback", + .channels_min = 1, + .channels_max = 32, + .rate_min = 8000, + .rate_max = 768000, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_EASRC_FORMATS, + }, + .capture = { + .stream_name = "ASRC-Capture", + .channels_min = 1, + .channels_max = 32, + .rate_min = 8000, + .rate_max = 768000, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_EASRC_FORMATS | + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, + }, + .ops = &fsl_easrc_dai_ops, +}; + +static const struct snd_soc_component_driver fsl_easrc_component = { + .name = "fsl-easrc-dai", + .controls = fsl_easrc_snd_controls, + .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls), +}; + +static const struct reg_default fsl_easrc_reg_defaults[] = { + {REG_EASRC_WRFIFO(0), 0x00000000}, + {REG_EASRC_WRFIFO(1), 0x00000000}, + {REG_EASRC_WRFIFO(2), 0x00000000}, + {REG_EASRC_WRFIFO(3), 0x00000000}, + {REG_EASRC_RDFIFO(0), 0x00000000}, + {REG_EASRC_RDFIFO(1), 0x00000000}, + {REG_EASRC_RDFIFO(2), 0x00000000}, + {REG_EASRC_RDFIFO(3), 0x00000000}, + {REG_EASRC_CC(0), 0x00000000}, + {REG_EASRC_CC(1), 0x00000000}, + {REG_EASRC_CC(2), 0x00000000}, + {REG_EASRC_CC(3), 0x00000000}, + {REG_EASRC_CCE1(0), 0x00000000}, + {REG_EASRC_CCE1(1), 0x00000000}, + {REG_EASRC_CCE1(2), 0x00000000}, + {REG_EASRC_CCE1(3), 0x00000000}, + {REG_EASRC_CCE2(0), 0x00000000}, + {REG_EASRC_CCE2(1), 0x00000000}, + {REG_EASRC_CCE2(2), 0x00000000}, + {REG_EASRC_CCE2(3), 0x00000000}, + {REG_EASRC_CIA(0), 0x00000000}, + {REG_EASRC_CIA(1), 0x00000000}, + {REG_EASRC_CIA(2), 0x00000000}, + {REG_EASRC_CIA(3), 0x00000000}, + {REG_EASRC_DPCS0R0(0), 0x00000000}, + {REG_EASRC_DPCS0R0(1), 0x00000000}, + {REG_EASRC_DPCS0R0(2), 0x00000000}, + {REG_EASRC_DPCS0R0(3), 0x00000000}, + {REG_EASRC_DPCS0R1(0), 0x00000000}, + {REG_EASRC_DPCS0R1(1), 0x00000000}, + {REG_EASRC_DPCS0R1(2), 0x00000000}, + {REG_EASRC_DPCS0R1(3), 0x00000000}, + {REG_EASRC_DPCS0R2(0), 0x00000000}, + {REG_EASRC_DPCS0R2(1), 0x00000000}, + {REG_EASRC_DPCS0R2(2), 0x00000000}, + {REG_EASRC_DPCS0R2(3), 0x00000000}, + {REG_EASRC_DPCS0R3(0), 0x00000000}, + {REG_EASRC_DPCS0R3(1), 0x00000000}, + {REG_EASRC_DPCS0R3(2), 0x00000000}, + {REG_EASRC_DPCS0R3(3), 0x00000000}, + {REG_EASRC_DPCS1R0(0), 0x00000000}, + {REG_EASRC_DPCS1R0(1), 0x00000000}, + {REG_EASRC_DPCS1R0(2), 0x00000000}, + {REG_EASRC_DPCS1R0(3), 0x00000000}, + {REG_EASRC_DPCS1R1(0), 0x00000000}, + {REG_EASRC_DPCS1R1(1), 0x00000000}, + {REG_EASRC_DPCS1R1(2), 0x00000000}, + {REG_EASRC_DPCS1R1(3), 0x00000000}, + {REG_EASRC_DPCS1R2(0), 0x00000000}, + {REG_EASRC_DPCS1R2(1), 0x00000000}, + {REG_EASRC_DPCS1R2(2), 0x00000000}, + {REG_EASRC_DPCS1R2(3), 0x00000000}, + {REG_EASRC_DPCS1R3(0), 0x00000000}, + {REG_EASRC_DPCS1R3(1), 0x00000000}, + {REG_EASRC_DPCS1R3(2), 0x00000000}, + {REG_EASRC_DPCS1R3(3), 0x00000000}, + {REG_EASRC_COC(0), 0x00000000}, + {REG_EASRC_COC(1), 0x00000000}, + {REG_EASRC_COC(2), 0x00000000}, + {REG_EASRC_COC(3), 0x00000000}, + {REG_EASRC_COA(0), 0x00000000}, + {REG_EASRC_COA(1), 0x00000000}, + {REG_EASRC_COA(2), 0x00000000}, + {REG_EASRC_COA(3), 0x00000000}, + {REG_EASRC_SFS(0), 0x00000000}, + {REG_EASRC_SFS(1), 0x00000000}, + {REG_EASRC_SFS(2), 0x00000000}, + {REG_EASRC_SFS(3), 0x00000000}, + {REG_EASRC_RRL(0), 0x00000000}, + {REG_EASRC_RRL(1), 0x00000000}, + {REG_EASRC_RRL(2), 0x00000000}, + {REG_EASRC_RRL(3), 0x00000000}, + {REG_EASRC_RRH(0), 0x00000000}, + {REG_EASRC_RRH(1), 0x00000000}, + {REG_EASRC_RRH(2), 0x00000000}, + {REG_EASRC_RRH(3), 0x00000000}, + {REG_EASRC_RUC(0), 0x00000000}, + {REG_EASRC_RUC(1), 0x00000000}, + {REG_EASRC_RUC(2), 0x00000000}, + {REG_EASRC_RUC(3), 0x00000000}, + {REG_EASRC_RUR(0), 0x7FFFFFFF}, + {REG_EASRC_RUR(1), 0x7FFFFFFF}, + {REG_EASRC_RUR(2), 0x7FFFFFFF}, + {REG_EASRC_RUR(3), 0x7FFFFFFF}, + {REG_EASRC_RCTCL, 0x00000000}, + {REG_EASRC_RCTCH, 0x00000000}, + {REG_EASRC_PCF(0), 0x00000000}, + {REG_EASRC_PCF(1), 0x00000000}, + {REG_EASRC_PCF(2), 0x00000000}, + {REG_EASRC_PCF(3), 0x00000000}, + {REG_EASRC_CRCM, 0x00000000}, + {REG_EASRC_CRCC, 0x00000000}, + {REG_EASRC_IRQC, 0x00000FFF}, + {REG_EASRC_IRQF, 0x00000000}, + {REG_EASRC_CS0(0), 0x00000000}, + {REG_EASRC_CS0(1), 0x00000000}, + {REG_EASRC_CS0(2), 0x00000000}, + {REG_EASRC_CS0(3), 0x00000000}, + {REG_EASRC_CS1(0), 0x00000000}, + {REG_EASRC_CS1(1), 0x00000000}, + {REG_EASRC_CS1(2), 0x00000000}, + {REG_EASRC_CS1(3), 0x00000000}, + {REG_EASRC_CS2(0), 0x00000000}, + {REG_EASRC_CS2(1), 0x00000000}, + {REG_EASRC_CS2(2), 0x00000000}, + {REG_EASRC_CS2(3), 0x00000000}, + {REG_EASRC_CS3(0), 0x00000000}, + {REG_EASRC_CS3(1), 0x00000000}, + {REG_EASRC_CS3(2), 0x00000000}, + {REG_EASRC_CS3(3), 0x00000000}, + {REG_EASRC_CS4(0), 0x00000000}, + {REG_EASRC_CS4(1), 0x00000000}, + {REG_EASRC_CS4(2), 0x00000000}, + {REG_EASRC_CS4(3), 0x00000000}, + {REG_EASRC_CS5(0), 0x00000000}, + {REG_EASRC_CS5(1), 0x00000000}, + {REG_EASRC_CS5(2), 0x00000000}, + {REG_EASRC_CS5(3), 0x00000000}, + {REG_EASRC_DBGC, 0x00000000}, + {REG_EASRC_DBGS, 0x00000000}, +}; + +static const struct regmap_range fsl_easrc_readable_ranges[] = { + regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RCTCH), + regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_PCF(3)), + regmap_reg_range(REG_EASRC_CRCC, REG_EASRC_DBGS), +}; + +static const struct regmap_access_table fsl_easrc_readable_table = { + .yes_ranges = fsl_easrc_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(fsl_easrc_readable_ranges), +}; + +static const struct regmap_range fsl_easrc_writeable_ranges[] = { + regmap_reg_range(REG_EASRC_WRFIFO(0), REG_EASRC_WRFIFO(3)), + regmap_reg_range(REG_EASRC_CC(0), REG_EASRC_COA(3)), + regmap_reg_range(REG_EASRC_RRL(0), REG_EASRC_RCTCH), + regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_DBGC), +}; + +static const struct regmap_access_table fsl_easrc_writeable_table = { + .yes_ranges = fsl_easrc_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(fsl_easrc_writeable_ranges), +}; + +static const struct regmap_range fsl_easrc_volatileable_ranges[] = { + regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RDFIFO(3)), + regmap_reg_range(REG_EASRC_SFS(0), REG_EASRC_SFS(3)), + regmap_reg_range(REG_EASRC_IRQF, REG_EASRC_IRQF), + regmap_reg_range(REG_EASRC_DBGS, REG_EASRC_DBGS), +}; + +static const struct regmap_access_table fsl_easrc_volatileable_table = { + .yes_ranges = fsl_easrc_volatileable_ranges, + .n_yes_ranges = ARRAY_SIZE(fsl_easrc_volatileable_ranges), +}; + +static const struct regmap_config fsl_easrc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = REG_EASRC_DBGS, + .reg_defaults = fsl_easrc_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(fsl_easrc_reg_defaults), + .rd_table = &fsl_easrc_readable_table, + .wr_table = &fsl_easrc_writeable_table, + .volatile_table = &fsl_easrc_volatileable_table, + .cache_type = REGCACHE_RBTREE, +}; + +#ifdef DEBUG +static void fsl_easrc_dump_firmware(struct fsl_asrc *easrc) +{ + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct asrc_firmware_hdr *firm = easrc_priv->firmware_hdr; + struct interp_params *interp = easrc_priv->interp; + struct prefil_params *prefil = easrc_priv->prefil; + struct device *dev = &easrc->pdev->dev; + int i; + + if (firm->magic != FIRMWARE_MAGIC) { + dev_err(dev, "Wrong magic. Something went wrong!"); + return; + } + + dev_dbg(dev, "Firmware v%u dump:\n", firm->firmware_version); + dev_dbg(dev, "Num prefitler scenarios: %u\n", firm->prefil_scen); + dev_dbg(dev, "Num interpolation scenarios: %u\n", firm->interp_scen); + dev_dbg(dev, "\nInterpolation scenarios:\n"); + + for (i = 0; i < firm->interp_scen; i++) { + if (interp[i].magic != FIRMWARE_MAGIC) { + dev_dbg(dev, "%d. wrong interp magic: %x\n", + i, interp[i].magic); + continue; + } + dev_dbg(dev, "%d. taps: %u, phases: %u, center: %llu\n", i, + interp[i].num_taps, interp[i].num_phases, + interp[i].center_tap); + } + + for (i = 0; i < firm->prefil_scen; i++) { + if (prefil[i].magic != FIRMWARE_MAGIC) { + dev_dbg(dev, "%d. wrong prefil magic: %x\n", + i, prefil[i].magic); + continue; + } + dev_dbg(dev, "%d. insr: %u, outsr: %u, st1: %u, st2: %u\n", i, + prefil[i].insr, prefil[i].outsr, + prefil[i].st1_taps, prefil[i].st2_taps); + } + + dev_dbg(dev, "end of firmware dump\n"); +} +#endif + +static int fsl_easrc_get_firmware(struct fsl_asrc *easrc) +{ + struct fsl_easrc_priv *easrc_priv; + const struct firmware **fw_p; + u32 pnum, inum, offset; + const u8 *data; + int ret; + + if (!easrc) + return -EINVAL; + + easrc_priv = easrc->private; + fw_p = &easrc_priv->fw; + + ret = request_firmware(fw_p, easrc_priv->fw_name, &easrc->pdev->dev); + if (ret) + return ret; + + data = easrc_priv->fw->data; + + easrc_priv->firmware_hdr = (struct asrc_firmware_hdr *)data; + pnum = easrc_priv->firmware_hdr->prefil_scen; + inum = easrc_priv->firmware_hdr->interp_scen; + + if (inum) { + offset = sizeof(struct asrc_firmware_hdr); + easrc_priv->interp = (struct interp_params *)(data + offset); + } + + if (pnum) { + offset = sizeof(struct asrc_firmware_hdr) + + inum * sizeof(struct interp_params); + easrc_priv->prefil = (struct prefil_params *)(data + offset); + } + +#ifdef DEBUG + fsl_easrc_dump_firmware(easrc); +#endif + + return 0; +} + +static irqreturn_t fsl_easrc_isr(int irq, void *dev_id) +{ + struct fsl_asrc *easrc = (struct fsl_asrc *)dev_id; + struct device *dev = &easrc->pdev->dev; + int val; + + regmap_read(easrc->regmap, REG_EASRC_IRQF, &val); + + if (val & EASRC_IRQF_OER_MASK) + dev_dbg(dev, "output FIFO underflow\n"); + + if (val & EASRC_IRQF_IFO_MASK) + dev_dbg(dev, "input FIFO overflow\n"); + + return IRQ_HANDLED; +} + +static int fsl_easrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) +{ + return REG_EASRC_FIFO(dir, index); +} + +static const struct of_device_id fsl_easrc_dt_ids[] = { + { .compatible = "fsl,imx8mn-easrc",}, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_easrc_dt_ids); + +static int fsl_easrc_probe(struct platform_device *pdev) +{ + struct fsl_easrc_priv *easrc_priv; + struct device *dev = &pdev->dev; + struct fsl_asrc *easrc; + struct resource *res; + struct device_node *np; + void __iomem *regs; + int ret, irq; + + easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL); + if (!easrc) + return -ENOMEM; + + easrc_priv = devm_kzalloc(dev, sizeof(*easrc_priv), GFP_KERNEL); + if (!easrc_priv) + return -ENOMEM; + + easrc->pdev = pdev; + easrc->private = easrc_priv; + np = dev->of_node; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "failed ioremap\n"); + return PTR_ERR(regs); + } + + easrc->paddr = res->start; + + easrc->regmap = devm_regmap_init_mmio_clk(dev, "mem", regs, + &fsl_easrc_regmap_config); + if (IS_ERR(easrc->regmap)) { + dev_err(dev, "failed to init regmap"); + return PTR_ERR(easrc->regmap); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq for node %pOF\n", np); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, fsl_easrc_isr, 0, + dev_name(dev), easrc); + if (ret) { + dev_err(dev, "failed to claim irq %u: %d\n", irq, ret); + return ret; + } + + easrc->mem_clk = devm_clk_get(dev, "mem"); + if (IS_ERR(easrc->mem_clk)) { + dev_err(dev, "failed to get mem clock\n"); + return PTR_ERR(easrc->mem_clk); + } + + /* Set default value */ + easrc->channel_avail = 32; + easrc->get_dma_channel = fsl_easrc_get_dma_channel; + easrc->request_pair = fsl_easrc_request_context; + easrc->release_pair = fsl_easrc_release_context; + easrc->get_fifo_addr = fsl_easrc_get_fifo_addr; + + easrc_priv->rs_num_taps = EASRC_RS_32_TAPS; + easrc_priv->const_coeff = 0x3FF0000000000000; + + ret = of_property_read_u32(np, "fsl,asrc-rate", &easrc->asrc_rate); + if (ret) { + dev_err(dev, "failed to asrc rate\n"); + return ret; + } + + ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format); + if (ret) { + dev_err(dev, "failed to asrc format\n"); + return ret; + } + + if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) { + dev_warn(dev, "unsupported format, switching to S24_LE\n"); + easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + } + + ret = of_property_read_string(np, "firmware-name", + &easrc_priv->fw_name); + if (ret) { + dev_err(dev, "failed to get firmware name\n"); + return ret; + } + + platform_set_drvdata(pdev, easrc); + pm_runtime_enable(dev); + + spin_lock_init(&easrc->lock); + + regcache_cache_only(easrc->regmap, true); + + ret = devm_snd_soc_register_component(dev, &fsl_easrc_component, + &fsl_easrc_dai, 1); + if (ret) { + dev_err(dev, "failed to register ASoC DAI\n"); + return ret; + } + + ret = devm_snd_soc_register_component(dev, &fsl_asrc_component, + NULL, 0); + if (ret) { + dev_err(&pdev->dev, "failed to register ASoC platform\n"); + return ret; + } + + return 0; +} + +static int fsl_easrc_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int fsl_easrc_runtime_suspend(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + struct fsl_easrc_priv *easrc_priv = easrc->private; + unsigned long lock_flags; + + regcache_cache_only(easrc->regmap, true); + + clk_disable_unprepare(easrc->mem_clk); + + spin_lock_irqsave(&easrc->lock, lock_flags); + easrc_priv->firmware_loaded = 0; + spin_unlock_irqrestore(&easrc->lock, lock_flags); + + return 0; +} + +static int fsl_easrc_runtime_resume(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + struct fsl_easrc_priv *easrc_priv = easrc->private; + struct fsl_easrc_ctx_priv *ctx_priv; + struct fsl_asrc_pair *ctx; + unsigned long lock_flags; + int ret; + int i; + + ret = clk_prepare_enable(easrc->mem_clk); + if (ret) + return ret; + + regcache_cache_only(easrc->regmap, false); + regcache_mark_dirty(easrc->regmap); + regcache_sync(easrc->regmap); + + spin_lock_irqsave(&easrc->lock, lock_flags); + if (easrc_priv->firmware_loaded) { + spin_unlock_irqrestore(&easrc->lock, lock_flags); + goto skip_load; + } + easrc_priv->firmware_loaded = 1; + spin_unlock_irqrestore(&easrc->lock, lock_flags); + + ret = fsl_easrc_get_firmware(easrc); + if (ret) { + dev_err(dev, "failed to get firmware\n"); + goto disable_mem_clk; + } + + /* + * Write Resampling Coefficients + * The coefficient RAM must be configured prior to beginning of + * any context processing within the ASRC + */ + ret = fsl_easrc_resampler_config(easrc); + if (ret) { + dev_err(dev, "resampler config failed\n"); + goto disable_mem_clk; + } + + for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) { + ctx = easrc->pair[i]; + if (!ctx) + continue; + + ctx_priv = ctx->private; + fsl_easrc_set_rs_ratio(ctx); + ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * + ctx_priv->out_params.sample_rate / + ctx_priv->in_params.sample_rate; + if (ctx_priv->in_filled_sample * ctx_priv->out_params.sample_rate + % ctx_priv->in_params.sample_rate != 0) + ctx_priv->out_missed_sample += 1; + + ret = fsl_easrc_write_pf_coeff_mem(easrc, i, + ctx_priv->st1_coeff, + ctx_priv->st1_num_taps, + ctx_priv->st1_addexp); + if (ret) + goto disable_mem_clk; + + ret = fsl_easrc_write_pf_coeff_mem(easrc, i, + ctx_priv->st2_coeff, + ctx_priv->st2_num_taps, + ctx_priv->st2_addexp); + if (ret) + goto disable_mem_clk; + } + +skip_load: + return 0; + +disable_mem_clk: + clk_disable_unprepare(easrc->mem_clk); + return ret; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops fsl_easrc_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, + fsl_easrc_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver fsl_easrc_driver = { + .probe = fsl_easrc_probe, + .remove = fsl_easrc_remove, + .driver = { + .name = "fsl-easrc", + .pm = &fsl_easrc_pm_ops, + .of_match_table = fsl_easrc_dt_ids, + }, +}; +module_platform_driver(fsl_easrc_driver); + +MODULE_DESCRIPTION("NXP Enhanced Asynchronous Sample Rate (eASRC) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h new file mode 100644 index 000000000000..30620d56252c --- /dev/null +++ b/sound/soc/fsl/fsl_easrc.h @@ -0,0 +1,651 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 NXP + */ + +#ifndef _FSL_EASRC_H +#define _FSL_EASRC_H + +#include <sound/asound.h> +#include <linux/platform_data/dma-imx.h> + +#include "fsl_asrc_common.h" + +/* EASRC Register Map */ + +/* ASRC Input Write FIFO */ +#define REG_EASRC_WRFIFO(ctx) (0x000 + 4 * (ctx)) +/* ASRC Output Read FIFO */ +#define REG_EASRC_RDFIFO(ctx) (0x010 + 4 * (ctx)) +/* ASRC Context Control */ +#define REG_EASRC_CC(ctx) (0x020 + 4 * (ctx)) +/* ASRC Context Control Extended 1 */ +#define REG_EASRC_CCE1(ctx) (0x030 + 4 * (ctx)) +/* ASRC Context Control Extended 2 */ +#define REG_EASRC_CCE2(ctx) (0x040 + 4 * (ctx)) +/* ASRC Control Input Access */ +#define REG_EASRC_CIA(ctx) (0x050 + 4 * (ctx)) +/* ASRC Datapath Processor Control Slot0 */ +#define REG_EASRC_DPCS0R0(ctx) (0x060 + 4 * (ctx)) +#define REG_EASRC_DPCS0R1(ctx) (0x070 + 4 * (ctx)) +#define REG_EASRC_DPCS0R2(ctx) (0x080 + 4 * (ctx)) +#define REG_EASRC_DPCS0R3(ctx) (0x090 + 4 * (ctx)) +/* ASRC Datapath Processor Control Slot1 */ +#define REG_EASRC_DPCS1R0(ctx) (0x0A0 + 4 * (ctx)) +#define REG_EASRC_DPCS1R1(ctx) (0x0B0 + 4 * (ctx)) +#define REG_EASRC_DPCS1R2(ctx) (0x0C0 + 4 * (ctx)) +#define REG_EASRC_DPCS1R3(ctx) (0x0D0 + 4 * (ctx)) +/* ASRC Context Output Control */ +#define REG_EASRC_COC(ctx) (0x0E0 + 4 * (ctx)) +/* ASRC Control Output Access */ +#define REG_EASRC_COA(ctx) (0x0F0 + 4 * (ctx)) +/* ASRC Sample FIFO Status */ +#define REG_EASRC_SFS(ctx) (0x100 + 4 * (ctx)) +/* ASRC Resampling Ratio Low */ +#define REG_EASRC_RRL(ctx) (0x110 + 8 * (ctx)) +/* ASRC Resampling Ratio High */ +#define REG_EASRC_RRH(ctx) (0x114 + 8 * (ctx)) +/* ASRC Resampling Ratio Update Control */ +#define REG_EASRC_RUC(ctx) (0x130 + 4 * (ctx)) +/* ASRC Resampling Ratio Update Rate */ +#define REG_EASRC_RUR(ctx) (0x140 + 4 * (ctx)) +/* ASRC Resampling Center Tap Coefficient Low */ +#define REG_EASRC_RCTCL (0x150) +/* ASRC Resampling Center Tap Coefficient High */ +#define REG_EASRC_RCTCH (0x154) +/* ASRC Prefilter Coefficient FIFO */ +#define REG_EASRC_PCF(ctx) (0x160 + 4 * (ctx)) +/* ASRC Context Resampling Coefficient Memory */ +#define REG_EASRC_CRCM 0x170 +/* ASRC Context Resampling Coefficient Control*/ +#define REG_EASRC_CRCC 0x174 +/* ASRC Interrupt Control */ +#define REG_EASRC_IRQC 0x178 +/* ASRC Interrupt Status Flags */ +#define REG_EASRC_IRQF 0x17C +/* ASRC Channel Status 0 */ +#define REG_EASRC_CS0(ctx) (0x180 + 4 * (ctx)) +/* ASRC Channel Status 1 */ +#define REG_EASRC_CS1(ctx) (0x190 + 4 * (ctx)) +/* ASRC Channel Status 2 */ +#define REG_EASRC_CS2(ctx) (0x1A0 + 4 * (ctx)) +/* ASRC Channel Status 3 */ +#define REG_EASRC_CS3(ctx) (0x1B0 + 4 * (ctx)) +/* ASRC Channel Status 4 */ +#define REG_EASRC_CS4(ctx) (0x1C0 + 4 * (ctx)) +/* ASRC Channel Status 5 */ +#define REG_EASRC_CS5(ctx) (0x1D0 + 4 * (ctx)) +/* ASRC Debug Control Register */ +#define REG_EASRC_DBGC 0x1E0 +/* ASRC Debug Status Register */ +#define REG_EASRC_DBGS 0x1E4 + +#define REG_EASRC_FIFO(x, ctx) (x == IN ? REG_EASRC_WRFIFO(ctx) \ + : REG_EASRC_RDFIFO(ctx)) + +/* ASRC Context Control (CC) */ +#define EASRC_CC_EN_SHIFT 31 +#define EASRC_CC_EN_MASK BIT(EASRC_CC_EN_SHIFT) +#define EASRC_CC_EN BIT(EASRC_CC_EN_SHIFT) +#define EASRC_CC_STOP_SHIFT 29 +#define EASRC_CC_STOP_MASK BIT(EASRC_CC_STOP_SHIFT) +#define EASRC_CC_STOP BIT(EASRC_CC_STOP_SHIFT) +#define EASRC_CC_FWMDE_SHIFT 28 +#define EASRC_CC_FWMDE_MASK BIT(EASRC_CC_FWMDE_SHIFT) +#define EASRC_CC_FWMDE BIT(EASRC_CC_FWMDE_SHIFT) +#define EASRC_CC_FIFO_WTMK_SHIFT 16 +#define EASRC_CC_FIFO_WTMK_WIDTH 7 +#define EASRC_CC_FIFO_WTMK_MASK ((BIT(EASRC_CC_FIFO_WTMK_WIDTH) - 1) \ + << EASRC_CC_FIFO_WTMK_SHIFT) +#define EASRC_CC_FIFO_WTMK(v) (((v) << EASRC_CC_FIFO_WTMK_SHIFT) \ + & EASRC_CC_FIFO_WTMK_MASK) +#define EASRC_CC_SAMPLE_POS_SHIFT 11 +#define EASRC_CC_SAMPLE_POS_WIDTH 5 +#define EASRC_CC_SAMPLE_POS_MASK ((BIT(EASRC_CC_SAMPLE_POS_WIDTH) - 1) \ + << EASRC_CC_SAMPLE_POS_SHIFT) +#define EASRC_CC_SAMPLE_POS(v) (((v) << EASRC_CC_SAMPLE_POS_SHIFT) \ + & EASRC_CC_SAMPLE_POS_MASK) +#define EASRC_CC_ENDIANNESS_SHIFT 10 +#define EASRC_CC_ENDIANNESS_MASK BIT(EASRC_CC_ENDIANNESS_SHIFT) +#define EASRC_CC_ENDIANNESS BIT(EASRC_CC_ENDIANNESS_SHIFT) +#define EASRC_CC_BPS_SHIFT 8 +#define EASRC_CC_BPS_WIDTH 2 +#define EASRC_CC_BPS_MASK ((BIT(EASRC_CC_BPS_WIDTH) - 1) \ + << EASRC_CC_BPS_SHIFT) +#define EASRC_CC_BPS(v) (((v) << EASRC_CC_BPS_SHIFT) \ + & EASRC_CC_BPS_MASK) +#define EASRC_CC_FMT_SHIFT 7 +#define EASRC_CC_FMT_MASK BIT(EASRC_CC_FMT_SHIFT) +#define EASRC_CC_FMT BIT(EASRC_CC_FMT_SHIFT) +#define EASRC_CC_INSIGN_SHIFT 6 +#define EASRC_CC_INSIGN_MASK BIT(EASRC_CC_INSIGN_SHIFT) +#define EASRC_CC_INSIGN BIT(EASRC_CC_INSIGN_SHIFT) +#define EASRC_CC_CHEN_SHIFT 0 +#define EASRC_CC_CHEN_WIDTH 5 +#define EASRC_CC_CHEN_MASK ((BIT(EASRC_CC_CHEN_WIDTH) - 1) \ + << EASRC_CC_CHEN_SHIFT) +#define EASRC_CC_CHEN(v) (((v) << EASRC_CC_CHEN_SHIFT) \ + & EASRC_CC_CHEN_MASK) + +/* ASRC Context Control Extended 1 (CCE1) */ +#define EASRC_CCE1_COEF_WS_SHIFT 25 +#define EASRC_CCE1_COEF_WS_MASK BIT(EASRC_CCE1_COEF_WS_SHIFT) +#define EASRC_CCE1_COEF_WS BIT(EASRC_CCE1_COEF_WS_SHIFT) +#define EASRC_CCE1_COEF_MEM_RST_SHIFT 24 +#define EASRC_CCE1_COEF_MEM_RST_MASK BIT(EASRC_CCE1_COEF_MEM_RST_SHIFT) +#define EASRC_CCE1_COEF_MEM_RST BIT(EASRC_CCE1_COEF_MEM_RST_SHIFT) +#define EASRC_CCE1_PF_EXP_SHIFT 16 +#define EASRC_CCE1_PF_EXP_WIDTH 8 +#define EASRC_CCE1_PF_EXP_MASK ((BIT(EASRC_CCE1_PF_EXP_WIDTH) - 1) \ + << EASRC_CCE1_PF_EXP_SHIFT) +#define EASRC_CCE1_PF_EXP(v) (((v) << EASRC_CCE1_PF_EXP_SHIFT) \ + & EASRC_CCE1_PF_EXP_MASK) +#define EASRC_CCE1_PF_ST1_WBFP_SHIFT 9 +#define EASRC_CCE1_PF_ST1_WBFP_MASK BIT(EASRC_CCE1_PF_ST1_WBFP_SHIFT) +#define EASRC_CCE1_PF_ST1_WBFP BIT(EASRC_CCE1_PF_ST1_WBFP_SHIFT) +#define EASRC_CCE1_PF_TSEN_SHIFT 8 +#define EASRC_CCE1_PF_TSEN_MASK BIT(EASRC_CCE1_PF_TSEN_SHIFT) +#define EASRC_CCE1_PF_TSEN BIT(EASRC_CCE1_PF_TSEN_SHIFT) +#define EASRC_CCE1_RS_BYPASS_SHIFT 7 +#define EASRC_CCE1_RS_BYPASS_MASK BIT(EASRC_CCE1_RS_BYPASS_SHIFT) +#define EASRC_CCE1_RS_BYPASS BIT(EASRC_CCE1_RS_BYPASS_SHIFT) +#define EASRC_CCE1_PF_BYPASS_SHIFT 6 +#define EASRC_CCE1_PF_BYPASS_MASK BIT(EASRC_CCE1_PF_BYPASS_SHIFT) +#define EASRC_CCE1_PF_BYPASS BIT(EASRC_CCE1_PF_BYPASS_SHIFT) +#define EASRC_CCE1_RS_STOP_SHIFT 5 +#define EASRC_CCE1_RS_STOP_MASK BIT(EASRC_CCE1_RS_STOP_SHIFT) +#define EASRC_CCE1_RS_STOP BIT(EASRC_CCE1_RS_STOP_SHIFT) +#define EASRC_CCE1_PF_STOP_SHIFT 4 +#define EASRC_CCE1_PF_STOP_MASK BIT(EASRC_CCE1_PF_STOP_SHIFT) +#define EASRC_CCE1_PF_STOP BIT(EASRC_CCE1_PF_STOP_SHIFT) +#define EASRC_CCE1_RS_INIT_SHIFT 2 +#define EASRC_CCE1_RS_INIT_WIDTH 2 +#define EASRC_CCE1_RS_INIT_MASK ((BIT(EASRC_CCE1_RS_INIT_WIDTH) - 1) \ + << EASRC_CCE1_RS_INIT_SHIFT) +#define EASRC_CCE1_RS_INIT(v) (((v) << EASRC_CCE1_RS_INIT_SHIFT) \ + & EASRC_CCE1_RS_INIT_MASK) +#define EASRC_CCE1_PF_INIT_SHIFT 0 +#define EASRC_CCE1_PF_INIT_WIDTH 2 +#define EASRC_CCE1_PF_INIT_MASK ((BIT(EASRC_CCE1_PF_INIT_WIDTH) - 1) \ + << EASRC_CCE1_PF_INIT_SHIFT) +#define EASRC_CCE1_PF_INIT(v) (((v) << EASRC_CCE1_PF_INIT_SHIFT) \ + & EASRC_CCE1_PF_INIT_MASK) + +/* ASRC Context Control Extended 2 (CCE2) */ +#define EASRC_CCE2_ST2_TAPS_SHIFT 16 +#define EASRC_CCE2_ST2_TAPS_WIDTH 9 +#define EASRC_CCE2_ST2_TAPS_MASK ((BIT(EASRC_CCE2_ST2_TAPS_WIDTH) - 1) \ + << EASRC_CCE2_ST2_TAPS_SHIFT) +#define EASRC_CCE2_ST2_TAPS(v) (((v) << EASRC_CCE2_ST2_TAPS_SHIFT) \ + & EASRC_CCE2_ST2_TAPS_MASK) +#define EASRC_CCE2_ST1_TAPS_SHIFT 0 +#define EASRC_CCE2_ST1_TAPS_WIDTH 9 +#define EASRC_CCE2_ST1_TAPS_MASK ((BIT(EASRC_CCE2_ST1_TAPS_WIDTH) - 1) \ + << EASRC_CCE2_ST1_TAPS_SHIFT) +#define EASRC_CCE2_ST1_TAPS(v) (((v) << EASRC_CCE2_ST1_TAPS_SHIFT) \ + & EASRC_CCE2_ST1_TAPS_MASK) + +/* ASRC Control Input Access (CIA) */ +#define EASRC_CIA_ITER_SHIFT 16 +#define EASRC_CIA_ITER_WIDTH 6 +#define EASRC_CIA_ITER_MASK ((BIT(EASRC_CIA_ITER_WIDTH) - 1) \ + << EASRC_CIA_ITER_SHIFT) +#define EASRC_CIA_ITER(v) (((v) << EASRC_CIA_ITER_SHIFT) \ + & EASRC_CIA_ITER_MASK) +#define EASRC_CIA_GRLEN_SHIFT 8 +#define EASRC_CIA_GRLEN_WIDTH 6 +#define EASRC_CIA_GRLEN_MASK ((BIT(EASRC_CIA_GRLEN_WIDTH) - 1) \ + << EASRC_CIA_GRLEN_SHIFT) +#define EASRC_CIA_GRLEN(v) (((v) << EASRC_CIA_GRLEN_SHIFT) \ + & EASRC_CIA_GRLEN_MASK) +#define EASRC_CIA_ACCLEN_SHIFT 0 +#define EASRC_CIA_ACCLEN_WIDTH 6 +#define EASRC_CIA_ACCLEN_MASK ((BIT(EASRC_CIA_ACCLEN_WIDTH) - 1) \ + << EASRC_CIA_ACCLEN_SHIFT) +#define EASRC_CIA_ACCLEN(v) (((v) << EASRC_CIA_ACCLEN_SHIFT) \ + & EASRC_CIA_ACCLEN_MASK) + +/* ASRC Datapath Processor Control Slot0 Register0 (DPCS0R0) */ +#define EASRC_DPCS0R0_MAXCH_SHIFT 24 +#define EASRC_DPCS0R0_MAXCH_WIDTH 5 +#define EASRC_DPCS0R0_MAXCH_MASK ((BIT(EASRC_DPCS0R0_MAXCH_WIDTH) - 1) \ + << EASRC_DPCS0R0_MAXCH_SHIFT) +#define EASRC_DPCS0R0_MAXCH(v) (((v) << EASRC_DPCS0R0_MAXCH_SHIFT) \ + & EASRC_DPCS0R0_MAXCH_MASK) +#define EASRC_DPCS0R0_MINCH_SHIFT 16 +#define EASRC_DPCS0R0_MINCH_WIDTH 5 +#define EASRC_DPCS0R0_MINCH_MASK ((BIT(EASRC_DPCS0R0_MINCH_WIDTH) - 1) \ + << EASRC_DPCS0R0_MINCH_SHIFT) +#define EASRC_DPCS0R0_MINCH(v) (((v) << EASRC_DPCS0R0_MINCH_SHIFT) \ + & EASRC_DPCS0R0_MINCH_MASK) +#define EASRC_DPCS0R0_NUMCH_SHIFT 8 +#define EASRC_DPCS0R0_NUMCH_WIDTH 5 +#define EASRC_DPCS0R0_NUMCH_MASK ((BIT(EASRC_DPCS0R0_NUMCH_WIDTH) - 1) \ + << EASRC_DPCS0R0_NUMCH_SHIFT) +#define EASRC_DPCS0R0_NUMCH(v) (((v) << EASRC_DPCS0R0_NUMCH_SHIFT) \ + & EASRC_DPCS0R0_NUMCH_MASK) +#define EASRC_DPCS0R0_CTXNUM_SHIFT 1 +#define EASRC_DPCS0R0_CTXNUM_WIDTH 2 +#define EASRC_DPCS0R0_CTXNUM_MASK ((BIT(EASRC_DPCS0R0_CTXNUM_WIDTH) - 1) \ + << EASRC_DPCS0R0_CTXNUM_SHIFT) +#define EASRC_DPCS0R0_CTXNUM(v) (((v) << EASRC_DPCS0R0_CTXNUM_SHIFT) \ + & EASRC_DPCS0R0_CTXNUM_MASK) +#define EASRC_DPCS0R0_EN_SHIFT 0 +#define EASRC_DPCS0R0_EN_MASK BIT(EASRC_DPCS0R0_EN_SHIFT) +#define EASRC_DPCS0R0_EN BIT(EASRC_DPCS0R0_EN_SHIFT) + +/* ASRC Datapath Processor Control Slot0 Register1 (DPCS0R1) */ +#define EASRC_DPCS0R1_ST1_EXP_SHIFT 0 +#define EASRC_DPCS0R1_ST1_EXP_WIDTH 13 +#define EASRC_DPCS0R1_ST1_EXP_MASK ((BIT(EASRC_DPCS0R1_ST1_EXP_WIDTH) - 1) \ + << EASRC_DPCS0R1_ST1_EXP_SHIFT) +#define EASRC_DPCS0R1_ST1_EXP(v) (((v) << EASRC_DPCS0R1_ST1_EXP_SHIFT) \ + & EASRC_DPCS0R1_ST1_EXP_MASK) + +/* ASRC Datapath Processor Control Slot0 Register2 (DPCS0R2) */ +#define EASRC_DPCS0R2_ST1_MA_SHIFT 16 +#define EASRC_DPCS0R2_ST1_MA_WIDTH 13 +#define EASRC_DPCS0R2_ST1_MA_MASK ((BIT(EASRC_DPCS0R2_ST1_MA_WIDTH) - 1) \ + << EASRC_DPCS0R2_ST1_MA_SHIFT) +#define EASRC_DPCS0R2_ST1_MA(v) (((v) << EASRC_DPCS0R2_ST1_MA_SHIFT) \ + & EASRC_DPCS0R2_ST1_MA_MASK) +#define EASRC_DPCS0R2_ST1_SA_SHIFT 0 +#define EASRC_DPCS0R2_ST1_SA_WIDTH 13 +#define EASRC_DPCS0R2_ST1_SA_MASK ((BIT(EASRC_DPCS0R2_ST1_SA_WIDTH) - 1) \ + << EASRC_DPCS0R2_ST1_SA_SHIFT) +#define EASRC_DPCS0R2_ST1_SA(v) (((v) << EASRC_DPCS0R2_ST1_SA_SHIFT) \ + & EASRC_DPCS0R2_ST1_SA_MASK) + +/* ASRC Datapath Processor Control Slot0 Register3 (DPCS0R3) */ +#define EASRC_DPCS0R3_ST2_MA_SHIFT 16 +#define EASRC_DPCS0R3_ST2_MA_WIDTH 13 +#define EASRC_DPCS0R3_ST2_MA_MASK ((BIT(EASRC_DPCS0R3_ST2_MA_WIDTH) - 1) \ + << EASRC_DPCS0R3_ST2_MA_SHIFT) +#define EASRC_DPCS0R3_ST2_MA(v) (((v) << EASRC_DPCS0R3_ST2_MA_SHIFT) \ + & EASRC_DPCS0R3_ST2_MA_MASK) +#define EASRC_DPCS0R3_ST2_SA_SHIFT 0 +#define EASRC_DPCS0R3_ST2_SA_WIDTH 13 +#define EASRC_DPCS0R3_ST2_SA_MASK ((BIT(EASRC_DPCS0R3_ST2_SA_WIDTH) - 1) \ + << EASRC_DPCS0R3_ST2_SA_SHIFT) +#define EASRC_DPCS0R3_ST2_SA(v) (((v) << EASRC_DPCS0R3_ST2_SA_SHIFT) \ + & EASRC_DPCS0R3_ST2_SA_MASK) + +/* ASRC Context Output Control (COC) */ +#define EASRC_COC_FWMDE_SHIFT 28 +#define EASRC_COC_FWMDE_MASK BIT(EASRC_COC_FWMDE_SHIFT) +#define EASRC_COC_FWMDE BIT(EASRC_COC_FWMDE_SHIFT) +#define EASRC_COC_FIFO_WTMK_SHIFT 16 +#define EASRC_COC_FIFO_WTMK_WIDTH 7 +#define EASRC_COC_FIFO_WTMK_MASK ((BIT(EASRC_COC_FIFO_WTMK_WIDTH) - 1) \ + << EASRC_COC_FIFO_WTMK_SHIFT) +#define EASRC_COC_FIFO_WTMK(v) (((v) << EASRC_COC_FIFO_WTMK_SHIFT) \ + & EASRC_COC_FIFO_WTMK_MASK) +#define EASRC_COC_SAMPLE_POS_SHIFT 11 +#define EASRC_COC_SAMPLE_POS_WIDTH 5 +#define EASRC_COC_SAMPLE_POS_MASK ((BIT(EASRC_COC_SAMPLE_POS_WIDTH) - 1) \ + << EASRC_COC_SAMPLE_POS_SHIFT) +#define EASRC_COC_SAMPLE_POS(v) (((v) << EASRC_COC_SAMPLE_POS_SHIFT) \ + & EASRC_COC_SAMPLE_POS_MASK) +#define EASRC_COC_ENDIANNESS_SHIFT 10 +#define EASRC_COC_ENDIANNESS_MASK BIT(EASRC_COC_ENDIANNESS_SHIFT) +#define EASRC_COC_ENDIANNESS BIT(EASRC_COC_ENDIANNESS_SHIFT) +#define EASRC_COC_BPS_SHIFT 8 +#define EASRC_COC_BPS_WIDTH 2 +#define EASRC_COC_BPS_MASK ((BIT(EASRC_COC_BPS_WIDTH) - 1) \ + << EASRC_COC_BPS_SHIFT) +#define EASRC_COC_BPS(v) (((v) << EASRC_COC_BPS_SHIFT) \ + & EASRC_COC_BPS_MASK) +#define EASRC_COC_FMT_SHIFT 7 +#define EASRC_COC_FMT_MASK BIT(EASRC_COC_FMT_SHIFT) +#define EASRC_COC_FMT BIT(EASRC_COC_FMT_SHIFT) +#define EASRC_COC_OUTSIGN_SHIFT 6 +#define EASRC_COC_OUTSIGN_MASK BIT(EASRC_COC_OUTSIGN_SHIFT) +#define EASRC_COC_OUTSIGN_OUT BIT(EASRC_COC_OUTSIGN_SHIFT) +#define EASRC_COC_IEC_VDATA_SHIFT 2 +#define EASRC_COC_IEC_VDATA_MASK BIT(EASRC_COC_IEC_VDATA_SHIFT) +#define EASRC_COC_IEC_VDATA BIT(EASRC_COC_IEC_VDATA_SHIFT) +#define EASRC_COC_IEC_EN_SHIFT 1 +#define EASRC_COC_IEC_EN_MASK BIT(EASRC_COC_IEC_EN_SHIFT) +#define EASRC_COC_IEC_EN BIT(EASRC_COC_IEC_EN_SHIFT) +#define EASRC_COC_DITHER_EN_SHIFT 0 +#define EASRC_COC_DITHER_EN_MASK BIT(EASRC_COC_DITHER_EN_SHIFT) +#define EASRC_COC_DITHER_EN BIT(EASRC_COC_DITHER_EN_SHIFT) + +/* ASRC Control Output Access (COA) */ +#define EASRC_COA_ITER_SHIFT 16 +#define EASRC_COA_ITER_WIDTH 6 +#define EASRC_COA_ITER_MASK ((BIT(EASRC_COA_ITER_WIDTH) - 1) \ + << EASRC_COA_ITER_SHIFT) +#define EASRC_COA_ITER(v) (((v) << EASRC_COA_ITER_SHIFT) \ + & EASRC_COA_ITER_MASK) +#define EASRC_COA_GRLEN_SHIFT 8 +#define EASRC_COA_GRLEN_WIDTH 6 +#define EASRC_COA_GRLEN_MASK ((BIT(EASRC_COA_GRLEN_WIDTH) - 1) \ + << EASRC_COA_GRLEN_SHIFT) +#define EASRC_COA_GRLEN(v) (((v) << EASRC_COA_GRLEN_SHIFT) \ + & EASRC_COA_GRLEN_MASK) +#define EASRC_COA_ACCLEN_SHIFT 0 +#define EASRC_COA_ACCLEN_WIDTH 6 +#define EASRC_COA_ACCLEN_MASK ((BIT(EASRC_COA_ACCLEN_WIDTH) - 1) \ + << EASRC_COA_ACCLEN_SHIFT) +#define EASRC_COA_ACCLEN(v) (((v) << EASRC_COA_ACCLEN_SHIFT) \ + & EASRC_COA_ACCLEN_MASK) + +/* ASRC Sample FIFO Status (SFS) */ +#define EASRC_SFS_IWTMK_SHIFT 23 +#define EASRC_SFS_IWTMK_MASK BIT(EASRC_SFS_IWTMK_SHIFT) +#define EASRC_SFS_IWTMK BIT(EASRC_SFS_IWTMK_SHIFT) +#define EASRC_SFS_NSGI_SHIFT 16 +#define EASRC_SFS_NSGI_WIDTH 7 +#define EASRC_SFS_NSGI_MASK ((BIT(EASRC_SFS_NSGI_WIDTH) - 1) \ + << EASRC_SFS_NSGI_SHIFT) +#define EASRC_SFS_NSGI(v) (((v) << EASRC_SFS_NSGI_SHIFT) \ + & EASRC_SFS_NSGI_MASK) +#define EASRC_SFS_OWTMK_SHIFT 7 +#define EASRC_SFS_OWTMK_MASK BIT(EASRC_SFS_OWTMK_SHIFT) +#define EASRC_SFS_OWTMK BIT(EASRC_SFS_OWTMK_SHIFT) +#define EASRC_SFS_NSGO_SHIFT 0 +#define EASRC_SFS_NSGO_WIDTH 7 +#define EASRC_SFS_NSGO_MASK ((BIT(EASRC_SFS_NSGO_WIDTH) - 1) \ + << EASRC_SFS_NSGO_SHIFT) +#define EASRC_SFS_NSGO(v) (((v) << EASRC_SFS_NSGO_SHIFT) \ + & EASRC_SFS_NSGO_MASK) + +/* ASRC Resampling Ratio Low (RRL) */ +#define EASRC_RRL_RS_RL_SHIFT 0 +#define EASRC_RRL_RS_RL_WIDTH 32 +#define EASRC_RRL_RS_RL(v) ((v) << EASRC_RRL_RS_RL_SHIFT) + +/* ASRC Resampling Ratio High (RRH) */ +#define EASRC_RRH_RS_VLD_SHIFT 31 +#define EASRC_RRH_RS_VLD_MASK BIT(EASRC_RRH_RS_VLD_SHIFT) +#define EASRC_RRH_RS_VLD BIT(EASRC_RRH_RS_VLD_SHIFT) +#define EASRC_RRH_RS_RH_SHIFT 0 +#define EASRC_RRH_RS_RH_WIDTH 12 +#define EASRC_RRH_RS_RH_MASK ((BIT(EASRC_RRH_RS_RH_WIDTH) - 1) \ + << EASRC_RRH_RS_RH_SHIFT) +#define EASRC_RRH_RS_RH(v) (((v) << EASRC_RRH_RS_RH_SHIFT) \ + & EASRC_RRH_RS_RH_MASK) + +/* ASRC Resampling Ratio Update Control (RSUC) */ +#define EASRC_RSUC_RS_RM_SHIFT 0 +#define EASRC_RSUC_RS_RM_WIDTH 32 +#define EASRC_RSUC_RS_RM(v) ((v) << EASRC_RSUC_RS_RM_SHIFT) + +/* ASRC Resampling Ratio Update Rate (RRUR) */ +#define EASRC_RRUR_RRR_SHIFT 0 +#define EASRC_RRUR_RRR_WIDTH 31 +#define EASRC_RRUR_RRR_MASK ((BIT(EASRC_RRUR_RRR_WIDTH) - 1) \ + << EASRC_RRUR_RRR_SHIFT) +#define EASRC_RRUR_RRR(v) (((v) << EASRC_RRUR_RRR_SHIFT) \ + & EASRC_RRUR_RRR_MASK) + +/* ASRC Resampling Center Tap Coefficient Low (RCTCL) */ +#define EASRC_RCTCL_RS_CL_SHIFT 0 +#define EASRC_RCTCL_RS_CL_WIDTH 32 +#define EASRC_RCTCL_RS_CL(v) ((v) << EASRC_RCTCL_RS_CL_SHIFT) + +/* ASRC Resampling Center Tap Coefficient High (RCTCH) */ +#define EASRC_RCTCH_RS_CH_SHIFT 0 +#define EASRC_RCTCH_RS_CH_WIDTH 32 +#define EASRC_RCTCH_RS_CH(v) ((v) << EASRC_RCTCH_RS_CH_SHIFT) + +/* ASRC Prefilter Coefficient FIFO (PCF) */ +#define EASRC_PCF_CD_SHIFT 0 +#define EASRC_PCF_CD_WIDTH 32 +#define EASRC_PCF_CD(v) ((v) << EASRC_PCF_CD_SHIFT) + +/* ASRC Context Resampling Coefficient Memory (CRCM) */ +#define EASRC_CRCM_RS_CWD_SHIFT 0 +#define EASRC_CRCM_RS_CWD_WIDTH 32 +#define EASRC_CRCM_RS_CWD(v) ((v) << EASRC_CRCM_RS_CWD_SHIFT) + +/* ASRC Context Resampling Coefficient Control (CRCC) */ +#define EASRC_CRCC_RS_CA_SHIFT 16 +#define EASRC_CRCC_RS_CA_WIDTH 11 +#define EASRC_CRCC_RS_CA_MASK ((BIT(EASRC_CRCC_RS_CA_WIDTH) - 1) \ + << EASRC_CRCC_RS_CA_SHIFT) +#define EASRC_CRCC_RS_CA(v) (((v) << EASRC_CRCC_RS_CA_SHIFT) \ + & EASRC_CRCC_RS_CA_MASK) +#define EASRC_CRCC_RS_TAPS_SHIFT 1 +#define EASRC_CRCC_RS_TAPS_WIDTH 2 +#define EASRC_CRCC_RS_TAPS_MASK ((BIT(EASRC_CRCC_RS_TAPS_WIDTH) - 1) \ + << EASRC_CRCC_RS_TAPS_SHIFT) +#define EASRC_CRCC_RS_TAPS(v) (((v) << EASRC_CRCC_RS_TAPS_SHIFT) \ + & EASRC_CRCC_RS_TAPS_MASK) +#define EASRC_CRCC_RS_CPR_SHIFT 0 +#define EASRC_CRCC_RS_CPR_MASK BIT(EASRC_CRCC_RS_CPR_SHIFT) +#define EASRC_CRCC_RS_CPR BIT(EASRC_CRCC_RS_CPR_SHIFT) + +/* ASRC Interrupt_Control (IC) */ +#define EASRC_IRQC_RSDM_SHIFT 8 +#define EASRC_IRQC_RSDM_WIDTH 4 +#define EASRC_IRQC_RSDM_MASK ((BIT(EASRC_IRQC_RSDM_WIDTH) - 1) \ + << EASRC_IRQC_RSDM_SHIFT) +#define EASRC_IRQC_RSDM(v) (((v) << EASRC_IRQC_RSDM_SHIFT) \ + & EASRC_IRQC_RSDM_MASK) +#define EASRC_IRQC_OERM_SHIFT 4 +#define EASRC_IRQC_OERM_WIDTH 4 +#define EASRC_IRQC_OERM_MASK ((BIT(EASRC_IRQC_OERM_WIDTH) - 1) \ + << EASRC_IRQC_OERM_SHIFT) +#define EASRC_IRQC_OERM(v) (((v) << EASRC_IRQC_OERM_SHIFT) \ + & EASRC_IEQC_OERM_MASK) +#define EASRC_IRQC_IOM_SHIFT 0 +#define EASRC_IRQC_IOM_WIDTH 4 +#define EASRC_IRQC_IOM_MASK ((BIT(EASRC_IRQC_IOM_WIDTH) - 1) \ + << EASRC_IRQC_IOM_SHIFT) +#define EASRC_IRQC_IOM(v) (((v) << EASRC_IRQC_IOM_SHIFT) \ + & EASRC_IRQC_IOM_MASK) + +/* ASRC Interrupt Status Flags (ISF) */ +#define EASRC_IRQF_RSD_SHIFT 8 +#define EASRC_IRQF_RSD_WIDTH 4 +#define EASRC_IRQF_RSD_MASK ((BIT(EASRC_IRQF_RSD_WIDTH) - 1) \ + << EASRC_IRQF_RSD_SHIFT) +#define EASRC_IRQF_RSD(v) (((v) << EASRC_IRQF_RSD_SHIFT) \ + & EASRC_IRQF_RSD_MASK) +#define EASRC_IRQF_OER_SHIFT 4 +#define EASRC_IRQF_OER_WIDTH 4 +#define EASRC_IRQF_OER_MASK ((BIT(EASRC_IRQF_OER_WIDTH) - 1) \ + << EASRC_IRQF_OER_SHIFT) +#define EASRC_IRQF_OER(v) (((v) << EASRC_IRQF_OER_SHIFT) \ + & EASRC_IRQF_OER_MASK) +#define EASRC_IRQF_IFO_SHIFT 0 +#define EASRC_IRQF_IFO_WIDTH 4 +#define EASRC_IRQF_IFO_MASK ((BIT(EASRC_IRQF_IFO_WIDTH) - 1) \ + << EASRC_IRQF_IFO_SHIFT) +#define EASRC_IRQF_IFO(v) (((v) << EASRC_IRQF_IFO_SHIFT) \ + & EASRC_IRQF_IFO_MASK) + +/* ASRC Context Channel STAT */ +#define EASRC_CSx_CSx_SHIFT 0 +#define EASRC_CSx_CSx_WIDTH 32 +#define EASRC_CSx_CSx(v) ((v) << EASRC_CSx_CSx_SHIFT) + +/* ASRC Debug Control Register */ +#define EASRC_DBGC_DMS_SHIFT 0 +#define EASRC_DBGC_DMS_WIDTH 6 +#define EASRC_DBGC_DMS_MASK ((BIT(EASRC_DBGC_DMS_WIDTH) - 1) \ + << EASRC_DBGC_DMS_SHIFT) +#define EASRC_DBGC_DMS(v) (((v) << EASRC_DBGC_DMS_SHIFT) \ + & EASRC_DBGC_DMS_MASK) + +/* ASRC Debug Status Register */ +#define EASRC_DBGS_DS_SHIFT 0 +#define EASRC_DBGS_DS_WIDTH 32 +#define EASRC_DBGS_DS(v) ((v) << EASRC_DBGS_DS_SHIFT) + +/* General Constants */ +#define EASRC_CTX_MAX_NUM 4 +#define EASRC_RS_COEFF_MEM 0 +#define EASRC_PF_COEFF_MEM 1 + +/* Prefilter constants */ +#define EASRC_PF_ST1_ONLY 0 +#define EASRC_PF_TWO_STAGE_MODE 1 +#define EASRC_PF_ST1_COEFF_WR 0 +#define EASRC_PF_ST2_COEFF_WR 1 +#define EASRC_MAX_PF_TAPS 384 + +/* Resampling constants */ +#define EASRC_RS_32_TAPS 0 +#define EASRC_RS_64_TAPS 1 +#define EASRC_RS_128_TAPS 2 + +/* Initialization mode */ +#define EASRC_INIT_MODE_SW_CONTROL 0 +#define EASRC_INIT_MODE_REPLICATE 1 +#define EASRC_INIT_MODE_ZERO_FILL 2 + +/* FIFO watermarks */ +#define FSL_EASRC_INPUTFIFO_WML 0x4 +#define FSL_EASRC_OUTPUTFIFO_WML 0x1 + +#define EASRC_INPUTFIFO_THRESHOLD_MIN 0 +#define EASRC_INPUTFIFO_THRESHOLD_MAX 127 +#define EASRC_OUTPUTFIFO_THRESHOLD_MIN 0 +#define EASRC_OUTPUTFIFO_THRESHOLD_MAX 63 + +#define EASRC_DMA_BUFFER_SIZE (1024 * 48 * 9) +#define EASRC_MAX_BUFFER_SIZE (1024 * 48) + +#define FIRMWARE_MAGIC 0xDEAD +#define FIRMWARE_VERSION 1 + +#define PREFILTER_MEM_LEN 0x1800 + +enum easrc_word_width { + EASRC_WIDTH_16_BIT = 0, + EASRC_WIDTH_20_BIT = 1, + EASRC_WIDTH_24_BIT = 2, + EASRC_WIDTH_32_BIT = 3, +}; + +struct __attribute__((__packed__)) asrc_firmware_hdr { + u32 magic; + u32 interp_scen; + u32 prefil_scen; + u32 firmware_version; +}; + +struct __attribute__((__packed__)) interp_params { + u32 magic; + u32 num_taps; + u32 num_phases; + u64 center_tap; + u64 coeff[8192]; +}; + +struct __attribute__((__packed__)) prefil_params { + u32 magic; + u32 insr; + u32 outsr; + u32 st1_taps; + u32 st2_taps; + u32 st1_exp; + u64 coeff[256]; +}; + +struct dma_block { + void *dma_vaddr; + unsigned int length; + unsigned int max_buf_size; +}; + +struct fsl_easrc_data_fmt { + unsigned int width : 2; + unsigned int endianness : 1; + unsigned int unsign : 1; + unsigned int floating_point : 1; + unsigned int iec958: 1; + unsigned int sample_pos: 5; + unsigned int addexp; +}; + +struct fsl_easrc_io_params { + struct fsl_easrc_data_fmt fmt; + unsigned int group_len; + unsigned int iterations; + unsigned int access_len; + unsigned int fifo_wtmk; + unsigned int sample_rate; + unsigned int sample_format; + unsigned int norm_rate; +}; + +struct fsl_easrc_slot { + bool busy; + int ctx_index; + int slot_index; + int num_channel; /* maximum is 8 */ + int min_channel; + int max_channel; + int pf_mem_used; +}; + +/** + * fsl_easrc_ctx_priv: EASRC context private data + * + * @in_params: input parameter + * @out_params: output parameter + * @st1_num_taps: tap number of stage 1 + * @st2_num_taps: tap number of stage 2 + * @st1_num_exp: exponent number of stage 1 + * @pf_init_mode: prefilter init mode + * @rs_init_mode: resample filter init mode + * @ctx_streams: stream flag of ctx + * @rs_ratio: resampler ratio + * @st1_coeff: pointer of stage 1 coeff + * @st2_coeff: pointer of stage 2 coeff + * @in_filled_sample: input filled sample + * @out_missed_sample: sample missed in output + * @st1_addexp: exponent added for stage1 + * @st2_addexp: exponent added for stage2 + */ +struct fsl_easrc_ctx_priv { + struct fsl_easrc_io_params in_params; + struct fsl_easrc_io_params out_params; + unsigned int st1_num_taps; + unsigned int st2_num_taps; + unsigned int st1_num_exp; + unsigned int pf_init_mode; + unsigned int rs_init_mode; + unsigned int ctx_streams; + u64 rs_ratio; + u64 *st1_coeff; + u64 *st2_coeff; + int in_filled_sample; + int out_missed_sample; + int st1_addexp; + int st2_addexp; +}; + +/** + * fsl_easrc_priv: EASRC private data + * + * @slot: slot setting + * @firmware_hdr: the header of firmware + * @interp: pointer to interpolation filter coeff + * @prefil: pointer to prefilter coeff + * @fw: firmware of coeff table + * @fw_name: firmware name + * @rs_num_taps: resample filter taps, 32, 64, or 128 + * @bps_iec958: bits per sample of iec958 + * @rs_coeff: resampler coefficient + * @const_coeff: one tap prefilter coefficient + * @firmware_loaded: firmware is loaded + */ +struct fsl_easrc_priv { + struct fsl_easrc_slot slot[EASRC_CTX_MAX_NUM][2]; + struct asrc_firmware_hdr *firmware_hdr; + struct interp_params *interp; + struct prefil_params *prefil; + const struct firmware *fw; + const char *fw_name; + unsigned int rs_num_taps; + unsigned int bps_iec958[EASRC_CTX_MAX_NUM]; + u64 *rs_coeff; + u64 const_coeff; + int firmware_loaded; +}; +#endif /* _FSL_EASRC_H */
On Wed, Apr 01, 2020 at 04:45:40PM +0800, Shengjiu Wang wrote:
EASRC (Enhanced Asynchronous Sample Rate Converter) is a new IP module found on i.MX8MN. It is different with old ASRC module.
The primary features for the EASRC are as follows:
- 4 Contexts - groups of channels with an independent time base
- Fully independent and concurrent context control
- Simultaneous processing of up to 32 audio channels
- Programmable filter charachteristics for each context
- 32, 24, 20, and 16-bit fixed point audio sample support
- 32-bit floating point audio sample support
- 8kHz to 384kHz sample rate
- 1/16 to 8x sample rate conversion ratio
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com Signed-off-by: Cosmin-Gabriel Samoila cosmin.samoila@nxp.com
Overall, looks good to me.
Please add: Acked-by: Nicolin Chen nicoleotsuka@gmail.com
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +static int fsl_easrc_normalize_filter(struct fsl_asrc *easrc,
* If exponent is zero (value == 0), or 7ff (value == NaNs)
[...]
- if (exp == 0 || exp == 0x7ff) {
[...]
- if ((shift > 0 && exp >= 2047) ||
(shift < 0 && exp <= 0)) {
Could fit into one line, and would be probably nicer to re-use "0x7ff" matching previous places, instead of "2047".
participants (4)
-
Nicolin Chen
-
Rob Herring
-
Shengjiu Wang
-
Shengjiu Wang