| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * GPIO driver for the Diamond Systems GPIO-MM |
|---|
| 3 | 4 | * Copyright (C) 2016 William Breathitt Gray |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 6 | | - * it under the terms of the GNU General Public License, version 2, as |
|---|
| 7 | | - * published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 10 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 12 | | - * General Public License for more details. |
|---|
| 13 | 5 | * |
|---|
| 14 | 6 | * This driver supports the following Diamond Systems devices: GPIO-MM and |
|---|
| 15 | 7 | * GPIO-MM-12. |
|---|
| .. | .. |
|---|
| 60 | 52 | const unsigned int port = offset / 8; |
|---|
| 61 | 53 | const unsigned int mask = BIT(offset % 8); |
|---|
| 62 | 54 | |
|---|
| 63 | | - return !!(gpiommgpio->io_state[port] & mask); |
|---|
| 55 | + if (gpiommgpio->io_state[port] & mask) |
|---|
| 56 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 57 | + |
|---|
| 58 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 64 | 59 | } |
|---|
| 65 | 60 | |
|---|
| 66 | 61 | static int gpiomm_gpio_direction_input(struct gpio_chip *chip, |
|---|
| .. | .. |
|---|
| 172 | 167 | return !!(port_state & mask); |
|---|
| 173 | 168 | } |
|---|
| 174 | 169 | |
|---|
| 170 | +static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; |
|---|
| 171 | + |
|---|
| 175 | 172 | static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, |
|---|
| 176 | 173 | unsigned long *bits) |
|---|
| 177 | 174 | { |
|---|
| 178 | 175 | struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); |
|---|
| 179 | | - size_t i; |
|---|
| 180 | | - static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; |
|---|
| 181 | | - const unsigned int gpio_reg_size = 8; |
|---|
| 182 | | - unsigned int bits_offset; |
|---|
| 183 | | - size_t word_index; |
|---|
| 184 | | - unsigned int word_offset; |
|---|
| 185 | | - unsigned long word_mask; |
|---|
| 186 | | - const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); |
|---|
| 176 | + unsigned long offset; |
|---|
| 177 | + unsigned long gpio_mask; |
|---|
| 178 | + unsigned int port_addr; |
|---|
| 187 | 179 | unsigned long port_state; |
|---|
| 188 | 180 | |
|---|
| 189 | 181 | /* clear bits array to a clean slate */ |
|---|
| 190 | 182 | bitmap_zero(bits, chip->ngpio); |
|---|
| 191 | 183 | |
|---|
| 192 | | - /* get bits are evaluated a gpio port register at a time */ |
|---|
| 193 | | - for (i = 0; i < ARRAY_SIZE(ports); i++) { |
|---|
| 194 | | - /* gpio offset in bits array */ |
|---|
| 195 | | - bits_offset = i * gpio_reg_size; |
|---|
| 184 | + for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { |
|---|
| 185 | + port_addr = gpiommgpio->base + ports[offset / 8]; |
|---|
| 186 | + port_state = inb(port_addr) & gpio_mask; |
|---|
| 196 | 187 | |
|---|
| 197 | | - /* word index for bits array */ |
|---|
| 198 | | - word_index = BIT_WORD(bits_offset); |
|---|
| 199 | | - |
|---|
| 200 | | - /* gpio offset within current word of bits array */ |
|---|
| 201 | | - word_offset = bits_offset % BITS_PER_LONG; |
|---|
| 202 | | - |
|---|
| 203 | | - /* mask of get bits for current gpio within current word */ |
|---|
| 204 | | - word_mask = mask[word_index] & (port_mask << word_offset); |
|---|
| 205 | | - if (!word_mask) { |
|---|
| 206 | | - /* no get bits in this port so skip to next one */ |
|---|
| 207 | | - continue; |
|---|
| 208 | | - } |
|---|
| 209 | | - |
|---|
| 210 | | - /* read bits from current gpio port */ |
|---|
| 211 | | - port_state = inb(gpiommgpio->base + ports[i]); |
|---|
| 212 | | - |
|---|
| 213 | | - /* store acquired bits at respective bits array offset */ |
|---|
| 214 | | - bits[word_index] |= port_state << word_offset; |
|---|
| 188 | + bitmap_set_value8(bits, port_state, offset); |
|---|
| 215 | 189 | } |
|---|
| 216 | 190 | |
|---|
| 217 | 191 | return 0; |
|---|
| .. | .. |
|---|
| 242 | 216 | unsigned long *mask, unsigned long *bits) |
|---|
| 243 | 217 | { |
|---|
| 244 | 218 | struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); |
|---|
| 245 | | - unsigned int i; |
|---|
| 246 | | - const unsigned int gpio_reg_size = 8; |
|---|
| 247 | | - unsigned int port; |
|---|
| 248 | | - unsigned int out_port; |
|---|
| 249 | | - unsigned int bitmask; |
|---|
| 219 | + unsigned long offset; |
|---|
| 220 | + unsigned long gpio_mask; |
|---|
| 221 | + size_t index; |
|---|
| 222 | + unsigned int port_addr; |
|---|
| 223 | + unsigned long bitmask; |
|---|
| 250 | 224 | unsigned long flags; |
|---|
| 251 | 225 | |
|---|
| 252 | | - /* set bits are evaluated a gpio register size at a time */ |
|---|
| 253 | | - for (i = 0; i < chip->ngpio; i += gpio_reg_size) { |
|---|
| 254 | | - /* no more set bits in this mask word; skip to the next word */ |
|---|
| 255 | | - if (!mask[BIT_WORD(i)]) { |
|---|
| 256 | | - i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size; |
|---|
| 257 | | - continue; |
|---|
| 258 | | - } |
|---|
| 226 | + for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { |
|---|
| 227 | + index = offset / 8; |
|---|
| 228 | + port_addr = gpiommgpio->base + ports[index]; |
|---|
| 259 | 229 | |
|---|
| 260 | | - port = i / gpio_reg_size; |
|---|
| 261 | | - out_port = (port > 2) ? port + 1 : port; |
|---|
| 262 | | - bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)]; |
|---|
| 230 | + bitmask = bitmap_get_value8(bits, offset) & gpio_mask; |
|---|
| 263 | 231 | |
|---|
| 264 | 232 | spin_lock_irqsave(&gpiommgpio->lock, flags); |
|---|
| 265 | 233 | |
|---|
| 266 | 234 | /* update output state data and set device gpio register */ |
|---|
| 267 | | - gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)]; |
|---|
| 268 | | - gpiommgpio->out_state[port] |= bitmask; |
|---|
| 269 | | - outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); |
|---|
| 235 | + gpiommgpio->out_state[index] &= ~gpio_mask; |
|---|
| 236 | + gpiommgpio->out_state[index] |= bitmask; |
|---|
| 237 | + outb(gpiommgpio->out_state[index], port_addr); |
|---|
| 270 | 238 | |
|---|
| 271 | 239 | spin_unlock_irqrestore(&gpiommgpio->lock, flags); |
|---|
| 272 | | - |
|---|
| 273 | | - /* prepare for next gpio register set */ |
|---|
| 274 | | - mask[BIT_WORD(i)] >>= gpio_reg_size; |
|---|
| 275 | | - bits[BIT_WORD(i)] >>= gpio_reg_size; |
|---|
| 276 | 240 | } |
|---|
| 277 | 241 | } |
|---|
| 278 | 242 | |
|---|