drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c

Source file repositories/reference/linux-study-clean/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
Extension
.c
Size
15824 bytes
Lines
534
Domain
Driver Families
Bucket
drivers/misc
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 pci1xxxx_gpio {
	struct auxiliary_device *aux_dev;
	void __iomem *reg_base;
	raw_spinlock_t wa_lock;
	struct gpio_chip gpio;
	spinlock_t lock;
	u32 gpio_wake_mask[3];
	int irq_base;
	u8 dev_rev;
};

static int pci1xxxx_gpio_get_device_revision(struct pci1xxxx_gpio *priv)
{
	struct device *parent = priv->aux_dev->dev.parent;
	struct pci_dev *pcidev = to_pci_dev(parent);
	int ret;
	u32 val;

	ret = pci_read_config_dword(pcidev, PCI_DEV_REV_OFFSET, &val);
	if (ret)
		return ret;

	priv->dev_rev = val;

	return 0;
}

static int pci1xxxx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr)
{
	struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
	u32 data;
	int ret = -EINVAL;

	data = readl(priv->reg_base + INP_EN_OFFSET(nr));
	if (data & BIT(nr % 32)) {
		ret =  1;
	} else {
		data = readl(priv->reg_base + OUT_EN_OFFSET(nr));
		if (data & BIT(nr % 32))
			ret =  0;
	}

	return ret;
}

static inline void pci1xxx_assign_bit(void __iomem *base_addr, unsigned int reg_offset,
				      unsigned int bitpos, bool set)
{
	u32 data;

	data = readl(base_addr + reg_offset);
	if (set)
		data |= BIT(bitpos);
	else
		data &= ~BIT(bitpos);
	writel(data, base_addr + reg_offset);
}

static int pci1xxxx_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
{
	struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
	pci1xxx_assign_bit(priv->reg_base, INP_EN_OFFSET(nr), (nr % 32), true);
	pci1xxx_assign_bit(priv->reg_base, OUT_EN_OFFSET(nr), (nr % 32), false);
	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
}

static int pci1xxxx_gpio_get(struct gpio_chip *gpio, unsigned int nr)
{
	struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);

	return (readl(priv->reg_base + INP_OFFSET(nr)) >> (nr % 32)) & 1;
}

static int pci1xxxx_gpio_direction_output(struct gpio_chip *gpio,
					  unsigned int nr, int val)
{
	struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
	unsigned long flags;
	u32 data;

	spin_lock_irqsave(&priv->lock, flags);
	pci1xxx_assign_bit(priv->reg_base, INP_EN_OFFSET(nr), (nr % 32), false);
	pci1xxx_assign_bit(priv->reg_base, OUT_EN_OFFSET(nr), (nr % 32), true);
	data = readl(priv->reg_base + OUT_OFFSET(nr));
	if (val)

Annotation

Implementation Notes