All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers
@ 2018-03-17 15:49 William Breathitt Gray
  2018-03-17 15:49 ` [PATCH v3 1/8] iio: stx104: Implement get_multiple callback William Breathitt Gray
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:49 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

Changes in v2:
  - Add missing bitmap.h header includes
  - Fix typographical error in symbol name for word_mask
  - Remove const qualifier for ports array

This patchset implements get_multiple callbacks for the PC104 GPIO
drivers as well as the PCI-IDIO-16 and PCIe-IDIO-24 GPIO drivers. These
devices all acquire the multiple input lines with a single read, so
utilizing the get_multiple callback can provide improvement for those
users who regularly access multiple input lines.

While developing this patchset I noticed many of these devices make use
of Intel 8255 compatible interfaces for their I/O. I may write a generic
8255 GPIO driver in the future to reduce some of the redundant code I
see pop among the drivers for these devices.

William Breathitt Gray (8):
  iio: stx104: Implement get_multiple callback
  gpio: 104-idio-16: Implement get_multiple callback
  gpio: pci-idio-16: Implement get_multiple callback
  gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks
  gpio: 104-dio-48e: Implement get_multiple callback
  gpio: 104-idi-48: Implement get_multiple callback
  gpio: gpio-mm: Implement get_multiple callback
  gpio: ws16c48: Implement get_multiple callback

 drivers/gpio/gpio-104-dio-48e.c  |  47 ++++++++++++++++
 drivers/gpio/gpio-104-idi-48.c   |  47 ++++++++++++++++
 drivers/gpio/gpio-104-idio-16.c  |  15 +++++
 drivers/gpio/gpio-gpio-mm.c      |  47 ++++++++++++++++
 drivers/gpio/gpio-pci-idio-16.c  |  50 +++++++++++++++++
 drivers/gpio/gpio-pcie-idio-24.c | 117 +++++++++++++++++++++++++++++++++++++++
 drivers/gpio/gpio-ws16c48.c      |  47 ++++++++++++++++
 drivers/iio/adc/stx104.c         |  11 ++++
 8 files changed, 381 insertions(+)

-- 
2.16.2

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v3 1/8] iio: stx104: Implement get_multiple callback
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
@ 2018-03-17 15:49 ` William Breathitt Gray
  2018-03-17 18:22   ` Jonathan Cameron
  2018-03-17 18:51   ` Andy Shevchenko
  2018-03-17 15:50 ` [PATCH v3 2/8] gpio: 104-idio-16: " William Breathitt Gray
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:49 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler

The Apex Embedded Systems STX104 series of devices provides 4 TTL
compatible lines of inputs accessed via a single 4-bit port. Since four
input lines are acquired on a single port input read, the STX104 GPIO
driver may improve multiple input reads by utilizing a get_multiple
callback. This patch implements the stx104_gpio_get_multiple function
which serves as the respective get_multiple callback.

Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Hartmut Knaack <knaack.h@gmx.de>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/iio/adc/stx104.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c
index 17b021f33180..0662ca199eb0 100644
--- a/drivers/iio/adc/stx104.c
+++ b/drivers/iio/adc/stx104.c
@@ -233,6 +233,16 @@ static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(inb(stx104gpio->base) & BIT(offset));
 }
 
+static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
+	*bits = inb(stx104gpio->base);
+
+	return 0;
+}
+
 static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -342,6 +352,7 @@ static int stx104_probe(struct device *dev, unsigned int id)
 	stx104gpio->chip.direction_input = stx104_gpio_direction_input;
 	stx104gpio->chip.direction_output = stx104_gpio_direction_output;
 	stx104gpio->chip.get = stx104_gpio_get;
+	stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
 	stx104gpio->chip.set = stx104_gpio_set;
 	stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
 	stx104gpio->base = base[id] + 3;
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 2/8] gpio: 104-idio-16: Implement get_multiple callback
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
  2018-03-17 15:49 ` [PATCH v3 1/8] iio: stx104: Implement get_multiple callback William Breathitt Gray
@ 2018-03-17 15:50 ` William Breathitt Gray
  2018-03-21 15:32   ` Andy Shevchenko
  2018-03-17 15:50 ` [PATCH v3 3/8] gpio: pci-idio-16: " William Breathitt Gray
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:50 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

The ACCES I/O 104-IDIO-16 series of devices provides 16
optically-isolated digital inputs accessed via two 8-bit ports. Since
eight input lines are acquired on a single port input read, the
104-IDIO-16 GPIO driver may improve multiple input reads by utilizing a
get_multiple callback. This patch implements the
idio_16_gpio_get_multiple function which serves as the respective
get_multiple callback.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/gpio/gpio-104-idio-16.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 2f16638a0589..5de5819e5156 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -90,6 +90,20 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return !!(inb(idio16gpio->base + 5) & (mask>>8));
 }
 
+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);
+
+	*bits = 0;
+	if (*mask & 0xFF0000)
+		*bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
+	if (*mask & 0xFF000000)
+		*bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
+
+	return 0;
+}
+
 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
@@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
 	idio16gpio->chip.get = idio_16_gpio_get;
+	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
 	idio16gpio->chip.set = idio_16_gpio_set;
 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
 	idio16gpio->base = base[id];
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 3/8] gpio: pci-idio-16: Implement get_multiple callback
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
  2018-03-17 15:49 ` [PATCH v3 1/8] iio: stx104: Implement get_multiple callback William Breathitt Gray
  2018-03-17 15:50 ` [PATCH v3 2/8] gpio: 104-idio-16: " William Breathitt Gray
@ 2018-03-17 15:50 ` William Breathitt Gray
  2018-03-21 17:45   ` Andy Shevchenko
  2018-03-17 15:51 ` [PATCH v3 4/8] gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks William Breathitt Gray
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:50 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

The ACCES I/O PCI-IDIO-16 series of devices provides 16
optically-isolated digital inputs accessed via two 8-bit ports. Since
eight input lines are acquired on a single port input read, the
PCI-IDIO-16 GPIO driver may improve multiple input reads by utilizing a
get_multiple callback. This patch implements the
idio_16_gpio_get_multiple function which serves as the respective
get_multiple callback.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/gpio/gpio-pci-idio-16.c | 50 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
index 57d1b7fbf07b..f273cf776cac 100644
--- a/drivers/gpio/gpio-pci-idio-16.c
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -11,6 +11,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -103,6 +104,54 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
 }
 
+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);
+	size_t i;
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+	u8 __iomem ports[] = {
+		idio16gpio->reg->out0_7, idio16gpio->reg->out8_15,
+		idio16gpio->reg->in0_7, idio16gpio->reg->in8_15
+	};
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = ioread8(ports + i);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -299,6 +348,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
 	idio16gpio->chip.get = idio_16_gpio_get;
+	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
 	idio16gpio->chip.set = idio_16_gpio_set;
 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
 
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 4/8] gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
                   ` (2 preceding siblings ...)
  2018-03-17 15:50 ` [PATCH v3 3/8] gpio: pci-idio-16: " William Breathitt Gray
@ 2018-03-17 15:51 ` William Breathitt Gray
  2018-03-17 15:51 ` [PATCH v3 5/8] gpio: 104-dio-48e: Implement get_multiple callback William Breathitt Gray
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:51 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

The ACCES I/O PCIe-IDIO-24 series of devices provides 24
optically-isolated digital I/O accessed via six 8-bit ports. Since eight
input lines are acquired on a single port input read -- and similarly
eight output lines are set on a single port output write -- the
PCIe-IDIO-24 GPIO driver may improve multiple I/O reads/writes by
utilizing a get_multiple/set_multiple callbacks. This patch implements
the idio_24_gpio_get_multiple function which serves as the respective
get_multiple callback, and implements the idio_24_gpio_set_multiple
function which serves as the respective set_multiple callback.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/gpio/gpio-pcie-idio-24.c | 117 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c
index f666e2e69074..412aca253c76 100644
--- a/drivers/gpio/gpio-pcie-idio-24.c
+++ b/drivers/gpio/gpio-pcie-idio-24.c
@@ -15,6 +15,7 @@
  * This driver supports the following ACCES devices: PCIe-IDIO-24,
  * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -193,6 +194,61 @@ static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
 }
 
+static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
+	size_t i;
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+	u8 __iomem ports[] = {
+		idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
+		idio24gpio->reg->out16_23, idio24gpio->reg->in0_7,
+		idio24gpio->reg->in8_15, idio24gpio->reg->in16_23
+	};
+	const unsigned long out_mode_mask = BIT(1);
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port (port 6 is TTL GPIO) */
+		if (i < 6)
+			port_state = ioread8(ports + i);
+		else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
+			port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
+		else
+			port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -234,6 +290,65 @@ static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 }
 
+static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
+	size_t i;
+	unsigned long bits_offset;
+	unsigned long gpio_mask;
+	const unsigned int gpio_reg_size = 8;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long flags;
+	unsigned int out_state;
+	u8 __iomem ports[] = {
+		idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
+		idio24gpio->reg->out16_23
+	};
+	const unsigned long out_mode_mask = BIT(1);
+	const unsigned int ttl_offset = 48;
+	const size_t ttl_i = BIT_WORD(ttl_offset);
+	const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
+	const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
+	const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
+
+	/* set bits are processed a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* check if any set bits for current port */
+		gpio_mask = (*mask >> bits_offset) & port_mask;
+		if (!gpio_mask) {
+			/* no set bits for this port so move on to next port */
+			continue;
+		}
+
+		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
+
+		/* process output lines */
+		out_state = ioread8(ports + i) & ~gpio_mask;
+		out_state |= (*bits >> bits_offset) & gpio_mask;
+		iowrite8(out_state, ports + i);
+
+		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+	}
+
+	/* check if setting TTL lines and if they are in output mode */
+	if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
+		return;
+
+	/* handle TTL output */
+	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
+
+	/* process output lines */
+	out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
+	out_state |= ttl_bits;
+	iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
+
+	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+}
+
 static void idio_24_irq_ack(struct irq_data *data)
 {
 }
@@ -397,7 +512,9 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
 	idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
 	idio24gpio->chip.get = idio_24_gpio_get;
+	idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
 	idio24gpio->chip.set = idio_24_gpio_set;
+	idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
 
 	raw_spin_lock_init(&idio24gpio->lock);
 
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 5/8] gpio: 104-dio-48e: Implement get_multiple callback
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
                   ` (3 preceding siblings ...)
  2018-03-17 15:51 ` [PATCH v3 4/8] gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks William Breathitt Gray
@ 2018-03-17 15:51 ` William Breathitt Gray
  2018-03-17 15:51 ` [PATCH v3 6/8] gpio: 104-idi-48: " William Breathitt Gray
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:51 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

The ACCES I/O 104-DIO-48E series of devices contain two Programmable
Peripheral Interface (PPI) chips of type 82C55, which each feature three
8-bit ports of I/O. Since eight input lines are acquired on a single
port input read, the 104-DIO-48E GPIO driver may improve multiple input
reads by utilizing a get_multiple callback. This patch implements the
dio48e_gpio_get_multiple function which serves as the respective
get_multiple callback.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/gpio/gpio-104-dio-48e.c | 47 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index bab3b94c5cbc..7d43c77364db 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -14,6 +14,7 @@
  * This driver supports the following ACCES devices: 104-DIO-48E and
  * 104-DIO-24E.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -182,6 +183,51 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return !!(port_state & mask);
 }
 
+static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
+	size_t i;
+	const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(dio48egpio->base + ports[i]);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
@@ -384,6 +430,7 @@ static int dio48e_probe(struct device *dev, unsigned int id)
 	dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
 	dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
 	dio48egpio->chip.get = dio48e_gpio_get;
+	dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple;
 	dio48egpio->chip.set = dio48e_gpio_set;
 	dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
 	dio48egpio->base = base[id];
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 6/8] gpio: 104-idi-48: Implement get_multiple callback
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
                   ` (4 preceding siblings ...)
  2018-03-17 15:51 ` [PATCH v3 5/8] gpio: 104-dio-48e: Implement get_multiple callback William Breathitt Gray
@ 2018-03-17 15:51 ` William Breathitt Gray
  2018-03-17 15:51 ` [PATCH v3 7/8] gpio: gpio-mm: " William Breathitt Gray
  2018-03-17 15:52 ` [PATCH v3 8/8] gpio: ws16c48: " William Breathitt Gray
  7 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:51 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

The ACCES I/O 104-IDI-48 series of devices provides 48
optically-isolated inputs accessed via six 8-bit ports. Since eight
input lines are acquired on a single port input read, the 104-IDI-48
GPIO driver may improve multiple input reads by utilizing a get_multiple
callback. This patch implements the idi_48_gpio_get_multiple function
which serves as the respective get_multiple callback.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/gpio/gpio-104-idi-48.c | 47 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index add859d59766..2c230415eeba 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -14,6 +14,7 @@
  * This driver supports the following ACCES devices: 104-IDI-48A,
  * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -88,6 +89,51 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return 0;
 }
 
+static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+	size_t i;
+	const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(idi48gpio->base + ports[i]);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void idi_48_irq_ack(struct irq_data *data)
 {
 }
@@ -256,6 +302,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
 	idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
 	idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
 	idi48gpio->chip.get = idi_48_gpio_get;
+	idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
 	idi48gpio->base = base[id];
 
 	raw_spin_lock_init(&idi48gpio->lock);
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 7/8] gpio: gpio-mm: Implement get_multiple callback
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
                   ` (5 preceding siblings ...)
  2018-03-17 15:51 ` [PATCH v3 6/8] gpio: 104-idi-48: " William Breathitt Gray
@ 2018-03-17 15:51 ` William Breathitt Gray
  2018-03-17 15:52 ` [PATCH v3 8/8] gpio: ws16c48: " William Breathitt Gray
  7 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:51 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

The Diamond Systems GPIO-MM series of devices contain two 82C55A
devices, which each feature three 8-bit ports of I/O. Since eight input
lines are acquired on a single port input read, the GPIO-MM GPIO driver
may improve multiple input reads by utilizing a get_multiple callback.
This patch implements the gpiomm_gpio_get_multiple function which serves
as the respective get_multiple callback.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/gpio/gpio-gpio-mm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c
index 11ade5b288f8..94b86fca65ba 100644
--- a/drivers/gpio/gpio-gpio-mm.c
+++ b/drivers/gpio/gpio-gpio-mm.c
@@ -14,6 +14,7 @@
  * This driver supports the following Diamond Systems devices: GPIO-MM and
  * GPIO-MM-12.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -171,6 +172,51 @@ static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(port_state & mask);
 }
 
+static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+	size_t i;
+	const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(gpiommgpio->base + ports[i]);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -268,6 +314,7 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
 	gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
 	gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
 	gpiommgpio->chip.get = gpiomm_gpio_get;
+	gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
 	gpiommgpio->chip.set = gpiomm_gpio_set;
 	gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
 	gpiommgpio->base = base[id];
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 8/8] gpio: ws16c48: Implement get_multiple callback
  2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
                   ` (6 preceding siblings ...)
  2018-03-17 15:51 ` [PATCH v3 7/8] gpio: gpio-mm: " William Breathitt Gray
@ 2018-03-17 15:52 ` William Breathitt Gray
  7 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 15:52 UTC (permalink / raw)
  To: linus.walleij
  Cc: andy.shevchenko, linux-gpio, linux-kernel, linux-iio,
	William Breathitt Gray

The WinSystems WS16C48 device provides 48 lines of digital I/O accessed
via six 8-bit ports. Since eight input lines are acquired on a single
port input read, the WS16C48 GPIO driver may improve multiple input
reads by utilizing a get_multiple callback. This patch implements the
ws16c48_gpio_get_multiple function which serves as the respective
get_multiple callback.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 drivers/gpio/gpio-ws16c48.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index 746648244bf3..10525367aa6f 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -11,6 +11,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -129,6 +130,51 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return !!(port_state & mask);
 }
 
+static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
+	const unsigned int gpio_reg_size = 8;
+	size_t i;
+	const size_t num_ports = chip->ngpio / gpio_reg_size;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < num_ports; i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(ws16c48gpio->base + i);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
@@ -383,6 +429,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
 	ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input;
 	ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
 	ws16c48gpio->chip.get = ws16c48_gpio_get;
+	ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple;
 	ws16c48gpio->chip.set = ws16c48_gpio_set;
 	ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
 	ws16c48gpio->base = base[id];
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 1/8] iio: stx104: Implement get_multiple callback
  2018-03-17 15:49 ` [PATCH v3 1/8] iio: stx104: Implement get_multiple callback William Breathitt Gray
@ 2018-03-17 18:22   ` Jonathan Cameron
  2018-03-17 18:51   ` Andy Shevchenko
  1 sibling, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2018-03-17 18:22 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: linus.walleij, andy.shevchenko, linux-gpio, linux-kernel,
	linux-iio, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler

On Sat, 17 Mar 2018 11:49:56 -0400
William Breathitt Gray <vilhelm.gray@gmail.com> wrote:

> The Apex Embedded Systems STX104 series of devices provides 4 TTL
> compatible lines of inputs accessed via a single 4-bit port. Since four
> input lines are acquired on a single port input read, the STX104 GPIO
> driver may improve multiple input reads by utilizing a get_multiple
> callback. This patch implements the stx104_gpio_get_multiple function
> which serves as the respective get_multiple callback.
> 
> Cc: Jonathan Cameron <jic23@kernel.org>
> Cc: Hartmut Knaack <knaack.h@gmx.de>
> Cc: Lars-Peter Clausen <lars@metafoo.de>
> Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
This one is simple so applied to the togreg branch of iio.git and pushed
out as testing for the autobuilders to play with it.

Thanks,

Jonathan

> ---
>  drivers/iio/adc/stx104.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c
> index 17b021f33180..0662ca199eb0 100644
> --- a/drivers/iio/adc/stx104.c
> +++ b/drivers/iio/adc/stx104.c
> @@ -233,6 +233,16 @@ static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
>  	return !!(inb(stx104gpio->base) & BIT(offset));
>  }
>  
> +static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
> +	unsigned long *bits)
> +{
> +	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
> +
> +	*bits = inb(stx104gpio->base);
> +
> +	return 0;
> +}
> +
>  static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
>  	int value)
>  {
> @@ -342,6 +352,7 @@ static int stx104_probe(struct device *dev, unsigned int id)
>  	stx104gpio->chip.direction_input = stx104_gpio_direction_input;
>  	stx104gpio->chip.direction_output = stx104_gpio_direction_output;
>  	stx104gpio->chip.get = stx104_gpio_get;
> +	stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
>  	stx104gpio->chip.set = stx104_gpio_set;
>  	stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
>  	stx104gpio->base = base[id] + 3;

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 1/8] iio: stx104: Implement get_multiple callback
  2018-03-17 15:49 ` [PATCH v3 1/8] iio: stx104: Implement get_multiple callback William Breathitt Gray
  2018-03-17 18:22   ` Jonathan Cameron
@ 2018-03-17 18:51   ` Andy Shevchenko
  2018-03-17 19:15     ` William Breathitt Gray
  1 sibling, 1 reply; 16+ messages in thread
From: Andy Shevchenko @ 2018-03-17 18:51 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: Linus Walleij, open list:GPIO SUBSYSTEM,
	Linux Kernel Mailing List, linux-iio, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler

On Sat, Mar 17, 2018 at 5:49 PM, William Breathitt Gray
<vilhelm.gray@gmail.com> wrote:
> The Apex Embedded Systems STX104 series of devices provides 4 TTL
> compatible lines of inputs accessed via a single 4-bit port. Since four
> input lines are acquired on a single port input read, the STX104 GPIO
> driver may improve multiple input reads by utilizing a get_multiple
> callback. This patch implements the stx104_gpio_get_multiple function
> which serves as the respective get_multiple callback.

> +static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
> +       unsigned long *bits)
> +{
> +       struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
> +

> +       *bits = inb(stx104gpio->base);

I think on LE and BE if will give you different results.

> +
> +       return 0;
> +}



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 1/8] iio: stx104: Implement get_multiple callback
  2018-03-17 18:51   ` Andy Shevchenko
@ 2018-03-17 19:15     ` William Breathitt Gray
  0 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-17 19:15 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Linus Walleij, open list:GPIO SUBSYSTEM,
	Linux Kernel Mailing List, linux-iio, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler

On Sat, Mar 17, 2018 at 08:51:07PM +0200, Andy Shevchenko wrote:
>On Sat, Mar 17, 2018 at 5:49 PM, William Breathitt Gray
><vilhelm.gray@gmail.com> wrote:
>> The Apex Embedded Systems STX104 series of devices provides 4 TTL
>> compatible lines of inputs accessed via a single 4-bit port. Since four
>> input lines are acquired on a single port input read, the STX104 GPIO
>> driver may improve multiple input reads by utilizing a get_multiple
>> callback. This patch implements the stx104_gpio_get_multiple function
>> which serves as the respective get_multiple callback.
>
>> +static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
>> +       unsigned long *bits)
>> +{
>> +       struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
>> +
>
>> +       *bits = inb(stx104gpio->base);
>
>I think on LE and BE if will give you different results.

That may be true for a memcpy operation, but in this case I'm relying on
the standard C evaluation rules. I expect we should be fine with the
returned byte assigned to an unsigned long, since it'll be evaluated by
its value rather than memory representation.

William Breathitt Gray

>
>> +
>> +       return 0;
>> +}
>
>
>
>-- 
>With Best Regards,
>Andy Shevchenko

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 2/8] gpio: 104-idio-16: Implement get_multiple callback
  2018-03-17 15:50 ` [PATCH v3 2/8] gpio: 104-idio-16: " William Breathitt Gray
@ 2018-03-21 15:32   ` Andy Shevchenko
  2018-03-21 16:04     ` William Breathitt Gray
  0 siblings, 1 reply; 16+ messages in thread
From: Andy Shevchenko @ 2018-03-21 15:32 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: Linus Walleij, open list:GPIO SUBSYSTEM,
	Linux Kernel Mailing List, linux-iio

On Sat, Mar 17, 2018 at 5:50 PM, William Breathitt Gray
<vilhelm.gray@gmail.com> wrote:
> The ACCES I/O 104-IDIO-16 series of devices provides 16
> optically-isolated digital inputs accessed via two 8-bit ports. Since
> eight input lines are acquired on a single port input read, the
> 104-IDIO-16 GPIO driver may improve multiple input reads by utilizing a
> get_multiple callback. This patch implements the
> idio_16_gpio_get_multiple function which serves as the respective
> get_multiple callback.

> +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);
> +
> +       *bits = 0;

> +       if (*mask & 0xFF0000)

GENMASK(23, 16) ?

> +               *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;

Do you need casting?

> +       if (*mask & 0xFF000000)

GENMASK(31, 24) ?

Alternative (and for above):

(*mask >> 24) & 0xff

(*mask >> 16) & 0xff


> +               *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;

Do you need casting?

> +
> +       return 0;
> +}
> +
>  static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
>  {
>         struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
> @@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
>         idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
>         idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
>         idio16gpio->chip.get = idio_16_gpio_get;
> +       idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
>         idio16gpio->chip.set = idio_16_gpio_set;
>         idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
>         idio16gpio->base = base[id];
> --
> 2.16.2
>



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 2/8] gpio: 104-idio-16: Implement get_multiple callback
  2018-03-21 15:32   ` Andy Shevchenko
@ 2018-03-21 16:04     ` William Breathitt Gray
  0 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-21 16:04 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Linus Walleij, open list:GPIO SUBSYSTEM,
	Linux Kernel Mailing List, linux-iio

On Wed, Mar 21, 2018 at 05:32:03PM +0200, Andy Shevchenko wrote:
>On Sat, Mar 17, 2018 at 5:50 PM, William Breathitt Gray
><vilhelm.gray@gmail.com> wrote:
>> The ACCES I/O 104-IDIO-16 series of devices provides 16
>> optically-isolated digital inputs accessed via two 8-bit ports. Since
>> eight input lines are acquired on a single port input read, the
>> 104-IDIO-16 GPIO driver may improve multiple input reads by utilizing a
>> get_multiple callback. This patch implements the
>> idio_16_gpio_get_multiple function which serves as the respective
>> get_multiple callback.
>
>> +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);
>> +
>> +       *bits = 0;
>
>> +       if (*mask & 0xFF0000)
>
>GENMASK(23, 16) ?
>
>> +               *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
>
>Do you need casting?
>
>> +       if (*mask & 0xFF000000)
>
>GENMASK(31, 24) ?
>
>Alternative (and for above):
>
>(*mask >> 24) & 0xff
>
>(*mask >> 16) & 0xff

That's a good suggestion since GENMASK would be useful in making it
clear which bits we are actually checking; the literal bitmasks such as
0xFF000000 can be difficult to read at a glance. I'll incorporate
GENMASK into a version 4 release of this patch.

>
>
>> +               *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
>
>Do you need casting?

The inb function returns a u8, which is typically a typedef of an
unsigned char. Since u8 only guaranteed a range of 8 bits, we require a
cast to unsigned long to guarantee that the left shifted value stays
intact as a 32-bit unsigned value rather than wrap around an 8-bit
unsigned range.

William Breathitt Gray

>
>> +
>> +       return 0;
>> +}
>> +
>>  static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
>>  {
>>         struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
>> @@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
>>         idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
>>         idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
>>         idio16gpio->chip.get = idio_16_gpio_get;
>> +       idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
>>         idio16gpio->chip.set = idio_16_gpio_set;
>>         idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
>>         idio16gpio->base = base[id];
>> --
>> 2.16.2
>>
>
>
>
>-- 
>With Best Regards,
>Andy Shevchenko

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/8] gpio: pci-idio-16: Implement get_multiple callback
  2018-03-17 15:50 ` [PATCH v3 3/8] gpio: pci-idio-16: " William Breathitt Gray
@ 2018-03-21 17:45   ` Andy Shevchenko
  2018-03-21 18:49     ` William Breathitt Gray
  0 siblings, 1 reply; 16+ messages in thread
From: Andy Shevchenko @ 2018-03-21 17:45 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: Linus Walleij, open list:GPIO SUBSYSTEM,
	Linux Kernel Mailing List, linux-iio

On Sat, Mar 17, 2018 at 5:50 PM, William Breathitt Gray
<vilhelm.gray@gmail.com> wrote:
> The ACCES I/O PCI-IDIO-16 series of devices provides 16
> optically-isolated digital inputs accessed via two 8-bit ports. Since
> eight input lines are acquired on a single port input read, the
> PCI-IDIO-16 GPIO driver may improve multiple input reads by utilizing a
> get_multiple callback. This patch implements the
> idio_16_gpio_get_multiple function which serves as the respective
> get_multiple callback.

> +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);
> +       size_t i;
> +       const unsigned int gpio_reg_size = 8;
> +       unsigned int bits_offset;
> +       size_t word_index;
> +       unsigned int word_offset;
> +       unsigned long word_mask;

> +       const unsigned long port_mask = GENMASK(gpio_reg_size, 0);

gpio_reg_size - 1?
Though I would prefer not to have that variable at all, just use 8 or
7 respectively.

> +       unsigned long port_state;

> +       u8 __iomem ports[] = {
> +               idio16gpio->reg->out0_7, idio16gpio->reg->out8_15,

> +               idio16gpio->reg->in0_7, idio16gpio->reg->in8_15

I would leave comma even here.

> +       };

> +       /* get bits are evaluated a gpio port register at a time */
> +       for (i = 0; i < ARRAY_SIZE(ports); i++) {
> +               /* gpio offset in bits array */
> +               bits_offset = i * gpio_reg_size;
> +
> +               /* word index for bits array */
> +               word_index = BIT_WORD(bits_offset);
> +
> +               /* gpio offset within current word of bits array */
> +               word_offset = bits_offset % BITS_PER_LONG;
> +
> +               /* mask of get bits for current gpio within current word */
> +               word_mask = mask[word_index] & (port_mask << word_offset);
> +               if (!word_mask) {
> +                       /* no get bits in this port so skip to next one */
> +                       continue;
> +               }
> +
> +               /* read bits from current gpio port */
> +               port_state = ioread8(ports + i);
> +
> +               /* store acquired bits at respective bits array offset */
> +               bits[word_index] |= port_state << word_offset;
> +       }

I would propose to do other way around, i.e.
read all ports to the bitmap array and call bitmap_and() after.

Further optimization can be something like introduction of generic

bitmap_copy_uXX_off(unsigned long *dst, u8 src, unsigned int offset);

It can be done using macros, though it's another story not quite
related to the topic.

> +}

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/8] gpio: pci-idio-16: Implement get_multiple callback
  2018-03-21 17:45   ` Andy Shevchenko
@ 2018-03-21 18:49     ` William Breathitt Gray
  0 siblings, 0 replies; 16+ messages in thread
From: William Breathitt Gray @ 2018-03-21 18:49 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Linus Walleij, open list:GPIO SUBSYSTEM,
	Linux Kernel Mailing List, linux-iio

On Wed, Mar 21, 2018 at 07:45:29PM +0200, Andy Shevchenko wrote:
>On Sat, Mar 17, 2018 at 5:50 PM, William Breathitt Gray
><vilhelm.gray@gmail.com> wrote:
>> The ACCES I/O PCI-IDIO-16 series of devices provides 16
>> optically-isolated digital inputs accessed via two 8-bit ports. Since
>> eight input lines are acquired on a single port input read, the
>> PCI-IDIO-16 GPIO driver may improve multiple input reads by utilizing a
>> get_multiple callback. This patch implements the
>> idio_16_gpio_get_multiple function which serves as the respective
>> get_multiple callback.
>
>> +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);
>> +       size_t i;
>> +       const unsigned int gpio_reg_size = 8;
>> +       unsigned int bits_offset;
>> +       size_t word_index;
>> +       unsigned int word_offset;
>> +       unsigned long word_mask;
>
>> +       const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
>
>gpio_reg_size - 1?

Oops, looks like I made an off-by-one error here so I'll make sure to
fix that up.

>Though I would prefer not to have that variable at all, just use 8 or
>7 respectively.

This device is simple enough that throughout this function I could
inline gpio_reg_size and port_mask to 8 and 0xFF respectively, but I
would like to keep the code generic enough for reuse in other drivers.
In addition, I believe the variable names help keep the intention of the
code clear, so I'll stick with dedicated const variables for now if
there are no other objections.

>
>> +       unsigned long port_state;
>
>> +       u8 __iomem ports[] = {
>> +               idio16gpio->reg->out0_7, idio16gpio->reg->out8_15,
>
>> +               idio16gpio->reg->in0_7, idio16gpio->reg->in8_15
>
>I would leave comma even here.

Will do.

>
>> +       };
>
>> +       /* get bits are evaluated a gpio port register at a time */
>> +       for (i = 0; i < ARRAY_SIZE(ports); i++) {
>> +               /* gpio offset in bits array */
>> +               bits_offset = i * gpio_reg_size;
>> +
>> +               /* word index for bits array */
>> +               word_index = BIT_WORD(bits_offset);
>> +
>> +               /* gpio offset within current word of bits array */
>> +               word_offset = bits_offset % BITS_PER_LONG;
>> +
>> +               /* mask of get bits for current gpio within current word */
>> +               word_mask = mask[word_index] & (port_mask << word_offset);
>> +               if (!word_mask) {
>> +                       /* no get bits in this port so skip to next one */
>> +                       continue;
>> +               }
>> +
>> +               /* read bits from current gpio port */
>> +               port_state = ioread8(ports + i);
>> +
>> +               /* store acquired bits at respective bits array offset */
>> +               bits[word_index] |= port_state << word_offset;
>> +       }
>
>I would propose to do other way around, i.e.
>read all ports to the bitmap array and call bitmap_and() after.
>
>Further optimization can be something like introduction of generic
>
>bitmap_copy_uXX_off(unsigned long *dst, u8 src, unsigned int offset);
>
>It can be done using macros, though it's another story not quite
>related to the topic.

Port I/O is significantly more costly to perform than the bitmask
evaluations for each port. Despite the increased complexity of the loop
logic, I believe the latency improvements of skipping unnecessary I/O
port reads are worth the trouble.

I do like the idea of a bitmap_copy_uXX_off macro as that could be quite
useful in general. Even if not for this particular patchset, I would be
interested in seeing that functionality added to the bitmap API. Perhaps
I might implement it as a standlone patch when I have some free time.

William Breathitt Gray

>
>> +}
>
>-- 
>With Best Regards,
>Andy Shevchenko

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2018-03-21 18:49 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-17 15:49 [PATCH v3 0/8] Implement get_multiple for ACCES and PC/104 drivers William Breathitt Gray
2018-03-17 15:49 ` [PATCH v3 1/8] iio: stx104: Implement get_multiple callback William Breathitt Gray
2018-03-17 18:22   ` Jonathan Cameron
2018-03-17 18:51   ` Andy Shevchenko
2018-03-17 19:15     ` William Breathitt Gray
2018-03-17 15:50 ` [PATCH v3 2/8] gpio: 104-idio-16: " William Breathitt Gray
2018-03-21 15:32   ` Andy Shevchenko
2018-03-21 16:04     ` William Breathitt Gray
2018-03-17 15:50 ` [PATCH v3 3/8] gpio: pci-idio-16: " William Breathitt Gray
2018-03-21 17:45   ` Andy Shevchenko
2018-03-21 18:49     ` William Breathitt Gray
2018-03-17 15:51 ` [PATCH v3 4/8] gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks William Breathitt Gray
2018-03-17 15:51 ` [PATCH v3 5/8] gpio: 104-dio-48e: Implement get_multiple callback William Breathitt Gray
2018-03-17 15:51 ` [PATCH v3 6/8] gpio: 104-idi-48: " William Breathitt Gray
2018-03-17 15:51 ` [PATCH v3 7/8] gpio: gpio-mm: " William Breathitt Gray
2018-03-17 15:52 ` [PATCH v3 8/8] gpio: ws16c48: " William Breathitt Gray

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.