sound/soc/sophgo/cv1800b-sound-adc.c

Source file repositories/reference/linux-study-clean/sound/soc/sophgo/cv1800b-sound-adc.c

File Facts

System
Linux kernel
Corpus path
sound/soc/sophgo/cv1800b-sound-adc.c
Extension
.c
Size
8772 bytes
Lines
320
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 cv1800b_priv {
	void __iomem *regs;
	struct device *dev;
	unsigned int mclk_rate;
};

static int cv1800b_adc_setbclk_div(struct cv1800b_priv *priv, unsigned int rate)
{
	u32 val;
	u32 bclk_div;
	u64 tmp;

	if (!priv->mclk_rate || !rate)
		return -EINVAL;

	tmp = div_u64(priv->mclk_rate, CV1800B_RXADC_WORD_LEN *
		      CV1800B_RXADC_CHANNELS * rate * 2);

	if (!tmp) {
		dev_err(priv->dev, "computed BCLK divider is zero\n");
		return -EINVAL;
	}

	if (tmp > 256) {
		dev_err(priv->dev, "BCLK divider %llu out of range\n", tmp);
		return -EINVAL;
	}

	bclk_div = tmp - 1;
	val = readl(priv->regs + CV1800B_RXADC_CLK);
	val = u32_replace_bits(val, bclk_div, REG_RXADC_SCK_DIV);
	/* Vendor value for 48kHz, tested on SG2000/SG2002 */
	val = u32_replace_bits(val, 0x19, REG_RXADC_DLYEN);
	writel(val, priv->regs + CV1800B_RXADC_CLK);

	return 0;
}

static void cv1800b_adc_enable(struct cv1800b_priv *priv, bool enable)
{
	u32 val;

	val = readl(priv->regs + CV1800B_RXADC_CTRL0);
	val = u32_replace_bits(val, enable, REG_RXADC_EN);
	val = u32_replace_bits(val, enable, REG_I2S_TX_EN);
	writel(val, priv->regs + CV1800B_RXADC_CTRL0);
}

static unsigned int cv1800b_adc_calc_db(u32 ana0, bool right)
{
	u32 step_mask = right ? FIELD_GET(REG_GSTEPR_RXPGA, ana0) :
				FIELD_GET(REG_GSTEPL_RXPGA, ana0);
	u32 coarse = right ? FIELD_GET(REG_GAINR_RXADC, ana0) :
			     FIELD_GET(REG_GAINL_RXADC, ana0);
	bool g6db = right ? FIELD_GET(REG_G6DBR_RXPGA, ana0) :
			    FIELD_GET(REG_G6DBL_RXPGA, ana0);

	u32 step = step_mask ? __ffs(step_mask) : 0;

	step = min(step, 12U);
	coarse = min(coarse, 3U);

	return 2 * step + 6 * coarse + (g6db ? 6 : 0);
}

static int cv1800b_adc_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params,
				 struct snd_soc_dai *dai)
{
	struct cv1800b_priv *priv = snd_soc_dai_get_drvdata(dai);
	unsigned int rate = params_rate(params);
	u32 val;
	int ret;

	ret = cv1800b_adc_setbclk_div(priv, rate);
	if (ret) {
		dev_err(priv->dev,
			"could not set rate, check DT node for fixed clock\n");
		return ret;
	}

	/* init adc */
	val = readl(priv->regs + CV1800B_RXADCC_CTRL1);
	val = u32_replace_bits(val, 1, REG_RXADC_IGR_INIT);
	val = u32_replace_bits(val, DECIMATION_64, REG_RXADC_CIC_OPT);
	writel(val, priv->regs + CV1800B_RXADCC_CTRL1);
	return 0;
}

static int cv1800b_adc_dai_trigger(struct snd_pcm_substream *substream, int cmd,

Annotation

Implementation Notes