sound/soc/intel/boards/bytcr_wm5102.c

Source file repositories/reference/linux-study-clean/sound/soc/intel/boards/bytcr_wm5102.c

File Facts

System
Linux kernel
Corpus path
sound/soc/intel/boards/bytcr_wm5102.c
Extension
.c
Size
19981 bytes
Lines
672
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 byt_wm5102_private {
	struct snd_soc_jack jack;
	struct clk *mclk;
	struct gpio_desc *spkvdd_en_gpio;
	int mclk_freq;
};

#define BYT_WM5102_IN_MAP		GENMASK(3, 0)
#define BYT_WM5102_OUT_MAP		GENMASK(7, 4)
#define BYT_WM5102_SSP2			BIT(16)
#define BYT_WM5102_MCLK_19_2MHZ		BIT(17)

enum {
	BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L,
	BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L,
};

/* Note these values are pre-shifted for easy use of setting quirks */
enum {
	BYT_WM5102_SPK_SPK_MAP		= FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 0),
	BYT_WM5102_SPK_HPOUT2_MAP	= FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 1),
};

static unsigned long quirk;

static int quirk_override = -1;
module_param_named(quirk, quirk_override, int, 0444);
MODULE_PARM_DESC(quirk, "Board-specific quirk override");

static void log_quirks(struct device *dev)
{
	switch (quirk & BYT_WM5102_IN_MAP) {
	case BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L:
		dev_info_once(dev, "quirk INTMIC_IN3L_HSMIC_IN1L enabled\n");
		break;
	case BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L:
		dev_info_once(dev, "quirk INTMIC_IN1L_HSMIC_IN2L enabled\n");
		break;
	default:
		dev_warn_once(dev, "quirk sets invalid input map: 0x%lx, defaulting to INTMIC_IN3L_HSMIC_IN1L\n",
			      quirk & BYT_WM5102_IN_MAP);
		quirk &= ~BYT_WM5102_IN_MAP;
		quirk |= BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L;
		break;
	}
	switch (quirk & BYT_WM5102_OUT_MAP) {
	case BYT_WM5102_SPK_SPK_MAP:
		dev_info_once(dev, "quirk SPK_SPK_MAP enabled\n");
		break;
	case BYT_WM5102_SPK_HPOUT2_MAP:
		dev_info_once(dev, "quirk SPK_HPOUT2_MAP enabled\n");
		break;
	default:
		dev_warn_once(dev, "quirk sets invalid output map: 0x%lx, defaulting to SPK_SPK_MAP\n",
			      quirk & BYT_WM5102_OUT_MAP);
		quirk &= ~BYT_WM5102_OUT_MAP;
		quirk |= BYT_WM5102_SPK_SPK_MAP;
		break;
	}
	if (quirk & BYT_WM5102_SSP2)
		dev_info_once(dev, "quirk SSP2 enabled");
	if (quirk & BYT_WM5102_MCLK_19_2MHZ)
		dev_info_once(dev, "quirk MCLK 19.2MHz enabled");
}

static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
	struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);

	gpiod_set_value_cansleep(priv->spkvdd_en_gpio,
				 !!SND_SOC_DAPM_EVENT_ON(event));

	return 0;
}

static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int rate)
{
	struct snd_soc_component *codec_component = codec_dai->component;
	struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(codec_component->card);
	int sr_mult = ((rate % 4000) == 0) ?
		(WM5102_MAX_SYSCLK_4K / rate) :
		(WM5102_MAX_SYSCLK_11025 / rate);
	int ret;

	/* Reset FLL1 */
	snd_soc_dai_set_pll(codec_dai, WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0);
	snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);

Annotation

Implementation Notes