sound/soc/codecs/wm8804.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/wm8804.c
Extension
.c
Size
18328 bytes
Lines
723
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 wm8804_priv {
	struct device *dev;
	struct regmap *regmap;
	struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
	struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
	int mclk_div;

	struct gpio_desc *reset;

	int aif_pwr;
};

static int txsrc_put(struct snd_kcontrol *kcontrol,
		     struct snd_ctl_elem_value *ucontrol);

static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
			    struct snd_kcontrol *kcontrol, int event);

/*
 * We can't use the same notifier block for more than one supply and
 * there's no way I can see to get from a callback to the caller
 * except container_of().
 */
#define WM8804_REGULATOR_EVENT(n) \
static int wm8804_regulator_event_##n(struct notifier_block *nb, \
				      unsigned long event, void *data)    \
{ \
	struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
						  disable_nb[n]); \
	if (event & REGULATOR_EVENT_DISABLE) { \
		regcache_mark_dirty(wm8804->regmap);	\
	} \
	return 0; \
}

WM8804_REGULATOR_EVENT(0)
WM8804_REGULATOR_EVENT(1)

static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
static SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text);

static const struct snd_kcontrol_new wm8804_tx_source_mux[] = {
	SOC_DAPM_ENUM_EXT("Input Source", txsrc,
			  snd_soc_dapm_get_enum_double, txsrc_put),
};

static const struct snd_soc_dapm_widget wm8804_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("SPDIF Out"),
SND_SOC_DAPM_INPUT("SPDIF In"),

SND_SOC_DAPM_PGA("SPDIFTX", WM8804_PWRDN, 2, 1, NULL, 0),
SND_SOC_DAPM_PGA("SPDIFRX", WM8804_PWRDN, 1, 1, NULL, 0),

SND_SOC_DAPM_MUX("Tx Source", SND_SOC_NOPM, 6, 0, wm8804_tx_source_mux),

SND_SOC_DAPM_AIF_OUT_E("AIFTX", NULL, 0, SND_SOC_NOPM, 0, 0, wm8804_aif_event,
		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_AIF_IN_E("AIFRX", NULL, 0, SND_SOC_NOPM, 0, 0, wm8804_aif_event,
		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
};

static const struct snd_soc_dapm_route wm8804_dapm_routes[] = {
	{ "AIFRX", NULL, "Playback" },
	{ "Tx Source", "AIF", "AIFRX" },

	{ "SPDIFRX", NULL, "SPDIF In" },
	{ "Tx Source", "S/PDIF RX", "SPDIFRX" },

	{ "SPDIFTX", NULL, "Tx Source" },
	{ "SPDIF Out", NULL, "SPDIFTX" },

	{ "AIFTX", NULL, "SPDIFRX" },
	{ "Capture", NULL, "AIFTX" },
};

static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
			    struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
	struct wm8804_priv *wm8804 = snd_soc_component_get_drvdata(component);

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		/* power up the aif */
		if (!wm8804->aif_pwr)
			snd_soc_component_update_bits(component, WM8804_PWRDN, 0x10, 0x0);
		wm8804->aif_pwr++;
		break;
	case SND_SOC_DAPM_POST_PMD:
		/* power down only both paths are disabled */

Annotation

Implementation Notes