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

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
...@@ -1563,6 +1563,7 @@ config GPIO_PCH ...@@ -1563,6 +1563,7 @@ config GPIO_PCH
config GPIO_PCI_IDIO_16 config GPIO_PCI_IDIO_16
tristate "ACCES PCI-IDIO-16 GPIO support" tristate "ACCES PCI-IDIO-16 GPIO support"
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
select GPIO_IDIO_16
help help
Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is 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 generated when any of the inputs change state (low to high or high to
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
* GPIO driver for the ACCES PCI-IDIO-16 * GPIO driver for the ACCES PCI-IDIO-16
* Copyright (C) 2017 William Breathitt Gray * Copyright (C) 2017 William Breathitt Gray
*/ */
#include <linux/bitmap.h> #include <linux/bits.h>
#include <linux/bitops.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
...@@ -16,51 +15,28 @@ ...@@ -16,51 +15,28 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
/** #include "gpio-idio-16.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;
};
/** /**
* struct idio_16_gpio - GPIO device private data structure * struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip * @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions * @lock: synchronization lock to prevent I/O race conditions
* @reg: I/O address offset for the GPIO device registers * @reg: I/O address offset for the GPIO device registers
* @state: ACCES IDIO-16 device state
* @irq_mask: I/O bits affected by interrupts * @irq_mask: I/O bits affected by interrupts
*/ */
struct idio_16_gpio { struct idio_16_gpio {
struct gpio_chip chip; struct gpio_chip chip;
raw_spinlock_t lock; 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; unsigned long irq_mask;
}; };
static int idio_16_gpio_get_direction(struct gpio_chip *chip, static int idio_16_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset) unsigned int offset)
{ {
if (offset > 15) if (idio_16_get_direction(offset))
return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT; return GPIO_LINE_DIRECTION_OUT;
...@@ -82,43 +58,16 @@ static int idio_16_gpio_direction_output(struct gpio_chip *chip, ...@@ -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) static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
{ {
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 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, static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits) unsigned long *mask, unsigned long *bits)
{ {
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 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; return 0;
} }
...@@ -126,61 +75,16 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, ...@@ -126,61 +75,16 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value) int value)
{ {
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 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) idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
out_state = ioread8(base) | mask;
else
out_state = ioread8(base) & ~mask;
iowrite8(out_state, base);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
} }
static void idio_16_gpio_set_multiple(struct gpio_chip *chip, static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits) unsigned long *mask, unsigned long *bits)
{ {
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 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); idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
out_state = ioread8(port_addr) & ~gpio_mask;
out_state |= bitmask;
iowrite8(out_state, port_addr);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
} }
static void idio_16_irq_ack(struct irq_data *data) 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) ...@@ -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 = idio_16_gpio_set;
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
idio_16_state_init(&idio16gpio->state);
girq = &idio16gpio->chip.irq; girq = &idio16gpio->chip.irq;
girq->chip = &idio_16_irqchip; girq->chip = &idio_16_irqchip;
/* This will let us handle the parent IRQ in the driver */ /* This will let us handle the parent IRQ in the driver */
...@@ -379,3 +285,4 @@ module_pci_driver(idio_16_driver); ...@@ -379,3 +285,4 @@ module_pci_driver(idio_16_driver);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver"); MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(GPIO_IDIO_16);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment