| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * GPIO driver for the ACCES 104-DIO-48E series |
|---|
| 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 ACCES devices: 104-DIO-48E and |
|---|
| 15 | 7 | * 104-DIO-24E. |
|---|
| .. | .. |
|---|
| 67 | 59 | const unsigned port = offset / 8; |
|---|
| 68 | 60 | const unsigned mask = BIT(offset % 8); |
|---|
| 69 | 61 | |
|---|
| 70 | | - return !!(dio48egpio->io_state[port] & mask); |
|---|
| 62 | + if (dio48egpio->io_state[port] & mask) |
|---|
| 63 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 64 | + |
|---|
| 65 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 71 | 66 | } |
|---|
| 72 | 67 | |
|---|
| 73 | 68 | static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset) |
|---|
| .. | .. |
|---|
| 183 | 178 | return !!(port_state & mask); |
|---|
| 184 | 179 | } |
|---|
| 185 | 180 | |
|---|
| 181 | +static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; |
|---|
| 182 | + |
|---|
| 186 | 183 | static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, |
|---|
| 187 | 184 | unsigned long *bits) |
|---|
| 188 | 185 | { |
|---|
| 189 | 186 | struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); |
|---|
| 190 | | - size_t i; |
|---|
| 191 | | - static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; |
|---|
| 192 | | - const unsigned int gpio_reg_size = 8; |
|---|
| 193 | | - unsigned int bits_offset; |
|---|
| 194 | | - size_t word_index; |
|---|
| 195 | | - unsigned int word_offset; |
|---|
| 196 | | - unsigned long word_mask; |
|---|
| 197 | | - const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); |
|---|
| 187 | + unsigned long offset; |
|---|
| 188 | + unsigned long gpio_mask; |
|---|
| 189 | + unsigned int port_addr; |
|---|
| 198 | 190 | unsigned long port_state; |
|---|
| 199 | 191 | |
|---|
| 200 | 192 | /* clear bits array to a clean slate */ |
|---|
| 201 | 193 | bitmap_zero(bits, chip->ngpio); |
|---|
| 202 | 194 | |
|---|
| 203 | | - /* get bits are evaluated a gpio port register at a time */ |
|---|
| 204 | | - for (i = 0; i < ARRAY_SIZE(ports); i++) { |
|---|
| 205 | | - /* gpio offset in bits array */ |
|---|
| 206 | | - bits_offset = i * gpio_reg_size; |
|---|
| 195 | + for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { |
|---|
| 196 | + port_addr = dio48egpio->base + ports[offset / 8]; |
|---|
| 197 | + port_state = inb(port_addr) & gpio_mask; |
|---|
| 207 | 198 | |
|---|
| 208 | | - /* word index for bits array */ |
|---|
| 209 | | - word_index = BIT_WORD(bits_offset); |
|---|
| 210 | | - |
|---|
| 211 | | - /* gpio offset within current word of bits array */ |
|---|
| 212 | | - word_offset = bits_offset % BITS_PER_LONG; |
|---|
| 213 | | - |
|---|
| 214 | | - /* mask of get bits for current gpio within current word */ |
|---|
| 215 | | - word_mask = mask[word_index] & (port_mask << word_offset); |
|---|
| 216 | | - if (!word_mask) { |
|---|
| 217 | | - /* no get bits in this port so skip to next one */ |
|---|
| 218 | | - continue; |
|---|
| 219 | | - } |
|---|
| 220 | | - |
|---|
| 221 | | - /* read bits from current gpio port */ |
|---|
| 222 | | - port_state = inb(dio48egpio->base + ports[i]); |
|---|
| 223 | | - |
|---|
| 224 | | - /* store acquired bits at respective bits array offset */ |
|---|
| 225 | | - bits[word_index] |= port_state << word_offset; |
|---|
| 199 | + bitmap_set_value8(bits, port_state, offset); |
|---|
| 226 | 200 | } |
|---|
| 227 | 201 | |
|---|
| 228 | 202 | return 0; |
|---|
| .. | .. |
|---|
| 252 | 226 | unsigned long *mask, unsigned long *bits) |
|---|
| 253 | 227 | { |
|---|
| 254 | 228 | struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); |
|---|
| 255 | | - unsigned int i; |
|---|
| 256 | | - const unsigned int gpio_reg_size = 8; |
|---|
| 257 | | - unsigned int port; |
|---|
| 258 | | - unsigned int out_port; |
|---|
| 259 | | - unsigned int bitmask; |
|---|
| 229 | + unsigned long offset; |
|---|
| 230 | + unsigned long gpio_mask; |
|---|
| 231 | + size_t index; |
|---|
| 232 | + unsigned int port_addr; |
|---|
| 233 | + unsigned long bitmask; |
|---|
| 260 | 234 | unsigned long flags; |
|---|
| 261 | 235 | |
|---|
| 262 | | - /* set bits are evaluated a gpio register size at a time */ |
|---|
| 263 | | - for (i = 0; i < chip->ngpio; i += gpio_reg_size) { |
|---|
| 264 | | - /* no more set bits in this mask word; skip to the next word */ |
|---|
| 265 | | - if (!mask[BIT_WORD(i)]) { |
|---|
| 266 | | - i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size; |
|---|
| 267 | | - continue; |
|---|
| 268 | | - } |
|---|
| 236 | + for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { |
|---|
| 237 | + index = offset / 8; |
|---|
| 238 | + port_addr = dio48egpio->base + ports[index]; |
|---|
| 269 | 239 | |
|---|
| 270 | | - port = i / gpio_reg_size; |
|---|
| 271 | | - out_port = (port > 2) ? port + 1 : port; |
|---|
| 272 | | - bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)]; |
|---|
| 240 | + bitmask = bitmap_get_value8(bits, offset) & gpio_mask; |
|---|
| 273 | 241 | |
|---|
| 274 | 242 | raw_spin_lock_irqsave(&dio48egpio->lock, flags); |
|---|
| 275 | 243 | |
|---|
| 276 | 244 | /* update output state data and set device gpio register */ |
|---|
| 277 | | - dio48egpio->out_state[port] &= ~mask[BIT_WORD(i)]; |
|---|
| 278 | | - dio48egpio->out_state[port] |= bitmask; |
|---|
| 279 | | - outb(dio48egpio->out_state[port], dio48egpio->base + out_port); |
|---|
| 245 | + dio48egpio->out_state[index] &= ~gpio_mask; |
|---|
| 246 | + dio48egpio->out_state[index] |= bitmask; |
|---|
| 247 | + outb(dio48egpio->out_state[index], port_addr); |
|---|
| 280 | 248 | |
|---|
| 281 | 249 | raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); |
|---|
| 282 | | - |
|---|
| 283 | | - /* prepare for next gpio register set */ |
|---|
| 284 | | - mask[BIT_WORD(i)] >>= gpio_reg_size; |
|---|
| 285 | | - bits[BIT_WORD(i)] >>= gpio_reg_size; |
|---|
| 286 | 250 | } |
|---|
| 287 | 251 | } |
|---|
| 288 | 252 | |
|---|
| .. | .. |
|---|
| 404 | 368 | "PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7" |
|---|
| 405 | 369 | }; |
|---|
| 406 | 370 | |
|---|
| 371 | +static int dio48e_irq_init_hw(struct gpio_chip *gc) |
|---|
| 372 | +{ |
|---|
| 373 | + struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc); |
|---|
| 374 | + |
|---|
| 375 | + /* Disable IRQ by default */ |
|---|
| 376 | + inb(dio48egpio->base + 0xB); |
|---|
| 377 | + |
|---|
| 378 | + return 0; |
|---|
| 379 | +} |
|---|
| 380 | + |
|---|
| 407 | 381 | static int dio48e_probe(struct device *dev, unsigned int id) |
|---|
| 408 | 382 | { |
|---|
| 409 | 383 | struct dio48e_gpio *dio48egpio; |
|---|
| 410 | 384 | const char *const name = dev_name(dev); |
|---|
| 385 | + struct gpio_irq_chip *girq; |
|---|
| 411 | 386 | int err; |
|---|
| 412 | 387 | |
|---|
| 413 | 388 | dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 435 | 410 | dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; |
|---|
| 436 | 411 | dio48egpio->base = base[id]; |
|---|
| 437 | 412 | |
|---|
| 438 | | - raw_spin_lock_init(&dio48egpio->lock); |
|---|
| 413 | + girq = &dio48egpio->chip.irq; |
|---|
| 414 | + girq->chip = &dio48e_irqchip; |
|---|
| 415 | + /* This will let us handle the parent IRQ in the driver */ |
|---|
| 416 | + girq->parent_handler = NULL; |
|---|
| 417 | + girq->num_parents = 0; |
|---|
| 418 | + girq->parents = NULL; |
|---|
| 419 | + girq->default_type = IRQ_TYPE_NONE; |
|---|
| 420 | + girq->handler = handle_edge_irq; |
|---|
| 421 | + girq->init_hw = dio48e_irq_init_hw; |
|---|
| 439 | 422 | |
|---|
| 440 | | - err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); |
|---|
| 441 | | - if (err) { |
|---|
| 442 | | - dev_err(dev, "GPIO registering failed (%d)\n", err); |
|---|
| 443 | | - return err; |
|---|
| 444 | | - } |
|---|
| 423 | + raw_spin_lock_init(&dio48egpio->lock); |
|---|
| 445 | 424 | |
|---|
| 446 | 425 | /* initialize all GPIO as output */ |
|---|
| 447 | 426 | outb(0x80, base[id] + 3); |
|---|
| .. | .. |
|---|
| 455 | 434 | outb(0x00, base[id] + 6); |
|---|
| 456 | 435 | outb(0x00, base[id] + 7); |
|---|
| 457 | 436 | |
|---|
| 458 | | - /* disable IRQ by default */ |
|---|
| 459 | | - inb(base[id] + 0xB); |
|---|
| 460 | | - |
|---|
| 461 | | - err = gpiochip_irqchip_add(&dio48egpio->chip, &dio48e_irqchip, 0, |
|---|
| 462 | | - handle_edge_irq, IRQ_TYPE_NONE); |
|---|
| 437 | + err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); |
|---|
| 463 | 438 | if (err) { |
|---|
| 464 | | - dev_err(dev, "Could not add irqchip (%d)\n", err); |
|---|
| 439 | + dev_err(dev, "GPIO registering failed (%d)\n", err); |
|---|
| 465 | 440 | return err; |
|---|
| 466 | 441 | } |
|---|
| 467 | 442 | |
|---|