drivers/mfd/twl6030-irq.c

Source file repositories/reference/linux-study-clean/drivers/mfd/twl6030-irq.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/twl6030-irq.c
Extension
.c
Size
11052 bytes
Lines
382
Domain
Driver Families
Bucket
drivers/mfd
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 twl6030_irq {
	unsigned int		irq_base;
	int			twl_irq;
	bool			irq_wake_enabled;
	atomic_t		wakeirqs;
	struct notifier_block	pm_nb;
	struct irq_chip		irq_chip;
	struct irq_domain	*irq_domain;
	const int		*irq_mapping_tbl;
};

static struct twl6030_irq *twl6030_irq;

static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
				   unsigned long pm_event, void *unused)
{
	int chained_wakeups;
	struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq,
						  pm_nb);

	switch (pm_event) {
	case PM_SUSPEND_PREPARE:
		chained_wakeups = atomic_read(&pdata->wakeirqs);

		if (chained_wakeups && !pdata->irq_wake_enabled) {
			if (enable_irq_wake(pdata->twl_irq))
				pr_err("twl6030 IRQ wake enable failed\n");
			else
				pdata->irq_wake_enabled = true;
		} else if (!chained_wakeups && pdata->irq_wake_enabled) {
			disable_irq_wake(pdata->twl_irq);
			pdata->irq_wake_enabled = false;
		}

		disable_irq(pdata->twl_irq);
		break;

	case PM_POST_SUSPEND:
		enable_irq(pdata->twl_irq);
		break;

	default:
		break;
	}

	return NOTIFY_DONE;
}

/*
* Threaded irq handler for the twl6030 interrupt.
* We query the interrupt controller in the twl6030 to determine
* which module is generating the interrupt request and call
* handle_nested_irq for that module.
*/
static irqreturn_t twl6030_irq_thread(int irq, void *data)
{
	int i, ret;
	union {
		u8 bytes[4];
		__le32 int_sts;
	} sts;
	u32 int_sts; /* sts.int_sts converted to CPU endianness */
	struct twl6030_irq *pdata = data;

	/* read INT_STS_A, B and C in one shot using a burst read */
	ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3);
	if (ret) {
		pr_warn("twl6030_irq: I2C error %d reading PIH ISR\n", ret);
		return IRQ_HANDLED;
	}

	sts.bytes[3] = 0; /* Only 24 bits are valid*/

	/*
	 * Since VBUS status bit is not reliable for VBUS disconnect
	 * use CHARGER VBUS detection status bit instead.
	 */
	if (sts.bytes[2] & 0x10)
		sts.bytes[2] |= 0x08;

	int_sts = le32_to_cpu(sts.int_sts);
	for (i = 0; int_sts; int_sts >>= 1, i++)
		if (int_sts & 0x1) {
			int module_irq =
				irq_find_mapping(pdata->irq_domain,
						 pdata->irq_mapping_tbl[i]);
			if (module_irq)
				handle_nested_irq(module_irq);
			else
				pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n",

Annotation

Implementation Notes