sound/soc/samsung/midas_wm1811.c

Source file repositories/reference/linux-study-clean/sound/soc/samsung/midas_wm1811.c

File Facts

System
Linux kernel
Corpus path
sound/soc/samsung/midas_wm1811.c
Extension
.c
Size
20756 bytes
Lines
776
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 midas_priv {
	struct gpio_desc *gpio_fm_sel;
	struct gpio_desc *gpio_lineout_sel;
	struct gpio_desc *gpio_headset_detect;
	struct gpio_desc *gpio_headset_key;
	struct iio_channel *adc_headset_detect;
	unsigned int fll1_rate;

	struct snd_soc_jack headset_jack;
};

static struct snd_soc_jack_pin headset_jack_pins[] = {
	{
		.pin = "Headphone",
		.mask = SND_JACK_HEADPHONE,
	},
	{
		.pin = "Headset Mic",
		.mask = SND_JACK_MICROPHONE,
	},
};

/*
 * min_mv/max_mv values in this struct are set up based on DT values.
 */
static struct snd_soc_jack_zone headset_jack_zones[] = {
	{ .jack_type = SND_JACK_HEADPHONE, },
	{ .jack_type = SND_JACK_HEADSET, },
	{ .jack_type = SND_JACK_HEADPHONE, },
};

/*
 * This is used for manual detection in headset_key_check, we reuse the
 * structure since it's convenient.
 *
 * min_mv/max_mv values in this struct are set up based on DT values.
 */
static struct snd_soc_jack_zone headset_key_zones[] = {
	{ .jack_type = SND_JACK_BTN_0, },  /* Media */
	{ .jack_type = SND_JACK_BTN_1, },  /* Volume Up */
	{ .jack_type = SND_JACK_BTN_2, },  /* Volume Down */
};

static int headset_jack_check(void *data)
{
	struct snd_soc_component *codec = data;
	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
	struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card);
	int adc, ret;
	int jack_type = 0;

	if (!gpiod_get_value_cansleep(priv->gpio_headset_detect))
		return 0;

	/* Enable headset mic bias regulator so that the ADC reading works */
	ret = snd_soc_dapm_force_enable_pin(dapm, "headset-mic-bias");
	if (ret < 0) {
		pr_err("%s: Failed to enable headset mic bias regulator (%d), assuming headphones\n",
		       __func__, ret);
		return SND_JACK_HEADPHONE;
	}
	snd_soc_dapm_sync(dapm);

	/* Sleep for a small amount of time to get the value to stabilize */
	msleep(20);

	ret = iio_read_channel_processed(priv->adc_headset_detect, &adc);
	if (ret) {
		pr_err("%s: Failed to read ADC (%d), assuming headphones\n",
		       __func__, ret);
		jack_type = SND_JACK_HEADPHONE;
		goto out;
	}
	pr_debug("%s: ADC value is %d\n", __func__, adc);

	jack_type = snd_soc_jack_get_type(&priv->headset_jack, adc);

out:
	ret = snd_soc_dapm_disable_pin(dapm, "headset-mic-bias");
	if (ret < 0)
		pr_err("%s: Failed to disable headset mic bias regulator (%d)\n",
		       __func__, ret);
	snd_soc_dapm_sync(dapm);

	return jack_type;
}

static int headset_key_check(void *data)
{
	struct snd_soc_component *codec = data;

Annotation

Implementation Notes