diff options
author | William Breathitt Gray <vilhelm.gray@gmail.com> | 2018-03-22 09:00:31 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2018-03-26 04:26:38 -0400 |
commit | f72b10713cf5a9f6a425bdbd8da093cb02990d4d (patch) | |
tree | aec5655ad4d1cfda5778443588433d34e0b04dc3 | |
parent | d2d02bcdd52b889ec1bcabf8d0da6f3c2b87e9fc (diff) |
gpio: 104-idi-48: Implement get_multiple callback
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>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/gpio/gpio-104-idi-48.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index add859d59766..f35632609379 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * This driver supports the following ACCES devices: 104-IDI-48A, | 14 | * This driver supports the following ACCES devices: 104-IDI-48A, |
15 | * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. | 15 | * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. |
16 | */ | 16 | */ |
17 | #include <linux/bitmap.h> | ||
17 | #include <linux/bitops.h> | 18 | #include <linux/bitops.h> |
18 | #include <linux/device.h> | 19 | #include <linux/device.h> |
19 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
@@ -88,6 +89,51 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset) | |||
88 | return 0; | 89 | return 0; |
89 | } | 90 | } |
90 | 91 | ||
92 | static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, | ||
93 | unsigned long *bits) | ||
94 | { | ||
95 | struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); | ||
96 | size_t i; | ||
97 | const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; | ||
98 | const unsigned int gpio_reg_size = 8; | ||
99 | unsigned int bits_offset; | ||
100 | size_t word_index; | ||
101 | unsigned int word_offset; | ||
102 | unsigned long word_mask; | ||
103 | const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); | ||
104 | unsigned long port_state; | ||
105 | |||
106 | /* clear bits array to a clean slate */ | ||
107 | bitmap_zero(bits, chip->ngpio); | ||
108 | |||
109 | /* get bits are evaluated a gpio port register at a time */ | ||
110 | for (i = 0; i < ARRAY_SIZE(ports); i++) { | ||
111 | /* gpio offset in bits array */ | ||
112 | bits_offset = i * gpio_reg_size; | ||
113 | |||
114 | /* word index for bits array */ | ||
115 | word_index = BIT_WORD(bits_offset); | ||
116 | |||
117 | /* gpio offset within current word of bits array */ | ||
118 | word_offset = bits_offset % BITS_PER_LONG; | ||
119 | |||
120 | /* mask of get bits for current gpio within current word */ | ||
121 | word_mask = mask[word_index] & (port_mask << word_offset); | ||
122 | if (!word_mask) { | ||
123 | /* no get bits in this port so skip to next one */ | ||
124 | continue; | ||
125 | } | ||
126 | |||
127 | /* read bits from current gpio port */ | ||
128 | port_state = inb(idi48gpio->base + ports[i]); | ||
129 | |||
130 | /* store acquired bits at respective bits array offset */ | ||
131 | bits[word_index] |= port_state << word_offset; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
91 | static void idi_48_irq_ack(struct irq_data *data) | 137 | static void idi_48_irq_ack(struct irq_data *data) |
92 | { | 138 | { |
93 | } | 139 | } |
@@ -256,6 +302,7 @@ static int idi_48_probe(struct device *dev, unsigned int id) | |||
256 | idi48gpio->chip.get_direction = idi_48_gpio_get_direction; | 302 | idi48gpio->chip.get_direction = idi_48_gpio_get_direction; |
257 | idi48gpio->chip.direction_input = idi_48_gpio_direction_input; | 303 | idi48gpio->chip.direction_input = idi_48_gpio_direction_input; |
258 | idi48gpio->chip.get = idi_48_gpio_get; | 304 | idi48gpio->chip.get = idi_48_gpio_get; |
305 | idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple; | ||
259 | idi48gpio->base = base[id]; | 306 | idi48gpio->base = base[id]; |
260 | 307 | ||
261 | raw_spin_lock_init(&idi48gpio->lock); | 308 | raw_spin_lock_init(&idi48gpio->lock); |