drivers/gpio/gpio-ws16c48.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpio-ws16c48.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-ws16c48.c
Extension
.c
Size
10300 bytes
Lines
328
Domain
Driver Families
Bucket
drivers/gpio
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 ws16c48_gpio {
	struct regmap *map;
	raw_spinlock_t lock;
	u8 irq_mask[WS16C48_NUM_IRQS / WS16C48_NGPIO_PER_REG];
};

static int ws16c48_handle_pre_irq(void *const irq_drv_data) __acquires(&ws16c48gpio->lock)
{
	struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;

	/* Lock to prevent Page/Lock register change while we handle IRQ */
	raw_spin_lock(&ws16c48gpio->lock);

	return 0;
}

static int ws16c48_handle_post_irq(void *const irq_drv_data) __releases(&ws16c48gpio->lock)
{
	struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;

	raw_spin_unlock(&ws16c48gpio->lock);

	return 0;
}

static int ws16c48_handle_mask_sync(const int index, const unsigned int mask_buf_def,
				    const unsigned int mask_buf, void *const irq_drv_data)
{
	struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
	unsigned long flags;
	int ret = 0;

	raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);

	/* exit early if no change since the last mask sync */
	if (mask_buf == ws16c48gpio->irq_mask[index])
		goto exit_unlock;
	ws16c48gpio->irq_mask[index] = mask_buf;

	ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, ENAB_PAGE);
	if (ret)
		goto exit_unlock;

	/* Update ENAB register (inverted mask) */
	ret = regmap_write(ws16c48gpio->map, WS16C48_ENAB + index, ~mask_buf);
	if (ret)
		goto exit_unlock;

	ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, INT_ID_PAGE);
	if (ret)
		goto exit_unlock;

exit_unlock:
	raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);

	return ret;
}

static int ws16c48_set_type_config(unsigned int **const buf, const unsigned int type,
				   const struct regmap_irq *const irq_data, const int idx,
				   void *const irq_drv_data)
{
	struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
	unsigned int polarity;
	unsigned long flags;
	int ret;

	switch (type) {
	case IRQ_TYPE_EDGE_RISING:
		polarity = irq_data->mask;
		break;
	case IRQ_TYPE_EDGE_FALLING:
		polarity = 0;
		break;
	default:
		return -EINVAL;
	}

	raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);

	ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, POL_PAGE);
	if (ret)
		goto exit_unlock;

	/* Set interrupt polarity */
	ret = regmap_update_bits(ws16c48gpio->map, WS16C48_POL + idx, irq_data->mask, polarity);
	if (ret)
		goto exit_unlock;

	ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, INT_ID_PAGE);

Annotation

Implementation Notes