sound/soc/codecs/rt5677.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/rt5677.c
Extension
.c
Size
187661 bytes
Lines
5710
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 rt5677_irq_desc {
	unsigned int enable_mask;
	unsigned int status_mask;
	unsigned int polarity_mask;
};

static const struct rt5677_irq_desc rt5677_irq_descs[] = {
	[RT5677_IRQ_JD1] = {
		.enable_mask = RT5677_EN_IRQ_GPIO_JD1,
		.status_mask = RT5677_STA_GPIO_JD1,
		.polarity_mask = RT5677_INV_GPIO_JD1,
	},
	[RT5677_IRQ_JD2] = {
		.enable_mask = RT5677_EN_IRQ_GPIO_JD2,
		.status_mask = RT5677_STA_GPIO_JD2,
		.polarity_mask = RT5677_INV_GPIO_JD2,
	},
	[RT5677_IRQ_JD3] = {
		.enable_mask = RT5677_EN_IRQ_GPIO_JD3,
		.status_mask = RT5677_STA_GPIO_JD3,
		.polarity_mask = RT5677_INV_GPIO_JD3,
	},
};

static bool rt5677_check_hotword(struct rt5677_priv *rt5677)
{
	int reg_gpio;

	if (!rt5677->is_dsp_mode)
		return false;

	if (regmap_read(rt5677->regmap, RT5677_GPIO_CTRL1, &reg_gpio))
		return false;

	/* Firmware sets GPIO1 pin to be GPIO1 after hotword is detected */
	if ((reg_gpio & RT5677_GPIO1_PIN_MASK) == RT5677_GPIO1_PIN_IRQ)
		return false;

	/* Set GPIO1 pin back to be IRQ output for jack detect */
	regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1,
			RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ);

	rt5677_spi_hotword_detected();
	return true;
}

static irqreturn_t rt5677_irq(int unused, void *data)
{
	struct rt5677_priv *rt5677 = data;
	int ret, loop, i, reg_irq, virq;
	bool irq_fired = false;

	mutex_lock(&rt5677->irq_lock);

	/*
	 * Loop to handle interrupts until the last i2c read shows no pending
	 * irqs. The interrupt line is shared by multiple interrupt sources.
	 * After the regmap_read() below, a new interrupt source line may
	 * become high before the regmap_write() finishes, so there isn't a
	 * rising edge on the shared interrupt line for the new interrupt. Thus,
	 * the loop is needed to avoid missing irqs.
	 *
	 * A safeguard of 20 loops is used to avoid hanging in the irq handler
	 * if there is something wrong with the interrupt status update. The
	 * interrupt sources here are audio jack plug/unplug events which
	 * shouldn't happen at a high frequency for a long period of time.
	 * Empirically, more than 3 loops have never been seen.
	 */
	for (loop = 0; loop < 20; loop++) {
		/* Read interrupt status */
		ret = regmap_read(rt5677->regmap, RT5677_IRQ_CTRL1, &reg_irq);
		if (ret) {
			dev_err(rt5677->dev, "failed reading IRQ status: %d\n",
				ret);
			goto exit;
		}

		irq_fired = false;
		for (i = 0; i < RT5677_IRQ_NUM; i++) {
			if (reg_irq & rt5677_irq_descs[i].status_mask) {
				irq_fired = true;
				virq = irq_find_mapping(rt5677->domain, i);
				if (virq)
					handle_nested_irq(virq);

				/* Clear the interrupt by flipping the polarity
				 * of the interrupt source line that fired
				 */
				reg_irq ^= rt5677_irq_descs[i].polarity_mask;
			}

Annotation

Implementation Notes