Skip to content

Commit ca37081

Browse files
William Breathitt Graylinusw
authored andcommitted
gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks
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> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent 810ebfc commit ca37081

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

drivers/gpio/gpio-pcie-idio-24.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* This driver supports the following ACCES devices: PCIe-IDIO-24,
1616
* PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
1717
*/
18+
#include <linux/bitmap.h>
1819
#include <linux/bitops.h>
1920
#include <linux/device.h>
2021
#include <linux/errno.h>
@@ -193,6 +194,61 @@ static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
193194
return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
194195
}
195196

197+
static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
198+
unsigned long *mask, unsigned long *bits)
199+
{
200+
struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
201+
size_t i;
202+
const unsigned int gpio_reg_size = 8;
203+
unsigned int bits_offset;
204+
size_t word_index;
205+
unsigned int word_offset;
206+
unsigned long word_mask;
207+
const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
208+
unsigned long port_state;
209+
u8 __iomem ports[] = {
210+
idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
211+
idio24gpio->reg->out16_23, idio24gpio->reg->in0_7,
212+
idio24gpio->reg->in8_15, idio24gpio->reg->in16_23,
213+
};
214+
const unsigned long out_mode_mask = BIT(1);
215+
216+
/* clear bits array to a clean slate */
217+
bitmap_zero(bits, chip->ngpio);
218+
219+
/* get bits are evaluated a gpio port register at a time */
220+
for (i = 0; i < ARRAY_SIZE(ports); i++) {
221+
/* gpio offset in bits array */
222+
bits_offset = i * gpio_reg_size;
223+
224+
/* word index for bits array */
225+
word_index = BIT_WORD(bits_offset);
226+
227+
/* gpio offset within current word of bits array */
228+
word_offset = bits_offset % BITS_PER_LONG;
229+
230+
/* mask of get bits for current gpio within current word */
231+
word_mask = mask[word_index] & (port_mask << word_offset);
232+
if (!word_mask) {
233+
/* no get bits in this port so skip to next one */
234+
continue;
235+
}
236+
237+
/* read bits from current gpio port (port 6 is TTL GPIO) */
238+
if (i < 6)
239+
port_state = ioread8(ports + i);
240+
else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
241+
port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
242+
else
243+
port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
244+
245+
/* store acquired bits at respective bits array offset */
246+
bits[word_index] |= port_state << word_offset;
247+
}
248+
249+
return 0;
250+
}
251+
196252
static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
197253
int value)
198254
{
@@ -234,6 +290,65 @@ static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
234290
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
235291
}
236292

293+
static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
294+
unsigned long *mask, unsigned long *bits)
295+
{
296+
struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
297+
size_t i;
298+
unsigned long bits_offset;
299+
unsigned long gpio_mask;
300+
const unsigned int gpio_reg_size = 8;
301+
const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
302+
unsigned long flags;
303+
unsigned int out_state;
304+
u8 __iomem ports[] = {
305+
idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
306+
idio24gpio->reg->out16_23
307+
};
308+
const unsigned long out_mode_mask = BIT(1);
309+
const unsigned int ttl_offset = 48;
310+
const size_t ttl_i = BIT_WORD(ttl_offset);
311+
const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
312+
const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
313+
const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
314+
315+
/* set bits are processed a gpio port register at a time */
316+
for (i = 0; i < ARRAY_SIZE(ports); i++) {
317+
/* gpio offset in bits array */
318+
bits_offset = i * gpio_reg_size;
319+
320+
/* check if any set bits for current port */
321+
gpio_mask = (*mask >> bits_offset) & port_mask;
322+
if (!gpio_mask) {
323+
/* no set bits for this port so move on to next port */
324+
continue;
325+
}
326+
327+
raw_spin_lock_irqsave(&idio24gpio->lock, flags);
328+
329+
/* process output lines */
330+
out_state = ioread8(ports + i) & ~gpio_mask;
331+
out_state |= (*bits >> bits_offset) & gpio_mask;
332+
iowrite8(out_state, ports + i);
333+
334+
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
335+
}
336+
337+
/* check if setting TTL lines and if they are in output mode */
338+
if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
339+
return;
340+
341+
/* handle TTL output */
342+
raw_spin_lock_irqsave(&idio24gpio->lock, flags);
343+
344+
/* process output lines */
345+
out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
346+
out_state |= ttl_bits;
347+
iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
348+
349+
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
350+
}
351+
237352
static void idio_24_irq_ack(struct irq_data *data)
238353
{
239354
}
@@ -397,7 +512,9 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
397512
idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
398513
idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
399514
idio24gpio->chip.get = idio_24_gpio_get;
515+
idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
400516
idio24gpio->chip.set = idio_24_gpio_set;
517+
idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
401518

402519
raw_spin_lock_init(&idio24gpio->lock);
403520

0 commit comments

Comments
 (0)