Commit da5dd31e authored by Linus Walleij's avatar Linus Walleij Committed by Bartosz Golaszewski
Browse files

gpio: vf610: Switch to gpio-mmio



After adding a pinctrl flag to gpio-mmio we can use it
for driving gpio-vf610.

The existing code has the same semantics and the generic
gpio-mmio, including reading from the data out register
when the direction is set to input, and it can also handle
the absence of the direction register better than the
current driver: we get the direction from the shadow
direction registers in gpio-mmio instead.

Since gpio-mmio has an internal spinlock we can drop the
direction-protecting spinlock from the driver.

Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Reviewed-by: default avatarHaibo Chen <haibo.chen@nxp.com>
Tested-by: default avatarHaibo Chen <haibo.chen@nxp.com>
Link: https://lore.kernel.org/r/20250219-vf610-mmio-v3-2-588b64f0b689@linaro.org


Signed-off-by: default avatarBartosz Golaszewski <bartosz.golaszewski@linaro.org>
parent 2145ba37
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -757,6 +757,7 @@ config GPIO_VF610
	default y if SOC_VF610
	depends on ARCH_MXC || COMPILE_TEST
	select GPIOLIB_IRQCHIP
	select GPIO_GENERIC
	help
	  Say yes here to support i.MX or Vybrid vf610 GPIOs.

+17 −88
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ struct vf610_gpio_port {
	struct clk *clk_port;
	struct clk *clk_gpio;
	int irq;
	spinlock_t lock; /* protect gpio direction registers */
};

#define GPIO_PDOR		0x00
@@ -94,78 +93,6 @@ static inline u32 vf610_gpio_readl(void __iomem *reg)
	return readl_relaxed(reg);
}

static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
	struct vf610_gpio_port *port = gpiochip_get_data(gc);
	u32 mask = BIT(gpio);
	unsigned long offset = GPIO_PDIR;

	if (port->sdata->have_paddr) {
		mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
		if (mask)
			offset = GPIO_PDOR;
	}

	return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio));
}

static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
	struct vf610_gpio_port *port = gpiochip_get_data(gc);
	u32 mask = BIT(gpio);
	unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR;

	vf610_gpio_writel(mask, port->gpio_base + offset);
}

static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
{
	struct vf610_gpio_port *port = gpiochip_get_data(chip);
	u32 mask = BIT(gpio);
	u32 val;

	if (port->sdata->have_paddr) {
		guard(spinlock_irqsave)(&port->lock);
		val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
		val &= ~mask;
		vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
	}

	return pinctrl_gpio_direction_input(chip, gpio);
}

static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
				       int value)
{
	struct vf610_gpio_port *port = gpiochip_get_data(chip);
	u32 mask = BIT(gpio);
	u32 val;

	vf610_gpio_set(chip, gpio, value);

	if (port->sdata->have_paddr) {
		guard(spinlock_irqsave)(&port->lock);
		val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
		val |= mask;
		vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
	}

	return pinctrl_gpio_direction_output(chip, gpio);
}

static int vf610_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
{
	struct vf610_gpio_port *port = gpiochip_get_data(gc);
	u32 mask = BIT(gpio);

	mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);

	if (mask)
		return GPIO_LINE_DIRECTION_OUT;

	return GPIO_LINE_DIRECTION_IN;
}

static void vf610_gpio_irq_handler(struct irq_desc *desc)
{
	struct vf610_gpio_port *port =
@@ -291,6 +218,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
	struct vf610_gpio_port *port;
	struct gpio_chip *gc;
	struct gpio_irq_chip *girq;
	unsigned long flags;
	int i;
	int ret;
	bool dual_base;
@@ -300,7 +228,6 @@ static int vf610_gpio_probe(struct platform_device *pdev)
		return -ENOMEM;

	port->sdata = device_get_match_data(dev);
	spin_lock_init(&port->lock);

	dual_base = port->sdata->have_dual_base;

@@ -367,23 +294,25 @@ static int vf610_gpio_probe(struct platform_device *pdev)
	}

	gc = &port->gc;
	gc->parent = dev;
	gc->label = dev_name(dev);
	gc->ngpio = VF610_GPIO_PER_PORT;
	gc->base = -1;

	gc->request = gpiochip_generic_request;
	gc->free = gpiochip_generic_free;
	gc->direction_input = vf610_gpio_direction_input;
	gc->get = vf610_gpio_get;
	gc->direction_output = vf610_gpio_direction_output;
	gc->set = vf610_gpio_set;
	flags = BGPIOF_PINCTRL_BACKEND;
	/*
	 * only IP has Port Data Direction Register(PDDR) can
	 * support get direction
	 * We only read the output register for current value on output
	 * lines if the direction register is available so we can switch
	 * direction.
	 */
	if (port->sdata->have_paddr)
		gc->get_direction = vf610_gpio_get_direction;
		flags |= BGPIOF_READ_OUTPUT_REG_SET;
	ret = bgpio_init(gc, dev, 4,
			 port->gpio_base + GPIO_PDIR,
			 port->gpio_base + GPIO_PDOR,
			 NULL,
			 port->sdata->have_paddr ? port->gpio_base + GPIO_PDDR : NULL,
			 NULL,
			 flags);
	if (ret)
		return dev_err_probe(dev, ret, "unable to init generic GPIO\n");
	gc->label = dev_name(dev);
	gc->base = -1;

	/* Mask all GPIO interrupts */
	for (i = 0; i < gc->ngpio; i++)