sound/soc/codecs/cs40l50-codec.c

Source file repositories/reference/linux-study-clean/sound/soc/codecs/cs40l50-codec.c

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/cs40l50-codec.c
Extension
.c
Size
8069 bytes
Lines
308
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 cs40l50_pll_config {
	unsigned int freq;
	unsigned int cfg;
};

struct cs40l50_codec {
	struct device *dev;
	struct regmap *regmap;
	unsigned int daifmt;
	unsigned int bclk_ratio;
	unsigned int rate;
};

static const struct cs40l50_pll_config cs40l50_pll_cfg[] = {
	{ 32768, 0x00 },
	{ 1536000, 0x1B },
	{ 3072000, 0x21 },
	{ 6144000, 0x28 },
	{ 9600000, 0x30 },
	{ 12288000, 0x33 },
};

static int cs40l50_get_clk_config(const unsigned int freq, unsigned int *cfg)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(cs40l50_pll_cfg); i++) {
		if (cs40l50_pll_cfg[i].freq == freq) {
			*cfg = cs40l50_pll_cfg[i].cfg;
			return 0;
		}
	}

	return -EINVAL;
}

static int cs40l50_swap_ext_clk(struct cs40l50_codec *codec, const unsigned int clk_src)
{
	unsigned int cfg;
	int ret;

	switch (clk_src) {
	case CS40L50_PLL_REFCLK_BCLK:
		ret = cs40l50_get_clk_config(codec->bclk_ratio * codec->rate, &cfg);
		if (ret)
			return ret;
		break;
	case CS40L50_PLL_REFCLK_MCLK:
		cfg = CS40L50_PLL_REEFCLK_MCLK_CFG;
		break;
	default:
		return -EINVAL;
	}

	ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
				 CS40L50_PLL_REFCLK_LOOP_MASK,
				 CS40L50_PLL_REFCLK_OPEN_LOOP <<
				 CS40L50_PLL_REFCLK_LOOP_SHIFT);
	if (ret)
		return ret;

	ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
				 CS40L50_PLL_REFCLK_FREQ_MASK |
				 CS40L50_PLL_REFCLK_SEL_MASK,
				 (cfg << CS40L50_PLL_REFCLK_FREQ_SHIFT) | clk_src);
	if (ret)
		return ret;

	return regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
				  CS40L50_PLL_REFCLK_LOOP_MASK,
				  CS40L50_PLL_REFCLK_CLOSED_LOOP <<
				  CS40L50_PLL_REFCLK_LOOP_SHIFT);
}

static int cs40l50_clk_en(struct snd_soc_dapm_widget *w,
			  struct snd_kcontrol *kcontrol,
			  int event)
{
	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
	struct cs40l50_codec *codec = snd_soc_component_get_drvdata(comp);
	int ret;

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_STOP_PLAYBACK);
		if (ret)
			return ret;

		ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_START_I2S);
		if (ret)

Annotation

Implementation Notes