Implement get_multiple for ACCES and PC/104 drivers
Subsystems (8)
v4 cover Implement get_multiple for ACCES and PC/104 drivers
Changes in v4:
- Remove STX104 patch as it has been picked up through the IIO tree
- Utilize GENMASK for 104-IDIO-16 patch to avoid long literal bitmasks
- Fix off-by-one errors for port_mask initializations
- Add end comma to ports arrays initializations for consistency
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 (7):
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 ++++++++++++++++ 7 files changed, 370 insertions(+)
Signature · 1 line
2.16.2
PATCH v4 1/7 gpio: 104-idio-16: Implement get_multiple callback
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.
--- drivers/gpio/gpio-104-idio-16.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/gpio/gpio-104-idio-16.c +15 -0
@@ -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 &GENMASK (23 ,16 )) + *bits |= (unsigned long )inb (idio16gpio->base +1 ) <<16 ; +if (*mask &GENMASK (31 ,24 )) + *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];
Signature · 1 line
2.16.2
Re: [PATCH v4 1/7] gpio: 104-idio-16: Implement get_multiple callback
Quoted 9 lines · 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_multiplecallback. This patch implements theidio_16_gpio_get_multiplefunction which serves as the respectiveget_multiplecallback.Signed-off-by William Breathitt Gray <[email protected]>
Patch applied.
Yours,
Linus Walleij
PATCH v4 2/7 gpio: pci-idio-16: Implement get_multiple callback
In reply to William Breathitt GrayThe 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.
--- drivers/gpio/gpio-pci-idio-16.c | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
drivers/gpio/gpio-pci-idio-16.c +50 -0
@@ -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 -1 ,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;
Signature · 1 line
2.16.2
Re: [PATCH v4 2/7] gpio: pci-idio-16: Implement get_multiple callback
Quoted 9 lines · 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_multiplecallback. This patch implements theidio_16_gpio_get_multiplefunction which serves as the respectiveget_multiplecallback.Signed-off-by William Breathitt Gray <[email protected]>
Patch applied.
Yours,
Linus Walleij
PATCH v4 3/7 gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks
In reply to William Breathitt GrayThe 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.
--- drivers/gpio/gpio-pcie-idio-24.c | 117 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+)
drivers/gpio/gpio-pcie-idio-24.c +117 -0
@@ -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 -1 ,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);
Signature · 1 line
2.16.2
Re: [PATCH v4 3/7] gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks
Quoted 11 lines · 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_multiplefunction which serves as the respectiveget_multiplecallback, and implements theidio_24_gpio_set_multiplefunction which serves as the respectiveset_multiplecallback.Signed-off-by William Breathitt Gray <[email protected]>
Patch applied.
Yours,
Linus Walleij
PATCH v4 4/7 gpio: 104-dio-48e: Implement get_multiple callback
In reply to William Breathitt GrayThe 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.
--- drivers/gpio/gpio-104-dio-48e.c | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
drivers/gpio/gpio-104-dio-48e.c +47 -0
@@ -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 -1 ,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];
Signature · 1 line
2.16.2
PATCH v4 5/7 gpio: 104-idi-48: Implement get_multiple callback
In reply to William Breathitt GrayThe 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.
--- drivers/gpio/gpio-104-idi-48.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
drivers/gpio/gpio-104-idi-48.c +47 -0
@@ -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 -1 ,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);
Signature · 1 line
2.16.2
Re: [PATCH v4 5/7] gpio: 104-idi-48: Implement get_multiple callback
Quoted 8 lines · 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_multiplecallback. This patch implements theidi_48_gpio_get_multiplefunction which serves as the respectiveget_multiplecallback.Signed-off-by William Breathitt Gray <[email protected]>
Patch applied.
Yours,
Linus Walleij
PATCH v4 6/7 gpio: gpio-mm: Implement get_multiple callback
In reply to William Breathitt GrayThe 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.
--- drivers/gpio/gpio-gpio-mm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
drivers/gpio/gpio-gpio-mm.c +47 -0
@@ -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 -1 ,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];
Signature · 1 line
2.16.2
Re: [PATCH v4 6/7] gpio: gpio-mm: Implement get_multiple callback
Quoted 8 lines · 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_multiplecallback. This patch implements thegpiomm_gpio_get_multiplefunction which serves as the respectiveget_multiplecallback.Signed-off-by William Breathitt Gray <[email protected]>
Patch applied.
Yours,
Linus Walleij
PATCH v4 7/7 gpio: ws16c48: Implement get_multiple callback
In reply to William Breathitt GrayThe 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.
--- drivers/gpio/gpio-ws16c48.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
drivers/gpio/gpio-ws16c48.c +47 -0
@@ -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 -1 ,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];
Signature · 1 line
2.16.2
Quoted 1 line · William Breathitt Gray
Changes in v4:
I applied the v4 patch set so we get some rotation in linux-next before the merge window.
If reviewers still find smallish issues they can certainly be fixed in follow-up patches.
Quoted 5 lines
This patchset implements
get_multiplecallbacks 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 theget_multiplecallback can provide improvement for those users who regularly access multiple input lines.
Did you use the userspace chardev for some interesting experiments with your set-ups?
I tend to think of your applications as pretty interesting for industry peers, and a good proof-of-concept for the userspace API.
Quoted 4 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.
Oh!
This guy?
https://en.wikipedia.org/wiki/Intel_8255
Yeah that makes all kind of sense. We are living with the legacy of the first PCs every day when it comes own to EISA & friends...
Yours,
Linus Walleij
Quoted 17 lines · Linus Walleij
Quoted 1 line · William Breathitt Gray
Changes in v4:
I applied the v4 patch set so we get some rotation in linux-next before the merge window.
If reviewers still find smallish issues they can certainly be fixed in follow-up patches.
Quoted 5 lines
This patchset implements
get_multiplecallbacks 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 theget_multiplecallback can provide improvement for those users who regularly access multiple input lines.
Quoted 5 lines
Did you use the userspace chardev for some interesting experiments with your set-ups?
I tend to think of your applications as pretty interesting for industry peers, and a good proof-of-concept for the userspace API.
I use these PC104 drivers in several semi-realtime critical applications, so latency has always been a big concern for me. The switch from sysfs file I/O to chardev ioctl had a great improvement in the reduction of latency, which I was very happy to utilize.
Since the next big point of latency in my systems have been port I/O, taking advantage of the get_multiple/set_multiple functionality is my next goal in optimization. I have a new system coming out soon that uses the 104-IDI-48 for input -- it'll be interesting to see the performance improvements of acquiring the entire input port at a time, rather than every GPIO line individually.
Quoted 6 lines
Quoted 5 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.
Quoted 6 lines
Oh!
This guy?
https://en.wikipedia.org/wiki/Intel_8255Yeah that makes all kind of sense. We are living with the legacy of the first PCs every day when it comes own to EISA & friends...
That's the one! I see this interface a lot in the GPIO devices I handle. It's very popular, which I believe is a testament to the popularity of the IBM PC.
Nowadays, most devices I encounter implement this interface in an FPGA, but I do occasionally come across the actual Intel 82C55 chip, such as on the 104-DIO-48E; it's fascinating to see this physical chip still popping up on circuit boards from time to time.
I would like to make a generic driver for this interface that will allow it to be used both in the port I/O and memory I/O drivers out there. Since I don't want to introduce too many changes in a single patchset I've postponed it for now to get get_multiple support merged in for these drivers, but I'll hopefully have something like a gpio-i8255 driver submitted soon enough.
William Breathitt Gray
Quoted 3 lines
Yours,
Linus Walleij