sound/soc/meson/g12a-toacodec.c

Source file repositories/reference/linux-study-clean/sound/soc/meson/g12a-toacodec.c

File Facts

System
Linux kernel
Corpus path
sound/soc/meson/g12a-toacodec.c
Extension
.c
Size
10840 bytes
Lines
357
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 g12a_toacodec {
	struct regmap_field *field_dat_sel;
	struct regmap_field *field_lrclk_sel;
	struct regmap_field *field_bclk_sel;
};

struct g12a_toacodec_match_data {
	const struct snd_soc_component_driver *component_drv;
	struct reg_field field_dat_sel;
	struct reg_field field_lrclk_sel;
	struct reg_field field_bclk_sel;
};

static const char * const g12a_toacodec_mux_texts[] = {
	"I2S A", "I2S B", "I2S C",
};

static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol,
				      struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
	struct g12a_toacodec *priv = snd_soc_component_get_drvdata(component);
	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
	unsigned int mux, reg;

	if (ucontrol->value.enumerated.item[0] >= e->items)
		return -EINVAL;

	mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
	regmap_field_read(priv->field_dat_sel, &reg);

	if (mux == reg)
		return 0;

	/* Force disconnect of the mux while updating */
	snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);

	regmap_field_write(priv->field_dat_sel, mux);
	regmap_field_write(priv->field_lrclk_sel, mux);
	regmap_field_write(priv->field_bclk_sel, mux);

	/*
	 * FIXME:
	 * On this soc, the glue gets the MCLK directly from the clock
	 * controller instead of going the through the TDM interface.
	 *
	 * Here we assume interface A uses clock A, etc ... While it is
	 * true for now, it could be different. Instead the glue should
	 * find out the clock used by the interface and select the same
	 * source. For that, we will need regmap backed clock mux which
	 * is a work in progress
	 */
	snd_soc_component_update_bits(component, e->reg,
				      CTRL0_MCLK_SEL,
				      FIELD_PREP(CTRL0_MCLK_SEL, mux));

	snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);

	return 1;
}

static SOC_ENUM_SINGLE_DECL(g12a_toacodec_mux_enum, TOACODEC_CTRL0,
			    CTRL0_DAT_SEL_LSB,
			    g12a_toacodec_mux_texts);

static SOC_ENUM_SINGLE_DECL(sm1_toacodec_mux_enum, TOACODEC_CTRL0,
			    CTRL0_DAT_SEL_SM1_LSB,
			    g12a_toacodec_mux_texts);

static const struct snd_kcontrol_new g12a_toacodec_mux =
	SOC_DAPM_ENUM_EXT("Source", g12a_toacodec_mux_enum,
			  snd_soc_dapm_get_enum_double,
			  g12a_toacodec_mux_put_enum);

static const struct snd_kcontrol_new sm1_toacodec_mux =
	SOC_DAPM_ENUM_EXT("Source", sm1_toacodec_mux_enum,
			  snd_soc_dapm_get_enum_double,
			  g12a_toacodec_mux_put_enum);

static const struct snd_kcontrol_new g12a_toacodec_out_enable =
	SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOACODEC_CTRL0,
				    CTRL0_ENABLE_SHIFT, 1, 0);

static const struct snd_soc_dapm_widget g12a_toacodec_widgets[] = {
	SND_SOC_DAPM_MUX("SRC", SND_SOC_NOPM, 0, 0,
			 &g12a_toacodec_mux),
	SND_SOC_DAPM_SWITCH("OUT EN", SND_SOC_NOPM, 0, 0,
			    &g12a_toacodec_out_enable),
};

Annotation

Implementation Notes