Commit e7f758fa authored by William Breathitt Gray's avatar William Breathitt Gray Committed by Bartosz Golaszewski
Browse files

gpio: pci-idio-16: Utilize the idio-16 GPIO library



The ACCES PCI-IDIO-16 device is part of the ACCES IDIO-16 family, so the
idio-16 GPIO library module is selected and utilized to consolidate
code.

Signed-off-by: default avatarWilliam Breathitt Gray <william.gray@linaro.org>
Signed-off-by: default avatarBartosz Golaszewski <bartosz.golaszewski@linaro.org>
parent c4ec384c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1563,6 +1563,7 @@ config GPIO_PCH
config GPIO_PCI_IDIO_16
	tristate "ACCES PCI-IDIO-16 GPIO support"
	select GPIOLIB_IRQCHIP
	select GPIO_IDIO_16
	help
	  Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is
	  generated when any of the inputs change state (low to high or high to
+13 −106
Original line number Diff line number Diff line
@@ -3,8 +3,7 @@
 * GPIO driver for the ACCES PCI-IDIO-16
 * Copyright (C) 2017 William Breathitt Gray
 */
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -16,51 +15,28 @@
#include <linux/spinlock.h>
#include <linux/types.h>

/**
 * struct idio_16_gpio_reg - GPIO device registers structure
 * @out0_7:	Read: FET Drive Outputs 0-7
 *		Write: FET Drive Outputs 0-7
 * @in0_7:	Read: Isolated Inputs 0-7
 *		Write: Clear Interrupt
 * @irq_ctl:	Read: Enable IRQ
 *		Write: Disable IRQ
 * @filter_ctl:	Read: Activate Input Filters 0-15
 *		Write: Deactivate Input Filters 0-15
 * @out8_15:	Read: FET Drive Outputs 8-15
 *		Write: FET Drive Outputs 8-15
 * @in8_15:	Read: Isolated Inputs 8-15
 *		Write: Unused
 * @irq_status:	Read: Interrupt status
 *		Write: Unused
 */
struct idio_16_gpio_reg {
	u8 out0_7;
	u8 in0_7;
	u8 irq_ctl;
	u8 filter_ctl;
	u8 out8_15;
	u8 in8_15;
	u8 irq_status;
};
#include "gpio-idio-16.h"

/**
 * struct idio_16_gpio - GPIO device private data structure
 * @chip:	instance of the gpio_chip
 * @lock:	synchronization lock to prevent I/O race conditions
 * @reg:	I/O address offset for the GPIO device registers
 * @state:	ACCES IDIO-16 device state
 * @irq_mask:	I/O bits affected by interrupts
 */
struct idio_16_gpio {
	struct gpio_chip chip;
	raw_spinlock_t lock;
	struct idio_16_gpio_reg __iomem *reg;
	struct idio_16 __iomem *reg;
	struct idio_16_state state;
	unsigned long irq_mask;
};

static int idio_16_gpio_get_direction(struct gpio_chip *chip,
	unsigned int offset)
{
	if (offset > 15)
	if (idio_16_get_direction(offset))
		return GPIO_LINE_DIRECTION_IN;

	return GPIO_LINE_DIRECTION_OUT;
@@ -82,43 +58,16 @@ static int idio_16_gpio_direction_output(struct gpio_chip *chip,
static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
	unsigned long mask = BIT(offset);

	if (offset < 8)
		return !!(ioread8(&idio16gpio->reg->out0_7) & mask);

	if (offset < 16)
		return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));

	if (offset < 24)
		return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));

	return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
	return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
}

static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
	unsigned long *mask, unsigned long *bits)
{
	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
	unsigned long offset;
	unsigned long gpio_mask;
	void __iomem *ports[] = {
		&idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
		&idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15,
	};
	void __iomem *port_addr;
	unsigned long port_state;

	/* clear bits array to a clean slate */
	bitmap_zero(bits, chip->ngpio);

	for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
		port_addr = ports[offset / 8];
		port_state = ioread8(port_addr) & gpio_mask;

		bitmap_set_value8(bits, port_state, offset);
	}

	idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
	return 0;
}

@@ -126,61 +75,16 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
	int value)
{
	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
	unsigned int mask = BIT(offset);
	void __iomem *base;
	unsigned long flags;
	unsigned int out_state;

	if (offset > 15)
		return;

	if (offset > 7) {
		mask >>= 8;
		base = &idio16gpio->reg->out8_15;
	} else
		base = &idio16gpio->reg->out0_7;

	raw_spin_lock_irqsave(&idio16gpio->lock, flags);

	if (value)
		out_state = ioread8(base) | mask;
	else
		out_state = ioread8(base) & ~mask;

	iowrite8(out_state, base);

	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
	idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
}

static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
	unsigned long *mask, unsigned long *bits)
{
	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
	unsigned long offset;
	unsigned long gpio_mask;
	void __iomem *ports[] = {
		&idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
	};
	size_t index;
	void __iomem *port_addr;
	unsigned long bitmask;
	unsigned long flags;
	unsigned long out_state;

	for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
		index = offset / 8;
		port_addr = ports[index];

		bitmask = bitmap_get_value8(bits, offset) & gpio_mask;

		raw_spin_lock_irqsave(&idio16gpio->lock, flags);

		out_state = ioread8(port_addr) & ~gpio_mask;
		out_state |= bitmask;
		iowrite8(out_state, port_addr);

		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
	}
	idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
}

static void idio_16_irq_ack(struct irq_data *data)
@@ -335,6 +239,8 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	idio16gpio->chip.set = idio_16_gpio_set;
	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;

	idio_16_state_init(&idio16gpio->state);

	girq = &idio16gpio->chip.irq;
	girq->chip = &idio_16_irqchip;
	/* This will let us handle the parent IRQ in the driver */
@@ -379,3 +285,4 @@ module_pci_driver(idio_16_driver);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(GPIO_IDIO_16);