sound/soc/codecs/da7218.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/da7218.c
Extension
.c
Size
109858 bytes
Lines
3305
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

if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) {
			++i;
			usleep_range(DA7218_ALC_CALIB_DELAY_MIN,
				     DA7218_ALC_CALIB_DELAY_MAX);
		} else {
			calibrated = true;
		}

	} while ((i < DA7218_ALC_CALIB_MAX_TRIES) && (!calibrated));

	/* If auto calibration fails, disable DC offset, hybrid ALC */
	if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) {
		dev_warn(component->dev,
			 "ALC auto calibration failed - %s\n",
			 (calibrated) ? "overflow" : "timeout");
		snd_soc_component_update_bits(component, DA7218_CALIB_CTRL,
				    DA7218_CALIB_OFFSET_EN_MASK, 0);
		snd_soc_component_update_bits(component, DA7218_ALC_CTRL1,
				    DA7218_ALC_SYNC_MODE_MASK, 0);

	} else {
		/* Enable DC offset cancellation */
		snd_soc_component_update_bits(component, DA7218_CALIB_CTRL,
				    DA7218_CALIB_OFFSET_EN_MASK,
				    DA7218_CALIB_OFFSET_EN_MASK);

		/* Enable ALC hybrid mode */
		snd_soc_component_update_bits(component, DA7218_ALC_CTRL1,
				    DA7218_ALC_SYNC_MODE_MASK,
				    DA7218_ALC_SYNC_MODE_CH1 |
				    DA7218_ALC_SYNC_MODE_CH2);
	}

	/* Restore input HPF control registers to original states */
	snd_soc_component_write(component, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl);
	snd_soc_component_write(component, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl);

	/* Restore input filter control registers to original states */
	snd_soc_component_write(component, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl);
	snd_soc_component_write(component, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl);
	snd_soc_component_write(component, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl);
	snd_soc_component_write(component, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl);

	/* Restore input mixer control registers to original state */
	snd_soc_component_write(component, DA7218_MIXIN_1_CTRL, mixin_1_ctrl);
	snd_soc_component_write(component, DA7218_MIXIN_2_CTRL, mixin_2_ctrl);

	/* Restore MIC control registers to original states */
	snd_soc_component_write(component, DA7218_MIC_1_CTRL, mic_1_ctrl);
	snd_soc_component_write(component, DA7218_MIC_2_CTRL, mic_2_ctrl);
}

static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
	int ret;

	ret = snd_soc_put_volsw(kcontrol, ucontrol);

	/*
	 * If ALC in operation and value of control has been updated,
	 * make sure calibrated offsets are updated.
	 */
	if ((ret == 1) && (da7218->alc_en))
		da7218_alc_calib(component);

	return ret;
}

static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
{
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *) kcontrol->private_value;
	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
	unsigned int lvalue = ucontrol->value.integer.value[0];
	unsigned int rvalue = ucontrol->value.integer.value[1];
	unsigned int lshift = mc->shift;
	unsigned int rshift = mc->rshift;
	unsigned int mask = (mc->max << lshift) | (mc->max << rshift);

	/* Force ALC offset calibration if enabling ALC */
	if ((lvalue || rvalue) && (!da7218->alc_en))
		da7218_alc_calib(component);

	/* Update bits to detail which channels are enabled/disabled */
	da7218->alc_en &= ~mask;

Annotation

Implementation Notes