sound/soc/codecs/wsa881x.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/wsa881x.c
Extension
.c
Size
40063 bytes
Lines
1210
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 wsa881x_priv {
	struct regmap *regmap;
	struct device *dev;
	struct sdw_slave *slave;
	struct sdw_stream_config sconfig;
	struct sdw_stream_runtime *sruntime;
	struct sdw_port_config port_config[WSA881X_MAX_SWR_PORTS];
	struct gpio_desc *sd_n;
	int active_ports;
	bool hw_init;
	bool port_prepared[WSA881X_MAX_SWR_PORTS];
	bool port_enable[WSA881X_MAX_SWR_PORTS];
};

static void wsa881x_init(struct wsa881x_priv *wsa881x)
{
	struct regmap *rm = wsa881x->regmap;
	unsigned int val = 0;

	if (wsa881x->hw_init)
		return;

	regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0,
			      ARRAY_SIZE(wsa881x_rev_2_0));

	/* Enable software reset output from soundwire slave */
	regmap_update_bits(rm, WSA881X_SWR_RESET_EN, 0x07, 0x07);

	/* Bring out of analog reset */
	regmap_update_bits(rm, WSA881X_CDC_RST_CTL, 0x02, 0x02);

	/* Bring out of digital reset */
	regmap_update_bits(rm, WSA881X_CDC_RST_CTL, 0x01, 0x01);
	regmap_update_bits(rm, WSA881X_CLOCK_CONFIG, 0x10, 0x10);
	regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x02, 0x02);
	regmap_update_bits(rm, WSA881X_SPKR_MISC_CTL1, 0xC0, 0x80);
	regmap_update_bits(rm, WSA881X_SPKR_MISC_CTL1, 0x06, 0x06);
	regmap_update_bits(rm, WSA881X_SPKR_BIAS_INT, 0xFF, 0x00);
	regmap_update_bits(rm, WSA881X_SPKR_PA_INT, 0xF0, 0x40);
	regmap_update_bits(rm, WSA881X_SPKR_PA_INT, 0x0E, 0x0E);
	regmap_update_bits(rm, WSA881X_BOOST_LOOP_STABILITY, 0x03, 0x03);
	regmap_update_bits(rm, WSA881X_BOOST_MISC2_CTL, 0xFF, 0x14);
	regmap_update_bits(rm, WSA881X_BOOST_START_CTL, 0x80, 0x80);
	regmap_update_bits(rm, WSA881X_BOOST_START_CTL, 0x03, 0x00);
	regmap_update_bits(rm, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x0C, 0x04);
	regmap_update_bits(rm, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x03, 0x00);

	regmap_read(rm, WSA881X_OTP_REG_0, &val);
	if (val)
		regmap_update_bits(rm, WSA881X_BOOST_PRESET_OUT1, 0xF0, 0x70);

	regmap_update_bits(rm, WSA881X_BOOST_PRESET_OUT2, 0xF0, 0x30);
	regmap_update_bits(rm, WSA881X_SPKR_DRV_EN, 0x08, 0x08);
	regmap_update_bits(rm, WSA881X_BOOST_CURRENT_LIMIT, 0x0F, 0x08);
	regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x30, 0x30);
	regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x0C, 0x00);
	regmap_update_bits(rm, WSA881X_OTP_REG_28, 0x3F, 0x3A);
	regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG1, 0xFF, 0xB2);
	regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG2, 0xFF, 0x05);

	wsa881x->hw_init = true;
}

static int wsa881x_component_probe(struct snd_soc_component *comp)
{
	struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(comp);

	snd_soc_component_init_regmap(comp, wsa881x->regmap);

	return 0;
}

static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *comp = snd_kcontrol_chip(kc);
	struct soc_mixer_control *mc =
			(struct soc_mixer_control *)kc->private_value;
	int max = mc->max;
	unsigned int mask = (1 << fls(max)) - 1;
	int val, ret, min_gain, max_gain;

	ret = pm_runtime_resume_and_get(comp->dev);
	if (ret < 0 && ret != -EACCES)
		return ret;

	max_gain = (max - ucontrol->value.integer.value[0]) & mask;
	/*
	 * Gain has to set incrementally in 4 steps
	 * as per HW sequence

Annotation

Implementation Notes