sound/soc/fsl/fsl_mqs.c

Source file repositories/reference/linux-study-clean/sound/soc/fsl/fsl_mqs.c

File Facts

System
Linux kernel
Corpus path
sound/soc/fsl/fsl_mqs.c
Extension
.c
Size
12233 bytes
Lines
472
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct fsl_mqs_soc_data {
	enum reg_type type;
	int  sm_index;
	int  ctrl_off;
	int  en_mask;
	int  en_shift;
	int  rst_mask;
	int  rst_shift;
	int  osr_mask;
	int  osr_shift;
	int  div_mask;
	int  div_shift;
};

/* codec private data */
struct fsl_mqs {
	struct regmap *regmap;
	struct clk *mclk;
	struct clk *ipg;
	const struct fsl_mqs_soc_data *soc;

	unsigned int reg_mqs_ctrl;
};

#define FSL_MQS_RATES	(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
#define FSL_MQS_FORMATS	SNDRV_PCM_FMTBIT_S16_LE

static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val)
{
	struct fsl_mqs *mqs_priv = context;
	int num = 1;

	if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) &&
	    mqs_priv->soc->ctrl_off == reg)
		return scmi_imx_misc_ctrl_get(mqs_priv->soc->sm_index, &num, val);

	return -EINVAL;
};

static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val)
{
	struct fsl_mqs *mqs_priv = context;

	if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) &&
	    mqs_priv->soc->ctrl_off == reg)
		return scmi_imx_misc_ctrl_set(mqs_priv->soc->sm_index, val);

	return -EINVAL;
};

static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params,
			     struct snd_soc_dai *dai)
{
	struct snd_soc_component *component = dai->component;
	struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
	unsigned long mclk_rate;
	int div, res;
	int lrclk;

	mclk_rate = clk_get_rate(mqs_priv->mclk);
	lrclk = params_rate(params);

	/*
	 * mclk_rate / (oversample(32,64) * FS * 2 * divider ) = repeat_rate;
	 * if repeat_rate is 8, mqs can achieve better quality.
	 * oversample rate is fix to 32 currently.
	 */
	div = mclk_rate / (32 * lrclk * 2 * 8);
	res = mclk_rate % (32 * lrclk * 2 * 8);

	if (res == 0 && div > 0 && div <= 256) {
		regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
				   mqs_priv->soc->div_mask,
				   (div - 1) << mqs_priv->soc->div_shift);
		regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
				   mqs_priv->soc->osr_mask, 0);
	} else {
		dev_err(component->dev, "can't get proper divider\n");
	}

	return 0;
}

static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
	/* Only LEFT_J & SLAVE mode is supported. */
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_LEFT_J:
		break;

Annotation

Implementation Notes