sound/soc/soc-jack.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/soc-jack.c
Extension
.c
Size
11379 bytes
Lines
440
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 jack_gpio_tbl {
	int count;
	struct snd_soc_jack *jack;
	struct snd_soc_jack_gpio *gpios;
};

/* gpio detect */
static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
{
	struct snd_soc_jack *jack = gpio->jack;
	int enable;
	int report;

	enable = gpiod_get_value_cansleep(gpio->desc);
	if (gpio->invert)
		enable = !enable;

	if (enable)
		report = gpio->report;
	else
		report = 0;

	if (gpio->jack_status_check)
		report = gpio->jack_status_check(gpio->data);

	snd_soc_jack_report(jack, report, gpio->report);
}

/* irq handler for gpio pin */
static irqreturn_t gpio_handler(int irq, void *data)
{
	struct snd_soc_jack_gpio *gpio = data;
	struct device *dev = gpio->jack->card->dev;

	trace_snd_soc_jack_irq(gpio->name);

	if (device_may_wakeup(dev))
		pm_wakeup_event(dev, gpio->debounce_time + 50);

	queue_delayed_work(system_power_efficient_wq, &gpio->work,
			      msecs_to_jiffies(gpio->debounce_time));

	return IRQ_HANDLED;
}

/* gpio work */
static void gpio_work(struct work_struct *work)
{
	struct snd_soc_jack_gpio *gpio;

	gpio = container_of(work, struct snd_soc_jack_gpio, work.work);
	snd_soc_jack_gpio_detect(gpio);
}

static int snd_soc_jack_pm_notifier(struct notifier_block *nb,
				    unsigned long action, void *data)
{
	struct snd_soc_jack_gpio *gpio =
			container_of(nb, struct snd_soc_jack_gpio, pm_notifier);

	switch (action) {
	case PM_POST_SUSPEND:
	case PM_POST_HIBERNATION:
	case PM_POST_RESTORE:
		/*
		 * Use workqueue so we do not have to care about running
		 * concurrently with work triggered by the interrupt handler.
		 */
		queue_delayed_work(system_power_efficient_wq, &gpio->work, 0);
		break;
	}

	return NOTIFY_DONE;
}

static void jack_free_gpios(struct snd_soc_jack *jack, int count,
			    struct snd_soc_jack_gpio *gpios)
{
	int i;

	for (i = 0; i < count; i++) {
		gpiod_unexport(gpios[i].desc);
		unregister_pm_notifier(&gpios[i].pm_notifier);
		free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
		cancel_delayed_work_sync(&gpios[i].work);
		gpiod_put(gpios[i].desc);
		gpios[i].jack = NULL;
	}
}

Annotation

Implementation Notes