drivers/gpio/gpio-mpc8xxx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-mpc8xxx.c
Extension
.c
Size
14179 bytes
Lines
512
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 mpc8xxx_gpio_chip {
	struct gpio_generic_chip chip;
	void __iomem *regs;
	raw_spinlock_t lock;

	int (*direction_output)(struct gpio_chip *chip,
				unsigned offset, int value);

	struct irq_domain *irq;
	int irqn;
};

/*
 * This hardware has a big endian bit assignment such that GPIO line 0 is
 * connected to bit 31, line 1 to bit 30 ... line 31 to bit 0.
 * This inline helper give the right bitmask for a certain line.
 */
static inline u32 mpc_pin2mask(unsigned int offset)
{
	return BIT(31 - offset);
}

/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
 * defined as output cannot be determined by reading GPDAT register,
 * so we use shadow data register instead. The status of input pins
 * is determined by reading GPDAT register.
 */
static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
	u32 val;
	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
	u32 out_mask, out_shadow;

	out_mask = gpio_generic_read_reg(&mpc8xxx_gc->chip,
					 mpc8xxx_gc->regs + GPIO_DIR);
	val = gpio_generic_read_reg(&mpc8xxx_gc->chip,
				    mpc8xxx_gc->regs + GPIO_DAT) & ~out_mask;
	out_shadow = mpc8xxx_gc->chip.sdata & out_mask;

	return !!((val | out_shadow) & mpc_pin2mask(gpio));
}

static int mpc5121_gpio_dir_out(struct gpio_chip *gc,
				unsigned int gpio, int val)
{
	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
	/* GPIO 28..31 are input only on MPC5121 */
	if (gpio >= 28)
		return -EINVAL;

	return mpc8xxx_gc->direction_output(gc, gpio, val);
}

static int mpc5125_gpio_dir_out(struct gpio_chip *gc,
				unsigned int gpio, int val)
{
	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
	/* GPIO 0..3 are input only on MPC5125 */
	if (gpio <= 3)
		return -EINVAL;

	return mpc8xxx_gc->direction_output(gc, gpio, val);
}

static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);

	if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
		return irq_create_mapping(mpc8xxx_gc->irq, offset);
	else
		return -ENXIO;
}

static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data)
{
	struct mpc8xxx_gpio_chip *mpc8xxx_gc = data;
	unsigned long mask;
	int i;

	mask = gpio_generic_read_reg(&mpc8xxx_gc->chip,
				     mpc8xxx_gc->regs + GPIO_IER) &
	       gpio_generic_read_reg(&mpc8xxx_gc->chip,
				     mpc8xxx_gc->regs + GPIO_IMR);
	for_each_set_bit(i, &mask, 32)
		generic_handle_domain_irq(mpc8xxx_gc->irq, 31 - i);

	return IRQ_HANDLED;
}

Annotation

Implementation Notes