162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright 2019 NXP 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/atomic.h> 562306a36Sopenharmony_ci#include <linux/clk.h> 662306a36Sopenharmony_ci#include <linux/device.h> 762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 862306a36Sopenharmony_ci#include <linux/firmware.h> 962306a36Sopenharmony_ci#include <linux/interrupt.h> 1062306a36Sopenharmony_ci#include <linux/kobject.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/miscdevice.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/of_address.h> 1662306a36Sopenharmony_ci#include <linux/of_irq.h> 1762306a36Sopenharmony_ci#include <linux/of_platform.h> 1862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1962306a36Sopenharmony_ci#include <linux/regmap.h> 2062306a36Sopenharmony_ci#include <linux/sched/signal.h> 2162306a36Sopenharmony_ci#include <linux/sysfs.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/gcd.h> 2462306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h> 2562306a36Sopenharmony_ci#include <sound/pcm.h> 2662306a36Sopenharmony_ci#include <sound/pcm_params.h> 2762306a36Sopenharmony_ci#include <sound/soc.h> 2862306a36Sopenharmony_ci#include <sound/tlv.h> 2962306a36Sopenharmony_ci#include <sound/core.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "fsl_easrc.h" 3262306a36Sopenharmony_ci#include "imx-pcm.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define FSL_EASRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 3562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE | \ 3662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 3762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | \ 3862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_LE | \ 3962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_3LE | \ 4062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | \ 4162306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_LE | \ 4262306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | \ 4362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U20_3LE | \ 4462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_FLOAT_LE) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, 4762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 5062306a36Sopenharmony_ci struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp); 5162306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 5262306a36Sopenharmony_ci struct soc_mreg_control *mc = 5362306a36Sopenharmony_ci (struct soc_mreg_control *)kcontrol->private_value; 5462306a36Sopenharmony_ci unsigned int regval = ucontrol->value.integer.value[0]; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci easrc_priv->bps_iec958[mc->regbase] = regval; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, 6262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 6562306a36Sopenharmony_ci struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp); 6662306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 6762306a36Sopenharmony_ci struct soc_mreg_control *mc = 6862306a36Sopenharmony_ci (struct soc_mreg_control *)kcontrol->private_value; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, 7662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 7962306a36Sopenharmony_ci struct soc_mreg_control *mc = 8062306a36Sopenharmony_ci (struct soc_mreg_control *)kcontrol->private_value; 8162306a36Sopenharmony_ci unsigned int regval; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci regval = snd_soc_component_read(component, mc->regbase); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = regval; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, 9162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 9462306a36Sopenharmony_ci struct soc_mreg_control *mc = 9562306a36Sopenharmony_ci (struct soc_mreg_control *)kcontrol->private_value; 9662306a36Sopenharmony_ci unsigned int regval = ucontrol->value.integer.value[0]; 9762306a36Sopenharmony_ci int ret; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci ret = snd_soc_component_write(component, mc->regbase, regval); 10062306a36Sopenharmony_ci if (ret < 0) 10162306a36Sopenharmony_ci return ret; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define SOC_SINGLE_REG_RW(xname, xreg) \ 10762306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ 10862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 10962306a36Sopenharmony_ci .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ 11062306a36Sopenharmony_ci .put = fsl_easrc_set_reg, \ 11162306a36Sopenharmony_ci .private_value = (unsigned long)&(struct soc_mreg_control) \ 11262306a36Sopenharmony_ci { .regbase = xreg, .regcount = 1, .nbits = 32, \ 11362306a36Sopenharmony_ci .invert = 0, .min = 0, .max = 0xffffffff, } } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define SOC_SINGLE_VAL_RW(xname, xreg) \ 11662306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ 11762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 11862306a36Sopenharmony_ci .info = snd_soc_info_xr_sx, .get = fsl_easrc_iec958_get_bits, \ 11962306a36Sopenharmony_ci .put = fsl_easrc_iec958_put_bits, \ 12062306a36Sopenharmony_ci .private_value = (unsigned long)&(struct soc_mreg_control) \ 12162306a36Sopenharmony_ci { .regbase = xreg, .regcount = 1, .nbits = 32, \ 12262306a36Sopenharmony_ci .invert = 0, .min = 0, .max = 2, } } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { 12562306a36Sopenharmony_ci SOC_SINGLE("Context 0 Dither Switch", REG_EASRC_COC(0), 0, 1, 0), 12662306a36Sopenharmony_ci SOC_SINGLE("Context 1 Dither Switch", REG_EASRC_COC(1), 0, 1, 0), 12762306a36Sopenharmony_ci SOC_SINGLE("Context 2 Dither Switch", REG_EASRC_COC(2), 0, 1, 0), 12862306a36Sopenharmony_ci SOC_SINGLE("Context 3 Dither Switch", REG_EASRC_COC(3), 0, 1, 0), 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci SOC_SINGLE("Context 0 IEC958 Validity", REG_EASRC_COC(0), 2, 1, 0), 13162306a36Sopenharmony_ci SOC_SINGLE("Context 1 IEC958 Validity", REG_EASRC_COC(1), 2, 1, 0), 13262306a36Sopenharmony_ci SOC_SINGLE("Context 2 IEC958 Validity", REG_EASRC_COC(2), 2, 1, 0), 13362306a36Sopenharmony_ci SOC_SINGLE("Context 3 IEC958 Validity", REG_EASRC_COC(3), 2, 1, 0), 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci SOC_SINGLE_VAL_RW("Context 0 IEC958 Bits Per Sample", 0), 13662306a36Sopenharmony_ci SOC_SINGLE_VAL_RW("Context 1 IEC958 Bits Per Sample", 1), 13762306a36Sopenharmony_ci SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), 13862306a36Sopenharmony_ci SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), 14162306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), 14262306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), 14362306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), 14462306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), 14562306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), 14662306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), 14762306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), 14862306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), 14962306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), 15062306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), 15162306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), 15262306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), 15362306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), 15462306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), 15562306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), 15662306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), 15762306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), 15862306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), 15962306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), 16062306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), 16162306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), 16262306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), 16362306a36Sopenharmony_ci SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * fsl_easrc_set_rs_ratio 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * According to the resample taps, calculate the resample ratio 17062306a36Sopenharmony_ci * ratio = in_rate / out_rate 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_cistatic int fsl_easrc_set_rs_ratio(struct fsl_asrc_pair *ctx) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 17562306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 17662306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; 17762306a36Sopenharmony_ci unsigned int in_rate = ctx_priv->in_params.norm_rate; 17862306a36Sopenharmony_ci unsigned int out_rate = ctx_priv->out_params.norm_rate; 17962306a36Sopenharmony_ci unsigned int frac_bits; 18062306a36Sopenharmony_ci u64 val; 18162306a36Sopenharmony_ci u32 *r; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci switch (easrc_priv->rs_num_taps) { 18462306a36Sopenharmony_ci case EASRC_RS_32_TAPS: 18562306a36Sopenharmony_ci /* integer bits = 5; */ 18662306a36Sopenharmony_ci frac_bits = 39; 18762306a36Sopenharmony_ci break; 18862306a36Sopenharmony_ci case EASRC_RS_64_TAPS: 18962306a36Sopenharmony_ci /* integer bits = 6; */ 19062306a36Sopenharmony_ci frac_bits = 38; 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci case EASRC_RS_128_TAPS: 19362306a36Sopenharmony_ci /* integer bits = 7; */ 19462306a36Sopenharmony_ci frac_bits = 37; 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci default: 19762306a36Sopenharmony_ci return -EINVAL; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci val = (u64)in_rate << frac_bits; 20162306a36Sopenharmony_ci do_div(val, out_rate); 20262306a36Sopenharmony_ci r = (uint32_t *)&val; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (r[1] & 0xFFFFF000) { 20562306a36Sopenharmony_ci dev_err(&easrc->pdev->dev, "ratio exceed range\n"); 20662306a36Sopenharmony_ci return -EINVAL; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_RRL(ctx->index), 21062306a36Sopenharmony_ci EASRC_RRL_RS_RL(r[0])); 21162306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_RRH(ctx->index), 21262306a36Sopenharmony_ci EASRC_RRH_RS_RH(r[1])); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* Normalize input and output sample rates */ 21862306a36Sopenharmony_cistatic void fsl_easrc_normalize_rates(struct fsl_asrc_pair *ctx) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv; 22162306a36Sopenharmony_ci int a, b; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (!ctx) 22462306a36Sopenharmony_ci return; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ctx_priv = ctx->private; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci a = ctx_priv->in_params.sample_rate; 22962306a36Sopenharmony_ci b = ctx_priv->out_params.sample_rate; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci a = gcd(a, b); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Divide by gcd to normalize the rate */ 23462306a36Sopenharmony_ci ctx_priv->in_params.norm_rate = ctx_priv->in_params.sample_rate / a; 23562306a36Sopenharmony_ci ctx_priv->out_params.norm_rate = ctx_priv->out_params.sample_rate / a; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* Resets the pointer of the coeff memory pointers */ 23962306a36Sopenharmony_cistatic int fsl_easrc_coeff_mem_ptr_reset(struct fsl_asrc *easrc, 24062306a36Sopenharmony_ci unsigned int ctx_id, int mem_type) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct device *dev; 24362306a36Sopenharmony_ci u32 reg, mask, val; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (!easrc) 24662306a36Sopenharmony_ci return -ENODEV; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci dev = &easrc->pdev->dev; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci switch (mem_type) { 25162306a36Sopenharmony_ci case EASRC_PF_COEFF_MEM: 25262306a36Sopenharmony_ci /* This resets the prefilter memory pointer addr */ 25362306a36Sopenharmony_ci if (ctx_id >= EASRC_CTX_MAX_NUM) { 25462306a36Sopenharmony_ci dev_err(dev, "Invalid context id[%d]\n", ctx_id); 25562306a36Sopenharmony_ci return -EINVAL; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci reg = REG_EASRC_CCE1(ctx_id); 25962306a36Sopenharmony_ci mask = EASRC_CCE1_COEF_MEM_RST_MASK; 26062306a36Sopenharmony_ci val = EASRC_CCE1_COEF_MEM_RST; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci case EASRC_RS_COEFF_MEM: 26362306a36Sopenharmony_ci /* This resets the resampling memory pointer addr */ 26462306a36Sopenharmony_ci reg = REG_EASRC_CRCC; 26562306a36Sopenharmony_ci mask = EASRC_CRCC_RS_CPR_MASK; 26662306a36Sopenharmony_ci val = EASRC_CRCC_RS_CPR; 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci default: 26962306a36Sopenharmony_ci dev_err(dev, "Unknown memory type\n"); 27062306a36Sopenharmony_ci return -EINVAL; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* 27462306a36Sopenharmony_ci * To reset the write pointer back to zero, the register field 27562306a36Sopenharmony_ci * ASRC_CTX_CTRL_EXT1x[PF_COEFF_MEM_RST] can be toggled from 27662306a36Sopenharmony_ci * 0x0 to 0x1 to 0x0. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg, mask, 0); 27962306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg, mask, val); 28062306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg, mask, 0); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return 0; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic inline uint32_t bits_taps_to_val(unsigned int t) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci switch (t) { 28862306a36Sopenharmony_ci case EASRC_RS_32_TAPS: 28962306a36Sopenharmony_ci return 32; 29062306a36Sopenharmony_ci case EASRC_RS_64_TAPS: 29162306a36Sopenharmony_ci return 64; 29262306a36Sopenharmony_ci case EASRC_RS_128_TAPS: 29362306a36Sopenharmony_ci return 128; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int fsl_easrc_resampler_config(struct fsl_asrc *easrc) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct device *dev = &easrc->pdev->dev; 30262306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 30362306a36Sopenharmony_ci struct asrc_firmware_hdr *hdr = easrc_priv->firmware_hdr; 30462306a36Sopenharmony_ci struct interp_params *interp = easrc_priv->interp; 30562306a36Sopenharmony_ci struct interp_params *selected_interp = NULL; 30662306a36Sopenharmony_ci unsigned int num_coeff; 30762306a36Sopenharmony_ci unsigned int i; 30862306a36Sopenharmony_ci u64 *coef; 30962306a36Sopenharmony_ci u32 *r; 31062306a36Sopenharmony_ci int ret; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!hdr) { 31362306a36Sopenharmony_ci dev_err(dev, "firmware not loaded!\n"); 31462306a36Sopenharmony_ci return -ENODEV; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci for (i = 0; i < hdr->interp_scen; i++) { 31862306a36Sopenharmony_ci if ((interp[i].num_taps - 1) != 31962306a36Sopenharmony_ci bits_taps_to_val(easrc_priv->rs_num_taps)) 32062306a36Sopenharmony_ci continue; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci coef = interp[i].coeff; 32362306a36Sopenharmony_ci selected_interp = &interp[i]; 32462306a36Sopenharmony_ci dev_dbg(dev, "Selected interp_filter: %u taps - %u phases\n", 32562306a36Sopenharmony_ci selected_interp->num_taps, 32662306a36Sopenharmony_ci selected_interp->num_phases); 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (!selected_interp) { 33162306a36Sopenharmony_ci dev_err(dev, "failed to get interpreter configuration\n"); 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * RS_LOW - first half of center tap of the sinc function 33762306a36Sopenharmony_ci * RS_HIGH - second half of center tap of the sinc function 33862306a36Sopenharmony_ci * This is due to the fact the resampling function must be 33962306a36Sopenharmony_ci * symetrical - i.e. odd number of taps 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci r = (uint32_t *)&selected_interp->center_tap; 34262306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_RCTCL, EASRC_RCTCL_RS_CL(r[0])); 34362306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_RCTCH, EASRC_RCTCH_RS_CH(r[1])); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* 34662306a36Sopenharmony_ci * Write Number of Resampling Coefficient Taps 34762306a36Sopenharmony_ci * 00b - 32-Tap Resampling Filter 34862306a36Sopenharmony_ci * 01b - 64-Tap Resampling Filter 34962306a36Sopenharmony_ci * 10b - 128-Tap Resampling Filter 35062306a36Sopenharmony_ci * 11b - N/A 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CRCC, 35362306a36Sopenharmony_ci EASRC_CRCC_RS_TAPS_MASK, 35462306a36Sopenharmony_ci EASRC_CRCC_RS_TAPS(easrc_priv->rs_num_taps)); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Reset prefilter coefficient pointer back to 0 */ 35762306a36Sopenharmony_ci ret = fsl_easrc_coeff_mem_ptr_reset(easrc, 0, EASRC_RS_COEFF_MEM); 35862306a36Sopenharmony_ci if (ret) 35962306a36Sopenharmony_ci return ret; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* 36262306a36Sopenharmony_ci * When the filter is programmed to run in: 36362306a36Sopenharmony_ci * 32-tap mode, 16-taps, 128-phases 4-coefficients per phase 36462306a36Sopenharmony_ci * 64-tap mode, 32-taps, 64-phases 4-coefficients per phase 36562306a36Sopenharmony_ci * 128-tap mode, 64-taps, 32-phases 4-coefficients per phase 36662306a36Sopenharmony_ci * This means the number of writes is constant no matter 36762306a36Sopenharmony_ci * the mode we are using 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci num_coeff = 16 * 128 * 4; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci for (i = 0; i < num_coeff; i++) { 37262306a36Sopenharmony_ci r = (uint32_t *)&coef[i]; 37362306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_CRCM, 37462306a36Sopenharmony_ci EASRC_CRCM_RS_CWD(r[0])); 37562306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_CRCM, 37662306a36Sopenharmony_ci EASRC_CRCM_RS_CWD(r[1])); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/** 38362306a36Sopenharmony_ci * fsl_easrc_normalize_filter - Scale filter coefficients (64 bits float) 38462306a36Sopenharmony_ci * For input float32 normalized range (1.0,-1.0) -> output int[16,24,32]: 38562306a36Sopenharmony_ci * scale it by multiplying filter coefficients by 2^31 38662306a36Sopenharmony_ci * For input int[16, 24, 32] -> output float32 38762306a36Sopenharmony_ci * scale it by multiplying filter coefficients by 2^-15, 2^-23, 2^-31 38862306a36Sopenharmony_ci * input: 38962306a36Sopenharmony_ci * @easrc: Structure pointer of fsl_asrc 39062306a36Sopenharmony_ci * @infilter : Pointer to non-scaled input filter 39162306a36Sopenharmony_ci * @shift: The multiply factor 39262306a36Sopenharmony_ci * output: 39362306a36Sopenharmony_ci * @outfilter: scaled filter 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_cistatic int fsl_easrc_normalize_filter(struct fsl_asrc *easrc, 39662306a36Sopenharmony_ci u64 *infilter, 39762306a36Sopenharmony_ci u64 *outfilter, 39862306a36Sopenharmony_ci int shift) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct device *dev = &easrc->pdev->dev; 40162306a36Sopenharmony_ci u64 coef = *infilter; 40262306a36Sopenharmony_ci s64 exp = (coef & 0x7ff0000000000000ll) >> 52; 40362306a36Sopenharmony_ci u64 outcoef; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* 40662306a36Sopenharmony_ci * If exponent is zero (value == 0), or 7ff (value == NaNs) 40762306a36Sopenharmony_ci * dont touch the content 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci if (exp == 0 || exp == 0x7ff) { 41062306a36Sopenharmony_ci *outfilter = coef; 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* coef * 2^shift ==> exp + shift */ 41562306a36Sopenharmony_ci exp += shift; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if ((shift > 0 && exp >= 0x7ff) || (shift < 0 && exp <= 0)) { 41862306a36Sopenharmony_ci dev_err(dev, "coef out of range\n"); 41962306a36Sopenharmony_ci return -EINVAL; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci outcoef = (u64)(coef & 0x800FFFFFFFFFFFFFll) + ((u64)exp << 52); 42362306a36Sopenharmony_ci *outfilter = outcoef; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int fsl_easrc_write_pf_coeff_mem(struct fsl_asrc *easrc, int ctx_id, 42962306a36Sopenharmony_ci u64 *coef, int n_taps, int shift) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct device *dev = &easrc->pdev->dev; 43262306a36Sopenharmony_ci int ret = 0; 43362306a36Sopenharmony_ci int i; 43462306a36Sopenharmony_ci u32 *r; 43562306a36Sopenharmony_ci u64 tmp; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* If STx_NUM_TAPS is set to 0x0 then return */ 43862306a36Sopenharmony_ci if (!n_taps) 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!coef) { 44262306a36Sopenharmony_ci dev_err(dev, "coef table is NULL\n"); 44362306a36Sopenharmony_ci return -EINVAL; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* 44762306a36Sopenharmony_ci * When switching between stages, the address pointer 44862306a36Sopenharmony_ci * should be reset back to 0x0 before performing a write 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ci ret = fsl_easrc_coeff_mem_ptr_reset(easrc, ctx_id, EASRC_PF_COEFF_MEM); 45162306a36Sopenharmony_ci if (ret) 45262306a36Sopenharmony_ci return ret; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci for (i = 0; i < (n_taps + 1) / 2; i++) { 45562306a36Sopenharmony_ci ret = fsl_easrc_normalize_filter(easrc, &coef[i], &tmp, shift); 45662306a36Sopenharmony_ci if (ret) 45762306a36Sopenharmony_ci return ret; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci r = (uint32_t *)&tmp; 46062306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id), 46162306a36Sopenharmony_ci EASRC_PCF_CD(r[0])); 46262306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id), 46362306a36Sopenharmony_ci EASRC_PCF_CD(r[1])); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int fsl_easrc_prefilter_config(struct fsl_asrc *easrc, 47062306a36Sopenharmony_ci unsigned int ctx_id) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct prefil_params *prefil, *selected_prefil = NULL; 47362306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv; 47462306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv; 47562306a36Sopenharmony_ci struct asrc_firmware_hdr *hdr; 47662306a36Sopenharmony_ci struct fsl_asrc_pair *ctx; 47762306a36Sopenharmony_ci struct device *dev; 47862306a36Sopenharmony_ci u32 inrate, outrate, offset = 0; 47962306a36Sopenharmony_ci u32 in_s_rate, out_s_rate; 48062306a36Sopenharmony_ci snd_pcm_format_t in_s_fmt, out_s_fmt; 48162306a36Sopenharmony_ci int ret, i; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (!easrc) 48462306a36Sopenharmony_ci return -ENODEV; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dev = &easrc->pdev->dev; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (ctx_id >= EASRC_CTX_MAX_NUM) { 48962306a36Sopenharmony_ci dev_err(dev, "Invalid context id[%d]\n", ctx_id); 49062306a36Sopenharmony_ci return -EINVAL; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci easrc_priv = easrc->private; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci ctx = easrc->pair[ctx_id]; 49662306a36Sopenharmony_ci ctx_priv = ctx->private; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci in_s_rate = ctx_priv->in_params.sample_rate; 49962306a36Sopenharmony_ci out_s_rate = ctx_priv->out_params.sample_rate; 50062306a36Sopenharmony_ci in_s_fmt = ctx_priv->in_params.sample_format; 50162306a36Sopenharmony_ci out_s_fmt = ctx_priv->out_params.sample_format; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ctx_priv->in_filled_sample = bits_taps_to_val(easrc_priv->rs_num_taps) / 2; 50462306a36Sopenharmony_ci ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ctx_priv->st1_num_taps = 0; 50762306a36Sopenharmony_ci ctx_priv->st2_num_taps = 0; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_CCE1(ctx_id), 0); 51062306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_CCE2(ctx_id), 0); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* 51362306a36Sopenharmony_ci * The audio float point data range is (-1, 1), the asrc would output 51462306a36Sopenharmony_ci * all zero for float point input and integer output case, that is to 51562306a36Sopenharmony_ci * drop the fractional part of the data directly. 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * In order to support float to int conversion or int to float 51862306a36Sopenharmony_ci * conversion we need to do special operation on the coefficient to 51962306a36Sopenharmony_ci * enlarge/reduce the data to the expected range. 52062306a36Sopenharmony_ci * 52162306a36Sopenharmony_ci * For float to int case: 52262306a36Sopenharmony_ci * Up sampling: 52362306a36Sopenharmony_ci * 1. Create a 1 tap filter with center tap (only tap) of 2^31 52462306a36Sopenharmony_ci * in 64 bits floating point. 52562306a36Sopenharmony_ci * double value = (double)(((uint64_t)1) << 31) 52662306a36Sopenharmony_ci * 2. Program 1 tap prefilter with center tap above. 52762306a36Sopenharmony_ci * 52862306a36Sopenharmony_ci * Down sampling, 52962306a36Sopenharmony_ci * 1. If the filter is single stage filter, add "shift" to the exponent 53062306a36Sopenharmony_ci * of stage 1 coefficients. 53162306a36Sopenharmony_ci * 2. If the filter is two stage filter , add "shift" to the exponent 53262306a36Sopenharmony_ci * of stage 2 coefficients. 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * The "shift" is 31, same for int16, int24, int32 case. 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * For int to float case: 53762306a36Sopenharmony_ci * Up sampling: 53862306a36Sopenharmony_ci * 1. Create a 1 tap filter with center tap (only tap) of 2^-31 53962306a36Sopenharmony_ci * in 64 bits floating point. 54062306a36Sopenharmony_ci * 2. Program 1 tap prefilter with center tap above. 54162306a36Sopenharmony_ci * 54262306a36Sopenharmony_ci * Down sampling, 54362306a36Sopenharmony_ci * 1. If the filter is single stage filter, subtract "shift" to the 54462306a36Sopenharmony_ci * exponent of stage 1 coefficients. 54562306a36Sopenharmony_ci * 2. If the filter is two stage filter , subtract "shift" to the 54662306a36Sopenharmony_ci * exponent of stage 2 coefficients. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * The "shift" is 15,23,31, different for int16, int24, int32 case. 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci if (out_s_rate >= in_s_rate) { 55262306a36Sopenharmony_ci if (out_s_rate == in_s_rate) 55362306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, 55462306a36Sopenharmony_ci REG_EASRC_CCE1(ctx_id), 55562306a36Sopenharmony_ci EASRC_CCE1_RS_BYPASS_MASK, 55662306a36Sopenharmony_ci EASRC_CCE1_RS_BYPASS); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ctx_priv->st1_num_taps = 1; 55962306a36Sopenharmony_ci ctx_priv->st1_coeff = &easrc_priv->const_coeff; 56062306a36Sopenharmony_ci ctx_priv->st1_num_exp = 1; 56162306a36Sopenharmony_ci ctx_priv->st2_num_taps = 0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE && 56462306a36Sopenharmony_ci out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE) 56562306a36Sopenharmony_ci ctx_priv->st1_addexp = 31; 56662306a36Sopenharmony_ci else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE && 56762306a36Sopenharmony_ci out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE) 56862306a36Sopenharmony_ci ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp; 56962306a36Sopenharmony_ci } else { 57062306a36Sopenharmony_ci inrate = ctx_priv->in_params.norm_rate; 57162306a36Sopenharmony_ci outrate = ctx_priv->out_params.norm_rate; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci hdr = easrc_priv->firmware_hdr; 57462306a36Sopenharmony_ci prefil = easrc_priv->prefil; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci for (i = 0; i < hdr->prefil_scen; i++) { 57762306a36Sopenharmony_ci if (inrate == prefil[i].insr && 57862306a36Sopenharmony_ci outrate == prefil[i].outsr) { 57962306a36Sopenharmony_ci selected_prefil = &prefil[i]; 58062306a36Sopenharmony_ci dev_dbg(dev, "Selected prefilter: %u insr, %u outsr, %u st1_taps, %u st2_taps\n", 58162306a36Sopenharmony_ci selected_prefil->insr, 58262306a36Sopenharmony_ci selected_prefil->outsr, 58362306a36Sopenharmony_ci selected_prefil->st1_taps, 58462306a36Sopenharmony_ci selected_prefil->st2_taps); 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (!selected_prefil) { 59062306a36Sopenharmony_ci dev_err(dev, "Conversion from in ratio %u(%u) to out ratio %u(%u) is not supported\n", 59162306a36Sopenharmony_ci in_s_rate, inrate, 59262306a36Sopenharmony_ci out_s_rate, outrate); 59362306a36Sopenharmony_ci return -EINVAL; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * In prefilter coeff array, first st1_num_taps represent the 59862306a36Sopenharmony_ci * stage1 prefilter coefficients followed by next st2_num_taps 59962306a36Sopenharmony_ci * representing stage 2 coefficients 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci ctx_priv->st1_num_taps = selected_prefil->st1_taps; 60262306a36Sopenharmony_ci ctx_priv->st1_coeff = selected_prefil->coeff; 60362306a36Sopenharmony_ci ctx_priv->st1_num_exp = selected_prefil->st1_exp; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci offset = ((selected_prefil->st1_taps + 1) / 2); 60662306a36Sopenharmony_ci ctx_priv->st2_num_taps = selected_prefil->st2_taps; 60762306a36Sopenharmony_ci ctx_priv->st2_coeff = selected_prefil->coeff + offset; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE && 61062306a36Sopenharmony_ci out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE) { 61162306a36Sopenharmony_ci /* only change stage2 coefficient for 2 stage case */ 61262306a36Sopenharmony_ci if (ctx_priv->st2_num_taps > 0) 61362306a36Sopenharmony_ci ctx_priv->st2_addexp = 31; 61462306a36Sopenharmony_ci else 61562306a36Sopenharmony_ci ctx_priv->st1_addexp = 31; 61662306a36Sopenharmony_ci } else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE && 61762306a36Sopenharmony_ci out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE) { 61862306a36Sopenharmony_ci if (ctx_priv->st2_num_taps > 0) 61962306a36Sopenharmony_ci ctx_priv->st2_addexp -= ctx_priv->in_params.fmt.addexp; 62062306a36Sopenharmony_ci else 62162306a36Sopenharmony_ci ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci ctx_priv->in_filled_sample += (ctx_priv->st1_num_taps / 2) * ctx_priv->st1_num_exp + 62662306a36Sopenharmony_ci ctx_priv->st2_num_taps / 2; 62762306a36Sopenharmony_ci ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (ctx_priv->in_filled_sample * out_s_rate % in_s_rate != 0) 63062306a36Sopenharmony_ci ctx_priv->out_missed_sample += 1; 63162306a36Sopenharmony_ci /* 63262306a36Sopenharmony_ci * To modify the value of a prefilter coefficient, the user must 63362306a36Sopenharmony_ci * perform a write to the register ASRC_PRE_COEFF_FIFOn[COEFF_DATA] 63462306a36Sopenharmony_ci * while the respective context RUN_EN bit is set to 0b0 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id), 63762306a36Sopenharmony_ci EASRC_CC_EN_MASK, 0); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) { 64062306a36Sopenharmony_ci dev_err(dev, "ST1 taps [%d] mus be lower than %d\n", 64162306a36Sopenharmony_ci ctx_priv->st1_num_taps, EASRC_MAX_PF_TAPS); 64262306a36Sopenharmony_ci ret = -EINVAL; 64362306a36Sopenharmony_ci goto ctx_error; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Update ctx ST1_NUM_TAPS in Context Control Extended 2 register */ 64762306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id), 64862306a36Sopenharmony_ci EASRC_CCE2_ST1_TAPS_MASK, 64962306a36Sopenharmony_ci EASRC_CCE2_ST1_TAPS(ctx_priv->st1_num_taps - 1)); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Prefilter Coefficient Write Select to write in ST1 coeff */ 65262306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), 65362306a36Sopenharmony_ci EASRC_CCE1_COEF_WS_MASK, 65462306a36Sopenharmony_ci EASRC_PF_ST1_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id, 65762306a36Sopenharmony_ci ctx_priv->st1_coeff, 65862306a36Sopenharmony_ci ctx_priv->st1_num_taps, 65962306a36Sopenharmony_ci ctx_priv->st1_addexp); 66062306a36Sopenharmony_ci if (ret) 66162306a36Sopenharmony_ci goto ctx_error; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (ctx_priv->st2_num_taps > 0) { 66462306a36Sopenharmony_ci if (ctx_priv->st2_num_taps + ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) { 66562306a36Sopenharmony_ci dev_err(dev, "ST2 taps [%d] mus be lower than %d\n", 66662306a36Sopenharmony_ci ctx_priv->st2_num_taps, EASRC_MAX_PF_TAPS); 66762306a36Sopenharmony_ci ret = -EINVAL; 66862306a36Sopenharmony_ci goto ctx_error; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), 67262306a36Sopenharmony_ci EASRC_CCE1_PF_TSEN_MASK, 67362306a36Sopenharmony_ci EASRC_CCE1_PF_TSEN); 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * Enable prefilter stage1 writeback floating point 67662306a36Sopenharmony_ci * which is used for FLOAT_LE case 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), 67962306a36Sopenharmony_ci EASRC_CCE1_PF_ST1_WBFP_MASK, 68062306a36Sopenharmony_ci EASRC_CCE1_PF_ST1_WBFP); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), 68362306a36Sopenharmony_ci EASRC_CCE1_PF_EXP_MASK, 68462306a36Sopenharmony_ci EASRC_CCE1_PF_EXP(ctx_priv->st1_num_exp - 1)); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Update ctx ST2_NUM_TAPS in Context Control Extended 2 reg */ 68762306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id), 68862306a36Sopenharmony_ci EASRC_CCE2_ST2_TAPS_MASK, 68962306a36Sopenharmony_ci EASRC_CCE2_ST2_TAPS(ctx_priv->st2_num_taps - 1)); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* Prefilter Coefficient Write Select to write in ST2 coeff */ 69262306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), 69362306a36Sopenharmony_ci EASRC_CCE1_COEF_WS_MASK, 69462306a36Sopenharmony_ci EASRC_PF_ST2_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id, 69762306a36Sopenharmony_ci ctx_priv->st2_coeff, 69862306a36Sopenharmony_ci ctx_priv->st2_num_taps, 69962306a36Sopenharmony_ci ctx_priv->st2_addexp); 70062306a36Sopenharmony_ci if (ret) 70162306a36Sopenharmony_ci goto ctx_error; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci return 0; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cictx_error: 70762306a36Sopenharmony_ci return ret; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int fsl_easrc_max_ch_for_slot(struct fsl_asrc_pair *ctx, 71162306a36Sopenharmony_ci struct fsl_easrc_slot *slot) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; 71462306a36Sopenharmony_ci int st1_mem_alloc = 0, st2_mem_alloc = 0; 71562306a36Sopenharmony_ci int pf_mem_alloc = 0; 71662306a36Sopenharmony_ci int max_channels = 8 - slot->num_channel; 71762306a36Sopenharmony_ci int channels = 0; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (ctx_priv->st1_num_taps > 0) { 72062306a36Sopenharmony_ci if (ctx_priv->st2_num_taps > 0) 72162306a36Sopenharmony_ci st1_mem_alloc = 72262306a36Sopenharmony_ci (ctx_priv->st1_num_taps - 1) * ctx_priv->st1_num_exp + 1; 72362306a36Sopenharmony_ci else 72462306a36Sopenharmony_ci st1_mem_alloc = ctx_priv->st1_num_taps; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (ctx_priv->st2_num_taps > 0) 72862306a36Sopenharmony_ci st2_mem_alloc = ctx_priv->st2_num_taps; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci pf_mem_alloc = st1_mem_alloc + st2_mem_alloc; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (pf_mem_alloc != 0) 73362306a36Sopenharmony_ci channels = (6144 - slot->pf_mem_used) / pf_mem_alloc; 73462306a36Sopenharmony_ci else 73562306a36Sopenharmony_ci channels = 8; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (channels < max_channels) 73862306a36Sopenharmony_ci max_channels = channels; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return max_channels; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int fsl_easrc_config_one_slot(struct fsl_asrc_pair *ctx, 74462306a36Sopenharmony_ci struct fsl_easrc_slot *slot, 74562306a36Sopenharmony_ci unsigned int slot_ctx_idx, 74662306a36Sopenharmony_ci unsigned int *req_channels, 74762306a36Sopenharmony_ci unsigned int *start_channel, 74862306a36Sopenharmony_ci unsigned int *avail_channel) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 75162306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; 75262306a36Sopenharmony_ci int st1_chanxexp, st1_mem_alloc = 0, st2_mem_alloc; 75362306a36Sopenharmony_ci unsigned int reg0, reg1, reg2, reg3; 75462306a36Sopenharmony_ci unsigned int addr; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (slot->slot_index == 0) { 75762306a36Sopenharmony_ci reg0 = REG_EASRC_DPCS0R0(slot_ctx_idx); 75862306a36Sopenharmony_ci reg1 = REG_EASRC_DPCS0R1(slot_ctx_idx); 75962306a36Sopenharmony_ci reg2 = REG_EASRC_DPCS0R2(slot_ctx_idx); 76062306a36Sopenharmony_ci reg3 = REG_EASRC_DPCS0R3(slot_ctx_idx); 76162306a36Sopenharmony_ci } else { 76262306a36Sopenharmony_ci reg0 = REG_EASRC_DPCS1R0(slot_ctx_idx); 76362306a36Sopenharmony_ci reg1 = REG_EASRC_DPCS1R1(slot_ctx_idx); 76462306a36Sopenharmony_ci reg2 = REG_EASRC_DPCS1R2(slot_ctx_idx); 76562306a36Sopenharmony_ci reg3 = REG_EASRC_DPCS1R3(slot_ctx_idx); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (*req_channels <= *avail_channel) { 76962306a36Sopenharmony_ci slot->num_channel = *req_channels; 77062306a36Sopenharmony_ci *req_channels = 0; 77162306a36Sopenharmony_ci } else { 77262306a36Sopenharmony_ci slot->num_channel = *avail_channel; 77362306a36Sopenharmony_ci *req_channels -= *avail_channel; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci slot->min_channel = *start_channel; 77762306a36Sopenharmony_ci slot->max_channel = *start_channel + slot->num_channel - 1; 77862306a36Sopenharmony_ci slot->ctx_index = ctx->index; 77962306a36Sopenharmony_ci slot->busy = true; 78062306a36Sopenharmony_ci *start_channel += slot->num_channel; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg0, 78362306a36Sopenharmony_ci EASRC_DPCS0R0_MAXCH_MASK, 78462306a36Sopenharmony_ci EASRC_DPCS0R0_MAXCH(slot->max_channel)); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg0, 78762306a36Sopenharmony_ci EASRC_DPCS0R0_MINCH_MASK, 78862306a36Sopenharmony_ci EASRC_DPCS0R0_MINCH(slot->min_channel)); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg0, 79162306a36Sopenharmony_ci EASRC_DPCS0R0_NUMCH_MASK, 79262306a36Sopenharmony_ci EASRC_DPCS0R0_NUMCH(slot->num_channel - 1)); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg0, 79562306a36Sopenharmony_ci EASRC_DPCS0R0_CTXNUM_MASK, 79662306a36Sopenharmony_ci EASRC_DPCS0R0_CTXNUM(slot->ctx_index)); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (ctx_priv->st1_num_taps > 0) { 79962306a36Sopenharmony_ci if (ctx_priv->st2_num_taps > 0) 80062306a36Sopenharmony_ci st1_mem_alloc = 80162306a36Sopenharmony_ci (ctx_priv->st1_num_taps - 1) * slot->num_channel * 80262306a36Sopenharmony_ci ctx_priv->st1_num_exp + slot->num_channel; 80362306a36Sopenharmony_ci else 80462306a36Sopenharmony_ci st1_mem_alloc = ctx_priv->st1_num_taps * slot->num_channel; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci slot->pf_mem_used = st1_mem_alloc; 80762306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg2, 80862306a36Sopenharmony_ci EASRC_DPCS0R2_ST1_MA_MASK, 80962306a36Sopenharmony_ci EASRC_DPCS0R2_ST1_MA(st1_mem_alloc)); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (slot->slot_index == 1) 81262306a36Sopenharmony_ci addr = PREFILTER_MEM_LEN - st1_mem_alloc; 81362306a36Sopenharmony_ci else 81462306a36Sopenharmony_ci addr = 0; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg2, 81762306a36Sopenharmony_ci EASRC_DPCS0R2_ST1_SA_MASK, 81862306a36Sopenharmony_ci EASRC_DPCS0R2_ST1_SA(addr)); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (ctx_priv->st2_num_taps > 0) { 82262306a36Sopenharmony_ci st1_chanxexp = slot->num_channel * (ctx_priv->st1_num_exp - 1); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg1, 82562306a36Sopenharmony_ci EASRC_DPCS0R1_ST1_EXP_MASK, 82662306a36Sopenharmony_ci EASRC_DPCS0R1_ST1_EXP(st1_chanxexp)); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci st2_mem_alloc = slot->num_channel * ctx_priv->st2_num_taps; 82962306a36Sopenharmony_ci slot->pf_mem_used += st2_mem_alloc; 83062306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg3, 83162306a36Sopenharmony_ci EASRC_DPCS0R3_ST2_MA_MASK, 83262306a36Sopenharmony_ci EASRC_DPCS0R3_ST2_MA(st2_mem_alloc)); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (slot->slot_index == 1) 83562306a36Sopenharmony_ci addr = PREFILTER_MEM_LEN - st1_mem_alloc - st2_mem_alloc; 83662306a36Sopenharmony_ci else 83762306a36Sopenharmony_ci addr = st1_mem_alloc; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg3, 84062306a36Sopenharmony_ci EASRC_DPCS0R3_ST2_SA_MASK, 84162306a36Sopenharmony_ci EASRC_DPCS0R3_ST2_SA(addr)); 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, reg0, 84562306a36Sopenharmony_ci EASRC_DPCS0R0_EN_MASK, EASRC_DPCS0R0_EN); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/* 85162306a36Sopenharmony_ci * fsl_easrc_config_slot 85262306a36Sopenharmony_ci * 85362306a36Sopenharmony_ci * A single context can be split amongst any of the 4 context processing pipes 85462306a36Sopenharmony_ci * in the design. 85562306a36Sopenharmony_ci * The total number of channels consumed within the context processor must be 85662306a36Sopenharmony_ci * less than or equal to 8. if a single context is configured to contain more 85762306a36Sopenharmony_ci * than 8 channels then it must be distributed across multiple context 85862306a36Sopenharmony_ci * processing pipe slots. 85962306a36Sopenharmony_ci * 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_cistatic int fsl_easrc_config_slot(struct fsl_asrc *easrc, unsigned int ctx_id) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 86462306a36Sopenharmony_ci struct fsl_asrc_pair *ctx = easrc->pair[ctx_id]; 86562306a36Sopenharmony_ci int req_channels = ctx->channels; 86662306a36Sopenharmony_ci int start_channel = 0, avail_channel; 86762306a36Sopenharmony_ci struct fsl_easrc_slot *slot0, *slot1; 86862306a36Sopenharmony_ci struct fsl_easrc_slot *slota, *slotb; 86962306a36Sopenharmony_ci int i, ret; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (req_channels <= 0) 87262306a36Sopenharmony_ci return -EINVAL; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci for (i = 0; i < EASRC_CTX_MAX_NUM; i++) { 87562306a36Sopenharmony_ci slot0 = &easrc_priv->slot[i][0]; 87662306a36Sopenharmony_ci slot1 = &easrc_priv->slot[i][1]; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (slot0->busy && slot1->busy) { 87962306a36Sopenharmony_ci continue; 88062306a36Sopenharmony_ci } else if ((slot0->busy && slot0->ctx_index == ctx->index) || 88162306a36Sopenharmony_ci (slot1->busy && slot1->ctx_index == ctx->index)) { 88262306a36Sopenharmony_ci continue; 88362306a36Sopenharmony_ci } else if (!slot0->busy) { 88462306a36Sopenharmony_ci slota = slot0; 88562306a36Sopenharmony_ci slotb = slot1; 88662306a36Sopenharmony_ci slota->slot_index = 0; 88762306a36Sopenharmony_ci } else if (!slot1->busy) { 88862306a36Sopenharmony_ci slota = slot1; 88962306a36Sopenharmony_ci slotb = slot0; 89062306a36Sopenharmony_ci slota->slot_index = 1; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (!slota || !slotb) 89462306a36Sopenharmony_ci continue; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci avail_channel = fsl_easrc_max_ch_for_slot(ctx, slotb); 89762306a36Sopenharmony_ci if (avail_channel <= 0) 89862306a36Sopenharmony_ci continue; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci ret = fsl_easrc_config_one_slot(ctx, slota, i, &req_channels, 90162306a36Sopenharmony_ci &start_channel, &avail_channel); 90262306a36Sopenharmony_ci if (ret) 90362306a36Sopenharmony_ci return ret; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (req_channels > 0) 90662306a36Sopenharmony_ci continue; 90762306a36Sopenharmony_ci else 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (req_channels > 0) { 91262306a36Sopenharmony_ci dev_err(&easrc->pdev->dev, "no avail slot.\n"); 91362306a36Sopenharmony_ci return -EINVAL; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci/* 92062306a36Sopenharmony_ci * fsl_easrc_release_slot 92162306a36Sopenharmony_ci * 92262306a36Sopenharmony_ci * Clear the slot configuration 92362306a36Sopenharmony_ci */ 92462306a36Sopenharmony_cistatic int fsl_easrc_release_slot(struct fsl_asrc *easrc, unsigned int ctx_id) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 92762306a36Sopenharmony_ci struct fsl_asrc_pair *ctx = easrc->pair[ctx_id]; 92862306a36Sopenharmony_ci int i; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci for (i = 0; i < EASRC_CTX_MAX_NUM; i++) { 93162306a36Sopenharmony_ci if (easrc_priv->slot[i][0].busy && 93262306a36Sopenharmony_ci easrc_priv->slot[i][0].ctx_index == ctx->index) { 93362306a36Sopenharmony_ci easrc_priv->slot[i][0].busy = false; 93462306a36Sopenharmony_ci easrc_priv->slot[i][0].num_channel = 0; 93562306a36Sopenharmony_ci easrc_priv->slot[i][0].pf_mem_used = 0; 93662306a36Sopenharmony_ci /* set registers */ 93762306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS0R0(i), 0); 93862306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS0R1(i), 0); 93962306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS0R2(i), 0); 94062306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS0R3(i), 0); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (easrc_priv->slot[i][1].busy && 94462306a36Sopenharmony_ci easrc_priv->slot[i][1].ctx_index == ctx->index) { 94562306a36Sopenharmony_ci easrc_priv->slot[i][1].busy = false; 94662306a36Sopenharmony_ci easrc_priv->slot[i][1].num_channel = 0; 94762306a36Sopenharmony_ci easrc_priv->slot[i][1].pf_mem_used = 0; 94862306a36Sopenharmony_ci /* set registers */ 94962306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS1R0(i), 0); 95062306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS1R1(i), 0); 95162306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS1R2(i), 0); 95262306a36Sopenharmony_ci regmap_write(easrc->regmap, REG_EASRC_DPCS1R3(i), 0); 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/* 96062306a36Sopenharmony_ci * fsl_easrc_config_context 96162306a36Sopenharmony_ci * 96262306a36Sopenharmony_ci * Configure the register relate with context. 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_cistatic int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv; 96762306a36Sopenharmony_ci struct fsl_asrc_pair *ctx; 96862306a36Sopenharmony_ci struct device *dev; 96962306a36Sopenharmony_ci unsigned long lock_flags; 97062306a36Sopenharmony_ci int ret; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (!easrc) 97362306a36Sopenharmony_ci return -ENODEV; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci dev = &easrc->pdev->dev; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (ctx_id >= EASRC_CTX_MAX_NUM) { 97862306a36Sopenharmony_ci dev_err(dev, "Invalid context id[%d]\n", ctx_id); 97962306a36Sopenharmony_ci return -EINVAL; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci ctx = easrc->pair[ctx_id]; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci ctx_priv = ctx->private; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci fsl_easrc_normalize_rates(ctx); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci ret = fsl_easrc_set_rs_ratio(ctx); 98962306a36Sopenharmony_ci if (ret) 99062306a36Sopenharmony_ci return ret; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* Initialize the context coeficients */ 99362306a36Sopenharmony_ci ret = fsl_easrc_prefilter_config(easrc, ctx->index); 99462306a36Sopenharmony_ci if (ret) 99562306a36Sopenharmony_ci return ret; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci spin_lock_irqsave(&easrc->lock, lock_flags); 99862306a36Sopenharmony_ci ret = fsl_easrc_config_slot(easrc, ctx->index); 99962306a36Sopenharmony_ci spin_unlock_irqrestore(&easrc->lock, lock_flags); 100062306a36Sopenharmony_ci if (ret) 100162306a36Sopenharmony_ci return ret; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* 100462306a36Sopenharmony_ci * Both prefilter and resampling filters can use following 100562306a36Sopenharmony_ci * initialization modes: 100662306a36Sopenharmony_ci * 2 - zero-fil mode 100762306a36Sopenharmony_ci * 1 - replication mode 100862306a36Sopenharmony_ci * 0 - software control 100962306a36Sopenharmony_ci */ 101062306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), 101162306a36Sopenharmony_ci EASRC_CCE1_RS_INIT_MASK, 101262306a36Sopenharmony_ci EASRC_CCE1_RS_INIT(ctx_priv->rs_init_mode)); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id), 101562306a36Sopenharmony_ci EASRC_CCE1_PF_INIT_MASK, 101662306a36Sopenharmony_ci EASRC_CCE1_PF_INIT(ctx_priv->pf_init_mode)); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* 101962306a36Sopenharmony_ci * Context Input FIFO Watermark 102062306a36Sopenharmony_ci * DMA request is generated when input FIFO < FIFO_WTMK 102162306a36Sopenharmony_ci */ 102262306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id), 102362306a36Sopenharmony_ci EASRC_CC_FIFO_WTMK_MASK, 102462306a36Sopenharmony_ci EASRC_CC_FIFO_WTMK(ctx_priv->in_params.fifo_wtmk)); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* 102762306a36Sopenharmony_ci * Context Output FIFO Watermark 102862306a36Sopenharmony_ci * DMA request is generated when output FIFO > FIFO_WTMK 102962306a36Sopenharmony_ci * So we set fifo_wtmk -1 to register. 103062306a36Sopenharmony_ci */ 103162306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx_id), 103262306a36Sopenharmony_ci EASRC_COC_FIFO_WTMK_MASK, 103362306a36Sopenharmony_ci EASRC_COC_FIFO_WTMK(ctx_priv->out_params.fifo_wtmk - 1)); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* Number of channels */ 103662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id), 103762306a36Sopenharmony_ci EASRC_CC_CHEN_MASK, 103862306a36Sopenharmony_ci EASRC_CC_CHEN(ctx->channels - 1)); 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int fsl_easrc_process_format(struct fsl_asrc_pair *ctx, 104362306a36Sopenharmony_ci struct fsl_easrc_data_fmt *fmt, 104462306a36Sopenharmony_ci snd_pcm_format_t raw_fmt) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 104762306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 104862306a36Sopenharmony_ci int ret; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (!fmt) 105162306a36Sopenharmony_ci return -EINVAL; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* 105462306a36Sopenharmony_ci * Context Input Floating Point Format 105562306a36Sopenharmony_ci * 0 - Integer Format 105662306a36Sopenharmony_ci * 1 - Single Precision FP Format 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_ci fmt->floating_point = !snd_pcm_format_linear(raw_fmt); 105962306a36Sopenharmony_ci fmt->sample_pos = 0; 106062306a36Sopenharmony_ci fmt->iec958 = 0; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* Get the data width */ 106362306a36Sopenharmony_ci switch (snd_pcm_format_width(raw_fmt)) { 106462306a36Sopenharmony_ci case 16: 106562306a36Sopenharmony_ci fmt->width = EASRC_WIDTH_16_BIT; 106662306a36Sopenharmony_ci fmt->addexp = 15; 106762306a36Sopenharmony_ci break; 106862306a36Sopenharmony_ci case 20: 106962306a36Sopenharmony_ci fmt->width = EASRC_WIDTH_20_BIT; 107062306a36Sopenharmony_ci fmt->addexp = 19; 107162306a36Sopenharmony_ci break; 107262306a36Sopenharmony_ci case 24: 107362306a36Sopenharmony_ci fmt->width = EASRC_WIDTH_24_BIT; 107462306a36Sopenharmony_ci fmt->addexp = 23; 107562306a36Sopenharmony_ci break; 107662306a36Sopenharmony_ci case 32: 107762306a36Sopenharmony_ci fmt->width = EASRC_WIDTH_32_BIT; 107862306a36Sopenharmony_ci fmt->addexp = 31; 107962306a36Sopenharmony_ci break; 108062306a36Sopenharmony_ci default: 108162306a36Sopenharmony_ci return -EINVAL; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci switch (raw_fmt) { 108562306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: 108662306a36Sopenharmony_ci fmt->width = easrc_priv->bps_iec958[ctx->index]; 108762306a36Sopenharmony_ci fmt->iec958 = 1; 108862306a36Sopenharmony_ci fmt->floating_point = 0; 108962306a36Sopenharmony_ci if (fmt->width == EASRC_WIDTH_16_BIT) { 109062306a36Sopenharmony_ci fmt->sample_pos = 12; 109162306a36Sopenharmony_ci fmt->addexp = 15; 109262306a36Sopenharmony_ci } else if (fmt->width == EASRC_WIDTH_20_BIT) { 109362306a36Sopenharmony_ci fmt->sample_pos = 8; 109462306a36Sopenharmony_ci fmt->addexp = 19; 109562306a36Sopenharmony_ci } else if (fmt->width == EASRC_WIDTH_24_BIT) { 109662306a36Sopenharmony_ci fmt->sample_pos = 4; 109762306a36Sopenharmony_ci fmt->addexp = 23; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci break; 110062306a36Sopenharmony_ci default: 110162306a36Sopenharmony_ci break; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* 110562306a36Sopenharmony_ci * Data Endianness 110662306a36Sopenharmony_ci * 0 - Little-Endian 110762306a36Sopenharmony_ci * 1 - Big-Endian 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci ret = snd_pcm_format_big_endian(raw_fmt); 111062306a36Sopenharmony_ci if (ret < 0) 111162306a36Sopenharmony_ci return ret; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci fmt->endianness = ret; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* 111662306a36Sopenharmony_ci * Input Data sign 111762306a36Sopenharmony_ci * 0b - Signed Format 111862306a36Sopenharmony_ci * 1b - Unsigned Format 111962306a36Sopenharmony_ci */ 112062306a36Sopenharmony_ci fmt->unsign = snd_pcm_format_unsigned(raw_fmt) > 0 ? 1 : 0; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic int fsl_easrc_set_ctx_format(struct fsl_asrc_pair *ctx, 112662306a36Sopenharmony_ci snd_pcm_format_t *in_raw_format, 112762306a36Sopenharmony_ci snd_pcm_format_t *out_raw_format) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 113062306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; 113162306a36Sopenharmony_ci struct fsl_easrc_data_fmt *in_fmt = &ctx_priv->in_params.fmt; 113262306a36Sopenharmony_ci struct fsl_easrc_data_fmt *out_fmt = &ctx_priv->out_params.fmt; 113362306a36Sopenharmony_ci int ret = 0; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* Get the bitfield values for input data format */ 113662306a36Sopenharmony_ci if (in_raw_format && out_raw_format) { 113762306a36Sopenharmony_ci ret = fsl_easrc_process_format(ctx, in_fmt, *in_raw_format); 113862306a36Sopenharmony_ci if (ret) 113962306a36Sopenharmony_ci return ret; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 114362306a36Sopenharmony_ci EASRC_CC_BPS_MASK, 114462306a36Sopenharmony_ci EASRC_CC_BPS(in_fmt->width)); 114562306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 114662306a36Sopenharmony_ci EASRC_CC_ENDIANNESS_MASK, 114762306a36Sopenharmony_ci in_fmt->endianness << EASRC_CC_ENDIANNESS_SHIFT); 114862306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 114962306a36Sopenharmony_ci EASRC_CC_FMT_MASK, 115062306a36Sopenharmony_ci in_fmt->floating_point << EASRC_CC_FMT_SHIFT); 115162306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 115262306a36Sopenharmony_ci EASRC_CC_INSIGN_MASK, 115362306a36Sopenharmony_ci in_fmt->unsign << EASRC_CC_INSIGN_SHIFT); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* In Sample Position */ 115662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 115762306a36Sopenharmony_ci EASRC_CC_SAMPLE_POS_MASK, 115862306a36Sopenharmony_ci EASRC_CC_SAMPLE_POS(in_fmt->sample_pos)); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* Get the bitfield values for input data format */ 116162306a36Sopenharmony_ci if (in_raw_format && out_raw_format) { 116262306a36Sopenharmony_ci ret = fsl_easrc_process_format(ctx, out_fmt, *out_raw_format); 116362306a36Sopenharmony_ci if (ret) 116462306a36Sopenharmony_ci return ret; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 116862306a36Sopenharmony_ci EASRC_COC_BPS_MASK, 116962306a36Sopenharmony_ci EASRC_COC_BPS(out_fmt->width)); 117062306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 117162306a36Sopenharmony_ci EASRC_COC_ENDIANNESS_MASK, 117262306a36Sopenharmony_ci out_fmt->endianness << EASRC_COC_ENDIANNESS_SHIFT); 117362306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 117462306a36Sopenharmony_ci EASRC_COC_FMT_MASK, 117562306a36Sopenharmony_ci out_fmt->floating_point << EASRC_COC_FMT_SHIFT); 117662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 117762306a36Sopenharmony_ci EASRC_COC_OUTSIGN_MASK, 117862306a36Sopenharmony_ci out_fmt->unsign << EASRC_COC_OUTSIGN_SHIFT); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Out Sample Position */ 118162306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 118262306a36Sopenharmony_ci EASRC_COC_SAMPLE_POS_MASK, 118362306a36Sopenharmony_ci EASRC_COC_SAMPLE_POS(out_fmt->sample_pos)); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 118662306a36Sopenharmony_ci EASRC_COC_IEC_EN_MASK, 118762306a36Sopenharmony_ci out_fmt->iec958 << EASRC_COC_IEC_EN_SHIFT); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return ret; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci/* 119362306a36Sopenharmony_ci * The ASRC provides interleaving support in hardware to ensure that a 119462306a36Sopenharmony_ci * variety of sample sources can be internally combined 119562306a36Sopenharmony_ci * to conform with this format. Interleaving parameters are accessed 119662306a36Sopenharmony_ci * through the ASRC_CTRL_IN_ACCESSa and ASRC_CTRL_OUT_ACCESSa registers 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_cistatic int fsl_easrc_set_ctx_organziation(struct fsl_asrc_pair *ctx) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv; 120162306a36Sopenharmony_ci struct fsl_asrc *easrc; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (!ctx) 120462306a36Sopenharmony_ci return -ENODEV; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci easrc = ctx->asrc; 120762306a36Sopenharmony_ci ctx_priv = ctx->private; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci /* input interleaving parameters */ 121062306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index), 121162306a36Sopenharmony_ci EASRC_CIA_ITER_MASK, 121262306a36Sopenharmony_ci EASRC_CIA_ITER(ctx_priv->in_params.iterations)); 121362306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index), 121462306a36Sopenharmony_ci EASRC_CIA_GRLEN_MASK, 121562306a36Sopenharmony_ci EASRC_CIA_GRLEN(ctx_priv->in_params.group_len)); 121662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index), 121762306a36Sopenharmony_ci EASRC_CIA_ACCLEN_MASK, 121862306a36Sopenharmony_ci EASRC_CIA_ACCLEN(ctx_priv->in_params.access_len)); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* output interleaving parameters */ 122162306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index), 122262306a36Sopenharmony_ci EASRC_COA_ITER_MASK, 122362306a36Sopenharmony_ci EASRC_COA_ITER(ctx_priv->out_params.iterations)); 122462306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index), 122562306a36Sopenharmony_ci EASRC_COA_GRLEN_MASK, 122662306a36Sopenharmony_ci EASRC_COA_GRLEN(ctx_priv->out_params.group_len)); 122762306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index), 122862306a36Sopenharmony_ci EASRC_COA_ACCLEN_MASK, 122962306a36Sopenharmony_ci EASRC_COA_ACCLEN(ctx_priv->out_params.access_len)); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci return 0; 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci/* 123562306a36Sopenharmony_ci * Request one of the available contexts 123662306a36Sopenharmony_ci * 123762306a36Sopenharmony_ci * Returns a negative number on error and >=0 as context id 123862306a36Sopenharmony_ci * on success 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_cistatic int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci enum asrc_pair_index index = ASRC_INVALID_PAIR; 124362306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 124462306a36Sopenharmony_ci struct device *dev; 124562306a36Sopenharmony_ci unsigned long lock_flags; 124662306a36Sopenharmony_ci int ret = 0; 124762306a36Sopenharmony_ci int i; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci dev = &easrc->pdev->dev; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci spin_lock_irqsave(&easrc->lock, lock_flags); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) { 125462306a36Sopenharmony_ci if (easrc->pair[i]) 125562306a36Sopenharmony_ci continue; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci index = i; 125862306a36Sopenharmony_ci break; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (index == ASRC_INVALID_PAIR) { 126262306a36Sopenharmony_ci dev_err(dev, "all contexts are busy\n"); 126362306a36Sopenharmony_ci ret = -EBUSY; 126462306a36Sopenharmony_ci } else if (channels > easrc->channel_avail) { 126562306a36Sopenharmony_ci dev_err(dev, "can't give the required channels: %d\n", 126662306a36Sopenharmony_ci channels); 126762306a36Sopenharmony_ci ret = -EINVAL; 126862306a36Sopenharmony_ci } else { 126962306a36Sopenharmony_ci ctx->index = index; 127062306a36Sopenharmony_ci ctx->channels = channels; 127162306a36Sopenharmony_ci easrc->pair[index] = ctx; 127262306a36Sopenharmony_ci easrc->channel_avail -= channels; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci spin_unlock_irqrestore(&easrc->lock, lock_flags); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci return ret; 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci/* 128162306a36Sopenharmony_ci * Release the context 128262306a36Sopenharmony_ci * 128362306a36Sopenharmony_ci * This funciton is mainly doing the revert thing in request context 128462306a36Sopenharmony_ci */ 128562306a36Sopenharmony_cistatic void fsl_easrc_release_context(struct fsl_asrc_pair *ctx) 128662306a36Sopenharmony_ci{ 128762306a36Sopenharmony_ci unsigned long lock_flags; 128862306a36Sopenharmony_ci struct fsl_asrc *easrc; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (!ctx) 129162306a36Sopenharmony_ci return; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci easrc = ctx->asrc; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci spin_lock_irqsave(&easrc->lock, lock_flags); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci fsl_easrc_release_slot(easrc, ctx->index); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci easrc->channel_avail += ctx->channels; 130062306a36Sopenharmony_ci easrc->pair[ctx->index] = NULL; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci spin_unlock_irqrestore(&easrc->lock, lock_flags); 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci/* 130662306a36Sopenharmony_ci * Start the context 130762306a36Sopenharmony_ci * 130862306a36Sopenharmony_ci * Enable the DMA request and context 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_cistatic int fsl_easrc_start_context(struct fsl_asrc_pair *ctx) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 131562306a36Sopenharmony_ci EASRC_CC_FWMDE_MASK, EASRC_CC_FWMDE); 131662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 131762306a36Sopenharmony_ci EASRC_COC_FWMDE_MASK, EASRC_COC_FWMDE); 131862306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 131962306a36Sopenharmony_ci EASRC_CC_EN_MASK, EASRC_CC_EN); 132062306a36Sopenharmony_ci return 0; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci/* 132462306a36Sopenharmony_ci * Stop the context 132562306a36Sopenharmony_ci * 132662306a36Sopenharmony_ci * Disable the DMA request and context 132762306a36Sopenharmony_ci */ 132862306a36Sopenharmony_cistatic int fsl_easrc_stop_context(struct fsl_asrc_pair *ctx) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 133162306a36Sopenharmony_ci int val, i; 133262306a36Sopenharmony_ci int size; 133362306a36Sopenharmony_ci int retry = 200; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci regmap_read(easrc->regmap, REG_EASRC_CC(ctx->index), &val); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (val & EASRC_CC_EN_MASK) { 133862306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, 133962306a36Sopenharmony_ci REG_EASRC_CC(ctx->index), 134062306a36Sopenharmony_ci EASRC_CC_STOP_MASK, EASRC_CC_STOP); 134162306a36Sopenharmony_ci do { 134262306a36Sopenharmony_ci regmap_read(easrc->regmap, REG_EASRC_SFS(ctx->index), &val); 134362306a36Sopenharmony_ci val &= EASRC_SFS_NSGO_MASK; 134462306a36Sopenharmony_ci size = val >> EASRC_SFS_NSGO_SHIFT; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci /* Read FIFO, drop the data */ 134762306a36Sopenharmony_ci for (i = 0; i < size * ctx->channels; i++) 134862306a36Sopenharmony_ci regmap_read(easrc->regmap, REG_EASRC_RDFIFO(ctx->index), &val); 134962306a36Sopenharmony_ci /* Check RUN_STOP_DONE */ 135062306a36Sopenharmony_ci regmap_read(easrc->regmap, REG_EASRC_IRQF, &val); 135162306a36Sopenharmony_ci if (val & EASRC_IRQF_RSD(1 << ctx->index)) { 135262306a36Sopenharmony_ci /*Clear RUN_STOP_DONE*/ 135362306a36Sopenharmony_ci regmap_write_bits(easrc->regmap, 135462306a36Sopenharmony_ci REG_EASRC_IRQF, 135562306a36Sopenharmony_ci EASRC_IRQF_RSD(1 << ctx->index), 135662306a36Sopenharmony_ci EASRC_IRQF_RSD(1 << ctx->index)); 135762306a36Sopenharmony_ci break; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci udelay(100); 136062306a36Sopenharmony_ci } while (--retry); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (retry == 0) 136362306a36Sopenharmony_ci dev_warn(&easrc->pdev->dev, "RUN STOP fail\n"); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 136762306a36Sopenharmony_ci EASRC_CC_EN_MASK | EASRC_CC_STOP_MASK, 0); 136862306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index), 136962306a36Sopenharmony_ci EASRC_CC_FWMDE_MASK, 0); 137062306a36Sopenharmony_ci regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index), 137162306a36Sopenharmony_ci EASRC_COC_FWMDE_MASK, 0); 137262306a36Sopenharmony_ci return 0; 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic struct dma_chan *fsl_easrc_get_dma_channel(struct fsl_asrc_pair *ctx, 137662306a36Sopenharmony_ci bool dir) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci struct fsl_asrc *easrc = ctx->asrc; 137962306a36Sopenharmony_ci enum asrc_pair_index index = ctx->index; 138062306a36Sopenharmony_ci char name[8]; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci /* Example of dma name: ctx0_rx */ 138362306a36Sopenharmony_ci sprintf(name, "ctx%c_%cx", index + '0', dir == IN ? 'r' : 't'); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci return dma_request_slave_channel(&easrc->pdev->dev, name); 138662306a36Sopenharmony_ci}; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cistatic const unsigned int easrc_rates[] = { 138962306a36Sopenharmony_ci 8000, 11025, 12000, 16000, 139062306a36Sopenharmony_ci 22050, 24000, 32000, 44100, 139162306a36Sopenharmony_ci 48000, 64000, 88200, 96000, 139262306a36Sopenharmony_ci 128000, 176400, 192000, 256000, 139362306a36Sopenharmony_ci 352800, 384000, 705600, 768000, 139462306a36Sopenharmony_ci}; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list easrc_rate_constraints = { 139762306a36Sopenharmony_ci .count = ARRAY_SIZE(easrc_rates), 139862306a36Sopenharmony_ci .list = easrc_rates, 139962306a36Sopenharmony_ci}; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_cistatic int fsl_easrc_startup(struct snd_pcm_substream *substream, 140262306a36Sopenharmony_ci struct snd_soc_dai *dai) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci return snd_pcm_hw_constraint_list(substream->runtime, 0, 140562306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 140662306a36Sopenharmony_ci &easrc_rate_constraints); 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic int fsl_easrc_trigger(struct snd_pcm_substream *substream, 141062306a36Sopenharmony_ci int cmd, struct snd_soc_dai *dai) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 141362306a36Sopenharmony_ci struct fsl_asrc_pair *ctx = runtime->private_data; 141462306a36Sopenharmony_ci int ret; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci switch (cmd) { 141762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 141862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 141962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 142062306a36Sopenharmony_ci ret = fsl_easrc_start_context(ctx); 142162306a36Sopenharmony_ci if (ret) 142262306a36Sopenharmony_ci return ret; 142362306a36Sopenharmony_ci break; 142462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 142562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 142662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 142762306a36Sopenharmony_ci ret = fsl_easrc_stop_context(ctx); 142862306a36Sopenharmony_ci if (ret) 142962306a36Sopenharmony_ci return ret; 143062306a36Sopenharmony_ci break; 143162306a36Sopenharmony_ci default: 143262306a36Sopenharmony_ci return -EINVAL; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci return 0; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic int fsl_easrc_hw_params(struct snd_pcm_substream *substream, 143962306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 144062306a36Sopenharmony_ci struct snd_soc_dai *dai) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci struct fsl_asrc *easrc = snd_soc_dai_get_drvdata(dai); 144362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 144462306a36Sopenharmony_ci struct device *dev = &easrc->pdev->dev; 144562306a36Sopenharmony_ci struct fsl_asrc_pair *ctx = runtime->private_data; 144662306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; 144762306a36Sopenharmony_ci unsigned int channels = params_channels(params); 144862306a36Sopenharmony_ci unsigned int rate = params_rate(params); 144962306a36Sopenharmony_ci snd_pcm_format_t format = params_format(params); 145062306a36Sopenharmony_ci int ret; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci ret = fsl_easrc_request_context(channels, ctx); 145362306a36Sopenharmony_ci if (ret) { 145462306a36Sopenharmony_ci dev_err(dev, "failed to request context\n"); 145562306a36Sopenharmony_ci return ret; 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci ctx_priv->ctx_streams |= BIT(substream->stream); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci /* 146162306a36Sopenharmony_ci * Set the input and output ratio so we can compute 146262306a36Sopenharmony_ci * the resampling ratio in RS_LOW/HIGH 146362306a36Sopenharmony_ci */ 146462306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 146562306a36Sopenharmony_ci ctx_priv->in_params.sample_rate = rate; 146662306a36Sopenharmony_ci ctx_priv->in_params.sample_format = format; 146762306a36Sopenharmony_ci ctx_priv->out_params.sample_rate = easrc->asrc_rate; 146862306a36Sopenharmony_ci ctx_priv->out_params.sample_format = easrc->asrc_format; 146962306a36Sopenharmony_ci } else { 147062306a36Sopenharmony_ci ctx_priv->out_params.sample_rate = rate; 147162306a36Sopenharmony_ci ctx_priv->out_params.sample_format = format; 147262306a36Sopenharmony_ci ctx_priv->in_params.sample_rate = easrc->asrc_rate; 147362306a36Sopenharmony_ci ctx_priv->in_params.sample_format = easrc->asrc_format; 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci ctx->channels = channels; 147762306a36Sopenharmony_ci ctx_priv->in_params.fifo_wtmk = 0x20; 147862306a36Sopenharmony_ci ctx_priv->out_params.fifo_wtmk = 0x20; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci /* 148162306a36Sopenharmony_ci * Do only rate conversion and keep the same format for input 148262306a36Sopenharmony_ci * and output data 148362306a36Sopenharmony_ci */ 148462306a36Sopenharmony_ci ret = fsl_easrc_set_ctx_format(ctx, 148562306a36Sopenharmony_ci &ctx_priv->in_params.sample_format, 148662306a36Sopenharmony_ci &ctx_priv->out_params.sample_format); 148762306a36Sopenharmony_ci if (ret) { 148862306a36Sopenharmony_ci dev_err(dev, "failed to set format %d", ret); 148962306a36Sopenharmony_ci return ret; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci ret = fsl_easrc_config_context(easrc, ctx->index); 149362306a36Sopenharmony_ci if (ret) { 149462306a36Sopenharmony_ci dev_err(dev, "failed to config context\n"); 149562306a36Sopenharmony_ci return ret; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci ctx_priv->in_params.iterations = 1; 149962306a36Sopenharmony_ci ctx_priv->in_params.group_len = ctx->channels; 150062306a36Sopenharmony_ci ctx_priv->in_params.access_len = ctx->channels; 150162306a36Sopenharmony_ci ctx_priv->out_params.iterations = 1; 150262306a36Sopenharmony_ci ctx_priv->out_params.group_len = ctx->channels; 150362306a36Sopenharmony_ci ctx_priv->out_params.access_len = ctx->channels; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci ret = fsl_easrc_set_ctx_organziation(ctx); 150662306a36Sopenharmony_ci if (ret) { 150762306a36Sopenharmony_ci dev_err(dev, "failed to set fifo organization\n"); 150862306a36Sopenharmony_ci return ret; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci return 0; 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_cistatic int fsl_easrc_hw_free(struct snd_pcm_substream *substream, 151562306a36Sopenharmony_ci struct snd_soc_dai *dai) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 151862306a36Sopenharmony_ci struct fsl_asrc_pair *ctx = runtime->private_data; 151962306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (!ctx) 152262306a36Sopenharmony_ci return -EINVAL; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci ctx_priv = ctx->private; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (ctx_priv->ctx_streams & BIT(substream->stream)) { 152762306a36Sopenharmony_ci ctx_priv->ctx_streams &= ~BIT(substream->stream); 152862306a36Sopenharmony_ci fsl_easrc_release_context(ctx); 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci return 0; 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_cistatic int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) 153562306a36Sopenharmony_ci{ 153662306a36Sopenharmony_ci struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci snd_soc_dai_init_dma_data(cpu_dai, 153962306a36Sopenharmony_ci &easrc->dma_params_tx, 154062306a36Sopenharmony_ci &easrc->dma_params_rx); 154162306a36Sopenharmony_ci return 0; 154262306a36Sopenharmony_ci} 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_cistatic const struct snd_soc_dai_ops fsl_easrc_dai_ops = { 154562306a36Sopenharmony_ci .probe = fsl_easrc_dai_probe, 154662306a36Sopenharmony_ci .startup = fsl_easrc_startup, 154762306a36Sopenharmony_ci .trigger = fsl_easrc_trigger, 154862306a36Sopenharmony_ci .hw_params = fsl_easrc_hw_params, 154962306a36Sopenharmony_ci .hw_free = fsl_easrc_hw_free, 155062306a36Sopenharmony_ci}; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_cistatic struct snd_soc_dai_driver fsl_easrc_dai = { 155362306a36Sopenharmony_ci .playback = { 155462306a36Sopenharmony_ci .stream_name = "ASRC-Playback", 155562306a36Sopenharmony_ci .channels_min = 1, 155662306a36Sopenharmony_ci .channels_max = 32, 155762306a36Sopenharmony_ci .rate_min = 8000, 155862306a36Sopenharmony_ci .rate_max = 768000, 155962306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 156062306a36Sopenharmony_ci .formats = FSL_EASRC_FORMATS, 156162306a36Sopenharmony_ci }, 156262306a36Sopenharmony_ci .capture = { 156362306a36Sopenharmony_ci .stream_name = "ASRC-Capture", 156462306a36Sopenharmony_ci .channels_min = 1, 156562306a36Sopenharmony_ci .channels_max = 32, 156662306a36Sopenharmony_ci .rate_min = 8000, 156762306a36Sopenharmony_ci .rate_max = 768000, 156862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 156962306a36Sopenharmony_ci .formats = FSL_EASRC_FORMATS | 157062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, 157162306a36Sopenharmony_ci }, 157262306a36Sopenharmony_ci .ops = &fsl_easrc_dai_ops, 157362306a36Sopenharmony_ci}; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_cistatic const struct snd_soc_component_driver fsl_easrc_component = { 157662306a36Sopenharmony_ci .name = "fsl-easrc-dai", 157762306a36Sopenharmony_ci .controls = fsl_easrc_snd_controls, 157862306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls), 157962306a36Sopenharmony_ci .legacy_dai_naming = 1, 158062306a36Sopenharmony_ci}; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cistatic const struct reg_default fsl_easrc_reg_defaults[] = { 158362306a36Sopenharmony_ci {REG_EASRC_WRFIFO(0), 0x00000000}, 158462306a36Sopenharmony_ci {REG_EASRC_WRFIFO(1), 0x00000000}, 158562306a36Sopenharmony_ci {REG_EASRC_WRFIFO(2), 0x00000000}, 158662306a36Sopenharmony_ci {REG_EASRC_WRFIFO(3), 0x00000000}, 158762306a36Sopenharmony_ci {REG_EASRC_RDFIFO(0), 0x00000000}, 158862306a36Sopenharmony_ci {REG_EASRC_RDFIFO(1), 0x00000000}, 158962306a36Sopenharmony_ci {REG_EASRC_RDFIFO(2), 0x00000000}, 159062306a36Sopenharmony_ci {REG_EASRC_RDFIFO(3), 0x00000000}, 159162306a36Sopenharmony_ci {REG_EASRC_CC(0), 0x00000000}, 159262306a36Sopenharmony_ci {REG_EASRC_CC(1), 0x00000000}, 159362306a36Sopenharmony_ci {REG_EASRC_CC(2), 0x00000000}, 159462306a36Sopenharmony_ci {REG_EASRC_CC(3), 0x00000000}, 159562306a36Sopenharmony_ci {REG_EASRC_CCE1(0), 0x00000000}, 159662306a36Sopenharmony_ci {REG_EASRC_CCE1(1), 0x00000000}, 159762306a36Sopenharmony_ci {REG_EASRC_CCE1(2), 0x00000000}, 159862306a36Sopenharmony_ci {REG_EASRC_CCE1(3), 0x00000000}, 159962306a36Sopenharmony_ci {REG_EASRC_CCE2(0), 0x00000000}, 160062306a36Sopenharmony_ci {REG_EASRC_CCE2(1), 0x00000000}, 160162306a36Sopenharmony_ci {REG_EASRC_CCE2(2), 0x00000000}, 160262306a36Sopenharmony_ci {REG_EASRC_CCE2(3), 0x00000000}, 160362306a36Sopenharmony_ci {REG_EASRC_CIA(0), 0x00000000}, 160462306a36Sopenharmony_ci {REG_EASRC_CIA(1), 0x00000000}, 160562306a36Sopenharmony_ci {REG_EASRC_CIA(2), 0x00000000}, 160662306a36Sopenharmony_ci {REG_EASRC_CIA(3), 0x00000000}, 160762306a36Sopenharmony_ci {REG_EASRC_DPCS0R0(0), 0x00000000}, 160862306a36Sopenharmony_ci {REG_EASRC_DPCS0R0(1), 0x00000000}, 160962306a36Sopenharmony_ci {REG_EASRC_DPCS0R0(2), 0x00000000}, 161062306a36Sopenharmony_ci {REG_EASRC_DPCS0R0(3), 0x00000000}, 161162306a36Sopenharmony_ci {REG_EASRC_DPCS0R1(0), 0x00000000}, 161262306a36Sopenharmony_ci {REG_EASRC_DPCS0R1(1), 0x00000000}, 161362306a36Sopenharmony_ci {REG_EASRC_DPCS0R1(2), 0x00000000}, 161462306a36Sopenharmony_ci {REG_EASRC_DPCS0R1(3), 0x00000000}, 161562306a36Sopenharmony_ci {REG_EASRC_DPCS0R2(0), 0x00000000}, 161662306a36Sopenharmony_ci {REG_EASRC_DPCS0R2(1), 0x00000000}, 161762306a36Sopenharmony_ci {REG_EASRC_DPCS0R2(2), 0x00000000}, 161862306a36Sopenharmony_ci {REG_EASRC_DPCS0R2(3), 0x00000000}, 161962306a36Sopenharmony_ci {REG_EASRC_DPCS0R3(0), 0x00000000}, 162062306a36Sopenharmony_ci {REG_EASRC_DPCS0R3(1), 0x00000000}, 162162306a36Sopenharmony_ci {REG_EASRC_DPCS0R3(2), 0x00000000}, 162262306a36Sopenharmony_ci {REG_EASRC_DPCS0R3(3), 0x00000000}, 162362306a36Sopenharmony_ci {REG_EASRC_DPCS1R0(0), 0x00000000}, 162462306a36Sopenharmony_ci {REG_EASRC_DPCS1R0(1), 0x00000000}, 162562306a36Sopenharmony_ci {REG_EASRC_DPCS1R0(2), 0x00000000}, 162662306a36Sopenharmony_ci {REG_EASRC_DPCS1R0(3), 0x00000000}, 162762306a36Sopenharmony_ci {REG_EASRC_DPCS1R1(0), 0x00000000}, 162862306a36Sopenharmony_ci {REG_EASRC_DPCS1R1(1), 0x00000000}, 162962306a36Sopenharmony_ci {REG_EASRC_DPCS1R1(2), 0x00000000}, 163062306a36Sopenharmony_ci {REG_EASRC_DPCS1R1(3), 0x00000000}, 163162306a36Sopenharmony_ci {REG_EASRC_DPCS1R2(0), 0x00000000}, 163262306a36Sopenharmony_ci {REG_EASRC_DPCS1R2(1), 0x00000000}, 163362306a36Sopenharmony_ci {REG_EASRC_DPCS1R2(2), 0x00000000}, 163462306a36Sopenharmony_ci {REG_EASRC_DPCS1R2(3), 0x00000000}, 163562306a36Sopenharmony_ci {REG_EASRC_DPCS1R3(0), 0x00000000}, 163662306a36Sopenharmony_ci {REG_EASRC_DPCS1R3(1), 0x00000000}, 163762306a36Sopenharmony_ci {REG_EASRC_DPCS1R3(2), 0x00000000}, 163862306a36Sopenharmony_ci {REG_EASRC_DPCS1R3(3), 0x00000000}, 163962306a36Sopenharmony_ci {REG_EASRC_COC(0), 0x00000000}, 164062306a36Sopenharmony_ci {REG_EASRC_COC(1), 0x00000000}, 164162306a36Sopenharmony_ci {REG_EASRC_COC(2), 0x00000000}, 164262306a36Sopenharmony_ci {REG_EASRC_COC(3), 0x00000000}, 164362306a36Sopenharmony_ci {REG_EASRC_COA(0), 0x00000000}, 164462306a36Sopenharmony_ci {REG_EASRC_COA(1), 0x00000000}, 164562306a36Sopenharmony_ci {REG_EASRC_COA(2), 0x00000000}, 164662306a36Sopenharmony_ci {REG_EASRC_COA(3), 0x00000000}, 164762306a36Sopenharmony_ci {REG_EASRC_SFS(0), 0x00000000}, 164862306a36Sopenharmony_ci {REG_EASRC_SFS(1), 0x00000000}, 164962306a36Sopenharmony_ci {REG_EASRC_SFS(2), 0x00000000}, 165062306a36Sopenharmony_ci {REG_EASRC_SFS(3), 0x00000000}, 165162306a36Sopenharmony_ci {REG_EASRC_RRL(0), 0x00000000}, 165262306a36Sopenharmony_ci {REG_EASRC_RRL(1), 0x00000000}, 165362306a36Sopenharmony_ci {REG_EASRC_RRL(2), 0x00000000}, 165462306a36Sopenharmony_ci {REG_EASRC_RRL(3), 0x00000000}, 165562306a36Sopenharmony_ci {REG_EASRC_RRH(0), 0x00000000}, 165662306a36Sopenharmony_ci {REG_EASRC_RRH(1), 0x00000000}, 165762306a36Sopenharmony_ci {REG_EASRC_RRH(2), 0x00000000}, 165862306a36Sopenharmony_ci {REG_EASRC_RRH(3), 0x00000000}, 165962306a36Sopenharmony_ci {REG_EASRC_RUC(0), 0x00000000}, 166062306a36Sopenharmony_ci {REG_EASRC_RUC(1), 0x00000000}, 166162306a36Sopenharmony_ci {REG_EASRC_RUC(2), 0x00000000}, 166262306a36Sopenharmony_ci {REG_EASRC_RUC(3), 0x00000000}, 166362306a36Sopenharmony_ci {REG_EASRC_RUR(0), 0x7FFFFFFF}, 166462306a36Sopenharmony_ci {REG_EASRC_RUR(1), 0x7FFFFFFF}, 166562306a36Sopenharmony_ci {REG_EASRC_RUR(2), 0x7FFFFFFF}, 166662306a36Sopenharmony_ci {REG_EASRC_RUR(3), 0x7FFFFFFF}, 166762306a36Sopenharmony_ci {REG_EASRC_RCTCL, 0x00000000}, 166862306a36Sopenharmony_ci {REG_EASRC_RCTCH, 0x00000000}, 166962306a36Sopenharmony_ci {REG_EASRC_PCF(0), 0x00000000}, 167062306a36Sopenharmony_ci {REG_EASRC_PCF(1), 0x00000000}, 167162306a36Sopenharmony_ci {REG_EASRC_PCF(2), 0x00000000}, 167262306a36Sopenharmony_ci {REG_EASRC_PCF(3), 0x00000000}, 167362306a36Sopenharmony_ci {REG_EASRC_CRCM, 0x00000000}, 167462306a36Sopenharmony_ci {REG_EASRC_CRCC, 0x00000000}, 167562306a36Sopenharmony_ci {REG_EASRC_IRQC, 0x00000FFF}, 167662306a36Sopenharmony_ci {REG_EASRC_IRQF, 0x00000000}, 167762306a36Sopenharmony_ci {REG_EASRC_CS0(0), 0x00000000}, 167862306a36Sopenharmony_ci {REG_EASRC_CS0(1), 0x00000000}, 167962306a36Sopenharmony_ci {REG_EASRC_CS0(2), 0x00000000}, 168062306a36Sopenharmony_ci {REG_EASRC_CS0(3), 0x00000000}, 168162306a36Sopenharmony_ci {REG_EASRC_CS1(0), 0x00000000}, 168262306a36Sopenharmony_ci {REG_EASRC_CS1(1), 0x00000000}, 168362306a36Sopenharmony_ci {REG_EASRC_CS1(2), 0x00000000}, 168462306a36Sopenharmony_ci {REG_EASRC_CS1(3), 0x00000000}, 168562306a36Sopenharmony_ci {REG_EASRC_CS2(0), 0x00000000}, 168662306a36Sopenharmony_ci {REG_EASRC_CS2(1), 0x00000000}, 168762306a36Sopenharmony_ci {REG_EASRC_CS2(2), 0x00000000}, 168862306a36Sopenharmony_ci {REG_EASRC_CS2(3), 0x00000000}, 168962306a36Sopenharmony_ci {REG_EASRC_CS3(0), 0x00000000}, 169062306a36Sopenharmony_ci {REG_EASRC_CS3(1), 0x00000000}, 169162306a36Sopenharmony_ci {REG_EASRC_CS3(2), 0x00000000}, 169262306a36Sopenharmony_ci {REG_EASRC_CS3(3), 0x00000000}, 169362306a36Sopenharmony_ci {REG_EASRC_CS4(0), 0x00000000}, 169462306a36Sopenharmony_ci {REG_EASRC_CS4(1), 0x00000000}, 169562306a36Sopenharmony_ci {REG_EASRC_CS4(2), 0x00000000}, 169662306a36Sopenharmony_ci {REG_EASRC_CS4(3), 0x00000000}, 169762306a36Sopenharmony_ci {REG_EASRC_CS5(0), 0x00000000}, 169862306a36Sopenharmony_ci {REG_EASRC_CS5(1), 0x00000000}, 169962306a36Sopenharmony_ci {REG_EASRC_CS5(2), 0x00000000}, 170062306a36Sopenharmony_ci {REG_EASRC_CS5(3), 0x00000000}, 170162306a36Sopenharmony_ci {REG_EASRC_DBGC, 0x00000000}, 170262306a36Sopenharmony_ci {REG_EASRC_DBGS, 0x00000000}, 170362306a36Sopenharmony_ci}; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic const struct regmap_range fsl_easrc_readable_ranges[] = { 170662306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RCTCH), 170762306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_PCF(3)), 170862306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_CRCC, REG_EASRC_DBGS), 170962306a36Sopenharmony_ci}; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic const struct regmap_access_table fsl_easrc_readable_table = { 171262306a36Sopenharmony_ci .yes_ranges = fsl_easrc_readable_ranges, 171362306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(fsl_easrc_readable_ranges), 171462306a36Sopenharmony_ci}; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_cistatic const struct regmap_range fsl_easrc_writeable_ranges[] = { 171762306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_WRFIFO(0), REG_EASRC_WRFIFO(3)), 171862306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_CC(0), REG_EASRC_COA(3)), 171962306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_RRL(0), REG_EASRC_RCTCH), 172062306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_DBGC), 172162306a36Sopenharmony_ci}; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_cistatic const struct regmap_access_table fsl_easrc_writeable_table = { 172462306a36Sopenharmony_ci .yes_ranges = fsl_easrc_writeable_ranges, 172562306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(fsl_easrc_writeable_ranges), 172662306a36Sopenharmony_ci}; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_cistatic const struct regmap_range fsl_easrc_volatileable_ranges[] = { 172962306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RDFIFO(3)), 173062306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_SFS(0), REG_EASRC_SFS(3)), 173162306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_IRQF, REG_EASRC_IRQF), 173262306a36Sopenharmony_ci regmap_reg_range(REG_EASRC_DBGS, REG_EASRC_DBGS), 173362306a36Sopenharmony_ci}; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_cistatic const struct regmap_access_table fsl_easrc_volatileable_table = { 173662306a36Sopenharmony_ci .yes_ranges = fsl_easrc_volatileable_ranges, 173762306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(fsl_easrc_volatileable_ranges), 173862306a36Sopenharmony_ci}; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_cistatic const struct regmap_config fsl_easrc_regmap_config = { 174162306a36Sopenharmony_ci .reg_bits = 32, 174262306a36Sopenharmony_ci .reg_stride = 4, 174362306a36Sopenharmony_ci .val_bits = 32, 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci .max_register = REG_EASRC_DBGS, 174662306a36Sopenharmony_ci .reg_defaults = fsl_easrc_reg_defaults, 174762306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(fsl_easrc_reg_defaults), 174862306a36Sopenharmony_ci .rd_table = &fsl_easrc_readable_table, 174962306a36Sopenharmony_ci .wr_table = &fsl_easrc_writeable_table, 175062306a36Sopenharmony_ci .volatile_table = &fsl_easrc_volatileable_table, 175162306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 175262306a36Sopenharmony_ci}; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci#ifdef DEBUG 175562306a36Sopenharmony_cistatic void fsl_easrc_dump_firmware(struct fsl_asrc *easrc) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 175862306a36Sopenharmony_ci struct asrc_firmware_hdr *firm = easrc_priv->firmware_hdr; 175962306a36Sopenharmony_ci struct interp_params *interp = easrc_priv->interp; 176062306a36Sopenharmony_ci struct prefil_params *prefil = easrc_priv->prefil; 176162306a36Sopenharmony_ci struct device *dev = &easrc->pdev->dev; 176262306a36Sopenharmony_ci int i; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if (firm->magic != FIRMWARE_MAGIC) { 176562306a36Sopenharmony_ci dev_err(dev, "Wrong magic. Something went wrong!"); 176662306a36Sopenharmony_ci return; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci dev_dbg(dev, "Firmware v%u dump:\n", firm->firmware_version); 177062306a36Sopenharmony_ci dev_dbg(dev, "Num prefilter scenarios: %u\n", firm->prefil_scen); 177162306a36Sopenharmony_ci dev_dbg(dev, "Num interpolation scenarios: %u\n", firm->interp_scen); 177262306a36Sopenharmony_ci dev_dbg(dev, "\nInterpolation scenarios:\n"); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci for (i = 0; i < firm->interp_scen; i++) { 177562306a36Sopenharmony_ci if (interp[i].magic != FIRMWARE_MAGIC) { 177662306a36Sopenharmony_ci dev_dbg(dev, "%d. wrong interp magic: %x\n", 177762306a36Sopenharmony_ci i, interp[i].magic); 177862306a36Sopenharmony_ci continue; 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci dev_dbg(dev, "%d. taps: %u, phases: %u, center: %llu\n", i, 178162306a36Sopenharmony_ci interp[i].num_taps, interp[i].num_phases, 178262306a36Sopenharmony_ci interp[i].center_tap); 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci for (i = 0; i < firm->prefil_scen; i++) { 178662306a36Sopenharmony_ci if (prefil[i].magic != FIRMWARE_MAGIC) { 178762306a36Sopenharmony_ci dev_dbg(dev, "%d. wrong prefil magic: %x\n", 178862306a36Sopenharmony_ci i, prefil[i].magic); 178962306a36Sopenharmony_ci continue; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci dev_dbg(dev, "%d. insr: %u, outsr: %u, st1: %u, st2: %u\n", i, 179262306a36Sopenharmony_ci prefil[i].insr, prefil[i].outsr, 179362306a36Sopenharmony_ci prefil[i].st1_taps, prefil[i].st2_taps); 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci dev_dbg(dev, "end of firmware dump\n"); 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci#endif 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_cistatic int fsl_easrc_get_firmware(struct fsl_asrc *easrc) 180162306a36Sopenharmony_ci{ 180262306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv; 180362306a36Sopenharmony_ci const struct firmware **fw_p; 180462306a36Sopenharmony_ci u32 pnum, inum, offset; 180562306a36Sopenharmony_ci const u8 *data; 180662306a36Sopenharmony_ci int ret; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci if (!easrc) 180962306a36Sopenharmony_ci return -EINVAL; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci easrc_priv = easrc->private; 181262306a36Sopenharmony_ci fw_p = &easrc_priv->fw; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci ret = request_firmware(fw_p, easrc_priv->fw_name, &easrc->pdev->dev); 181562306a36Sopenharmony_ci if (ret) 181662306a36Sopenharmony_ci return ret; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci data = easrc_priv->fw->data; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci easrc_priv->firmware_hdr = (struct asrc_firmware_hdr *)data; 182162306a36Sopenharmony_ci pnum = easrc_priv->firmware_hdr->prefil_scen; 182262306a36Sopenharmony_ci inum = easrc_priv->firmware_hdr->interp_scen; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci if (inum) { 182562306a36Sopenharmony_ci offset = sizeof(struct asrc_firmware_hdr); 182662306a36Sopenharmony_ci easrc_priv->interp = (struct interp_params *)(data + offset); 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci if (pnum) { 183062306a36Sopenharmony_ci offset = sizeof(struct asrc_firmware_hdr) + 183162306a36Sopenharmony_ci inum * sizeof(struct interp_params); 183262306a36Sopenharmony_ci easrc_priv->prefil = (struct prefil_params *)(data + offset); 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci#ifdef DEBUG 183662306a36Sopenharmony_ci fsl_easrc_dump_firmware(easrc); 183762306a36Sopenharmony_ci#endif 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_cistatic irqreturn_t fsl_easrc_isr(int irq, void *dev_id) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci struct fsl_asrc *easrc = (struct fsl_asrc *)dev_id; 184562306a36Sopenharmony_ci struct device *dev = &easrc->pdev->dev; 184662306a36Sopenharmony_ci int val; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci regmap_read(easrc->regmap, REG_EASRC_IRQF, &val); 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci if (val & EASRC_IRQF_OER_MASK) 185162306a36Sopenharmony_ci dev_dbg(dev, "output FIFO underflow\n"); 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (val & EASRC_IRQF_IFO_MASK) 185462306a36Sopenharmony_ci dev_dbg(dev, "input FIFO overflow\n"); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci return IRQ_HANDLED; 185762306a36Sopenharmony_ci} 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_cistatic int fsl_easrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci return REG_EASRC_FIFO(dir, index); 186262306a36Sopenharmony_ci} 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_cistatic const struct of_device_id fsl_easrc_dt_ids[] = { 186562306a36Sopenharmony_ci { .compatible = "fsl,imx8mn-easrc",}, 186662306a36Sopenharmony_ci {} 186762306a36Sopenharmony_ci}; 186862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_easrc_dt_ids); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_cistatic int fsl_easrc_probe(struct platform_device *pdev) 187162306a36Sopenharmony_ci{ 187262306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv; 187362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 187462306a36Sopenharmony_ci struct fsl_asrc *easrc; 187562306a36Sopenharmony_ci struct resource *res; 187662306a36Sopenharmony_ci struct device_node *np; 187762306a36Sopenharmony_ci void __iomem *regs; 187862306a36Sopenharmony_ci u32 asrc_fmt = 0; 187962306a36Sopenharmony_ci int ret, irq; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL); 188262306a36Sopenharmony_ci if (!easrc) 188362306a36Sopenharmony_ci return -ENOMEM; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci easrc_priv = devm_kzalloc(dev, sizeof(*easrc_priv), GFP_KERNEL); 188662306a36Sopenharmony_ci if (!easrc_priv) 188762306a36Sopenharmony_ci return -ENOMEM; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci easrc->pdev = pdev; 189062306a36Sopenharmony_ci easrc->private = easrc_priv; 189162306a36Sopenharmony_ci np = dev->of_node; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 189462306a36Sopenharmony_ci if (IS_ERR(regs)) 189562306a36Sopenharmony_ci return PTR_ERR(regs); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci easrc->paddr = res->start; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci easrc->regmap = devm_regmap_init_mmio(dev, regs, &fsl_easrc_regmap_config); 190062306a36Sopenharmony_ci if (IS_ERR(easrc->regmap)) { 190162306a36Sopenharmony_ci dev_err(dev, "failed to init regmap"); 190262306a36Sopenharmony_ci return PTR_ERR(easrc->regmap); 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 190662306a36Sopenharmony_ci if (irq < 0) 190762306a36Sopenharmony_ci return irq; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, fsl_easrc_isr, 0, 191062306a36Sopenharmony_ci dev_name(dev), easrc); 191162306a36Sopenharmony_ci if (ret) { 191262306a36Sopenharmony_ci dev_err(dev, "failed to claim irq %u: %d\n", irq, ret); 191362306a36Sopenharmony_ci return ret; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci easrc->mem_clk = devm_clk_get(dev, "mem"); 191762306a36Sopenharmony_ci if (IS_ERR(easrc->mem_clk)) { 191862306a36Sopenharmony_ci dev_err(dev, "failed to get mem clock\n"); 191962306a36Sopenharmony_ci return PTR_ERR(easrc->mem_clk); 192062306a36Sopenharmony_ci } 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci /* Set default value */ 192362306a36Sopenharmony_ci easrc->channel_avail = 32; 192462306a36Sopenharmony_ci easrc->get_dma_channel = fsl_easrc_get_dma_channel; 192562306a36Sopenharmony_ci easrc->request_pair = fsl_easrc_request_context; 192662306a36Sopenharmony_ci easrc->release_pair = fsl_easrc_release_context; 192762306a36Sopenharmony_ci easrc->get_fifo_addr = fsl_easrc_get_fifo_addr; 192862306a36Sopenharmony_ci easrc->pair_priv_size = sizeof(struct fsl_easrc_ctx_priv); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci easrc_priv->rs_num_taps = EASRC_RS_32_TAPS; 193162306a36Sopenharmony_ci easrc_priv->const_coeff = 0x3FF0000000000000; 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-rate", &easrc->asrc_rate); 193462306a36Sopenharmony_ci if (ret) { 193562306a36Sopenharmony_ci dev_err(dev, "failed to asrc rate\n"); 193662306a36Sopenharmony_ci return ret; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); 194062306a36Sopenharmony_ci easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; 194162306a36Sopenharmony_ci if (ret) { 194262306a36Sopenharmony_ci dev_err(dev, "failed to asrc format\n"); 194362306a36Sopenharmony_ci return ret; 194462306a36Sopenharmony_ci } 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci if (!(FSL_EASRC_FORMATS & (pcm_format_to_bits(easrc->asrc_format)))) { 194762306a36Sopenharmony_ci dev_warn(dev, "unsupported format, switching to S24_LE\n"); 194862306a36Sopenharmony_ci easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci ret = of_property_read_string(np, "firmware-name", 195262306a36Sopenharmony_ci &easrc_priv->fw_name); 195362306a36Sopenharmony_ci if (ret) { 195462306a36Sopenharmony_ci dev_err(dev, "failed to get firmware name\n"); 195562306a36Sopenharmony_ci return ret; 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci platform_set_drvdata(pdev, easrc); 195962306a36Sopenharmony_ci pm_runtime_enable(dev); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci spin_lock_init(&easrc->lock); 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci regcache_cache_only(easrc->regmap, true); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &fsl_easrc_component, 196662306a36Sopenharmony_ci &fsl_easrc_dai, 1); 196762306a36Sopenharmony_ci if (ret) { 196862306a36Sopenharmony_ci dev_err(dev, "failed to register ASoC DAI\n"); 196962306a36Sopenharmony_ci goto err_pm_disable; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &fsl_asrc_component, 197362306a36Sopenharmony_ci NULL, 0); 197462306a36Sopenharmony_ci if (ret) { 197562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register ASoC platform\n"); 197662306a36Sopenharmony_ci goto err_pm_disable; 197762306a36Sopenharmony_ci } 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci return 0; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_cierr_pm_disable: 198262306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 198362306a36Sopenharmony_ci return ret; 198462306a36Sopenharmony_ci} 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_cistatic void fsl_easrc_remove(struct platform_device *pdev) 198762306a36Sopenharmony_ci{ 198862306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 198962306a36Sopenharmony_ci} 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_cistatic __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev) 199262306a36Sopenharmony_ci{ 199362306a36Sopenharmony_ci struct fsl_asrc *easrc = dev_get_drvdata(dev); 199462306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 199562306a36Sopenharmony_ci unsigned long lock_flags; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci regcache_cache_only(easrc->regmap, true); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci clk_disable_unprepare(easrc->mem_clk); 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci spin_lock_irqsave(&easrc->lock, lock_flags); 200262306a36Sopenharmony_ci easrc_priv->firmware_loaded = 0; 200362306a36Sopenharmony_ci spin_unlock_irqrestore(&easrc->lock, lock_flags); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci return 0; 200662306a36Sopenharmony_ci} 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_cistatic __maybe_unused int fsl_easrc_runtime_resume(struct device *dev) 200962306a36Sopenharmony_ci{ 201062306a36Sopenharmony_ci struct fsl_asrc *easrc = dev_get_drvdata(dev); 201162306a36Sopenharmony_ci struct fsl_easrc_priv *easrc_priv = easrc->private; 201262306a36Sopenharmony_ci struct fsl_easrc_ctx_priv *ctx_priv; 201362306a36Sopenharmony_ci struct fsl_asrc_pair *ctx; 201462306a36Sopenharmony_ci unsigned long lock_flags; 201562306a36Sopenharmony_ci int ret; 201662306a36Sopenharmony_ci int i; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci ret = clk_prepare_enable(easrc->mem_clk); 201962306a36Sopenharmony_ci if (ret) 202062306a36Sopenharmony_ci return ret; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci regcache_cache_only(easrc->regmap, false); 202362306a36Sopenharmony_ci regcache_mark_dirty(easrc->regmap); 202462306a36Sopenharmony_ci regcache_sync(easrc->regmap); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci spin_lock_irqsave(&easrc->lock, lock_flags); 202762306a36Sopenharmony_ci if (easrc_priv->firmware_loaded) { 202862306a36Sopenharmony_ci spin_unlock_irqrestore(&easrc->lock, lock_flags); 202962306a36Sopenharmony_ci goto skip_load; 203062306a36Sopenharmony_ci } 203162306a36Sopenharmony_ci easrc_priv->firmware_loaded = 1; 203262306a36Sopenharmony_ci spin_unlock_irqrestore(&easrc->lock, lock_flags); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci ret = fsl_easrc_get_firmware(easrc); 203562306a36Sopenharmony_ci if (ret) { 203662306a36Sopenharmony_ci dev_err(dev, "failed to get firmware\n"); 203762306a36Sopenharmony_ci goto disable_mem_clk; 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci /* 204162306a36Sopenharmony_ci * Write Resampling Coefficients 204262306a36Sopenharmony_ci * The coefficient RAM must be configured prior to beginning of 204362306a36Sopenharmony_ci * any context processing within the ASRC 204462306a36Sopenharmony_ci */ 204562306a36Sopenharmony_ci ret = fsl_easrc_resampler_config(easrc); 204662306a36Sopenharmony_ci if (ret) { 204762306a36Sopenharmony_ci dev_err(dev, "resampler config failed\n"); 204862306a36Sopenharmony_ci goto disable_mem_clk; 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) { 205262306a36Sopenharmony_ci ctx = easrc->pair[i]; 205362306a36Sopenharmony_ci if (!ctx) 205462306a36Sopenharmony_ci continue; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci ctx_priv = ctx->private; 205762306a36Sopenharmony_ci fsl_easrc_set_rs_ratio(ctx); 205862306a36Sopenharmony_ci ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * 205962306a36Sopenharmony_ci ctx_priv->out_params.sample_rate / 206062306a36Sopenharmony_ci ctx_priv->in_params.sample_rate; 206162306a36Sopenharmony_ci if (ctx_priv->in_filled_sample * ctx_priv->out_params.sample_rate 206262306a36Sopenharmony_ci % ctx_priv->in_params.sample_rate != 0) 206362306a36Sopenharmony_ci ctx_priv->out_missed_sample += 1; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci ret = fsl_easrc_write_pf_coeff_mem(easrc, i, 206662306a36Sopenharmony_ci ctx_priv->st1_coeff, 206762306a36Sopenharmony_ci ctx_priv->st1_num_taps, 206862306a36Sopenharmony_ci ctx_priv->st1_addexp); 206962306a36Sopenharmony_ci if (ret) 207062306a36Sopenharmony_ci goto disable_mem_clk; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci ret = fsl_easrc_write_pf_coeff_mem(easrc, i, 207362306a36Sopenharmony_ci ctx_priv->st2_coeff, 207462306a36Sopenharmony_ci ctx_priv->st2_num_taps, 207562306a36Sopenharmony_ci ctx_priv->st2_addexp); 207662306a36Sopenharmony_ci if (ret) 207762306a36Sopenharmony_ci goto disable_mem_clk; 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ciskip_load: 208162306a36Sopenharmony_ci return 0; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_cidisable_mem_clk: 208462306a36Sopenharmony_ci clk_disable_unprepare(easrc->mem_clk); 208562306a36Sopenharmony_ci return ret; 208662306a36Sopenharmony_ci} 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_cistatic const struct dev_pm_ops fsl_easrc_pm_ops = { 208962306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, 209062306a36Sopenharmony_ci fsl_easrc_runtime_resume, 209162306a36Sopenharmony_ci NULL) 209262306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 209362306a36Sopenharmony_ci pm_runtime_force_resume) 209462306a36Sopenharmony_ci}; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_cistatic struct platform_driver fsl_easrc_driver = { 209762306a36Sopenharmony_ci .probe = fsl_easrc_probe, 209862306a36Sopenharmony_ci .remove_new = fsl_easrc_remove, 209962306a36Sopenharmony_ci .driver = { 210062306a36Sopenharmony_ci .name = "fsl-easrc", 210162306a36Sopenharmony_ci .pm = &fsl_easrc_pm_ops, 210262306a36Sopenharmony_ci .of_match_table = fsl_easrc_dt_ids, 210362306a36Sopenharmony_ci }, 210462306a36Sopenharmony_ci}; 210562306a36Sopenharmony_cimodule_platform_driver(fsl_easrc_driver); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ciMODULE_DESCRIPTION("NXP Enhanced Asynchronous Sample Rate (eASRC) driver"); 210862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2109