.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * GPIO driver for the ACCES PCI-IDIO-16 |
---|
3 | 4 | * Copyright (C) 2017 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 | #include <linux/bitmap.h> |
---|
15 | 7 | #include <linux/bitops.h> |
---|
.. | .. |
---|
69 | 61 | unsigned int offset) |
---|
70 | 62 | { |
---|
71 | 63 | if (offset > 15) |
---|
72 | | - return 1; |
---|
| 64 | + return GPIO_LINE_DIRECTION_IN; |
---|
73 | 65 | |
---|
74 | | - return 0; |
---|
| 66 | + return GPIO_LINE_DIRECTION_OUT; |
---|
75 | 67 | } |
---|
76 | 68 | |
---|
77 | 69 | static int idio_16_gpio_direction_input(struct gpio_chip *chip, |
---|
.. | .. |
---|
108 | 100 | unsigned long *mask, unsigned long *bits) |
---|
109 | 101 | { |
---|
110 | 102 | struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); |
---|
111 | | - size_t i; |
---|
112 | | - const unsigned int gpio_reg_size = 8; |
---|
113 | | - unsigned int bits_offset; |
---|
114 | | - size_t word_index; |
---|
115 | | - unsigned int word_offset; |
---|
116 | | - unsigned long word_mask; |
---|
117 | | - const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); |
---|
118 | | - unsigned long port_state; |
---|
| 103 | + unsigned long offset; |
---|
| 104 | + unsigned long gpio_mask; |
---|
119 | 105 | void __iomem *ports[] = { |
---|
120 | 106 | &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15, |
---|
121 | 107 | &idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15, |
---|
122 | 108 | }; |
---|
| 109 | + void __iomem *port_addr; |
---|
| 110 | + unsigned long port_state; |
---|
123 | 111 | |
---|
124 | 112 | /* clear bits array to a clean slate */ |
---|
125 | 113 | bitmap_zero(bits, chip->ngpio); |
---|
126 | 114 | |
---|
127 | | - /* get bits are evaluated a gpio port register at a time */ |
---|
128 | | - for (i = 0; i < ARRAY_SIZE(ports); i++) { |
---|
129 | | - /* gpio offset in bits array */ |
---|
130 | | - bits_offset = i * gpio_reg_size; |
---|
| 115 | + for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { |
---|
| 116 | + port_addr = ports[offset / 8]; |
---|
| 117 | + port_state = ioread8(port_addr) & gpio_mask; |
---|
131 | 118 | |
---|
132 | | - /* word index for bits array */ |
---|
133 | | - word_index = BIT_WORD(bits_offset); |
---|
134 | | - |
---|
135 | | - /* gpio offset within current word of bits array */ |
---|
136 | | - word_offset = bits_offset % BITS_PER_LONG; |
---|
137 | | - |
---|
138 | | - /* mask of get bits for current gpio within current word */ |
---|
139 | | - word_mask = mask[word_index] & (port_mask << word_offset); |
---|
140 | | - if (!word_mask) { |
---|
141 | | - /* no get bits in this port so skip to next one */ |
---|
142 | | - continue; |
---|
143 | | - } |
---|
144 | | - |
---|
145 | | - /* read bits from current gpio port */ |
---|
146 | | - port_state = ioread8(ports[i]); |
---|
147 | | - |
---|
148 | | - /* store acquired bits at respective bits array offset */ |
---|
149 | | - bits[word_index] |= port_state << word_offset; |
---|
| 119 | + bitmap_set_value8(bits, port_state, offset); |
---|
150 | 120 | } |
---|
151 | 121 | |
---|
152 | 122 | return 0; |
---|
.. | .. |
---|
186 | 156 | unsigned long *mask, unsigned long *bits) |
---|
187 | 157 | { |
---|
188 | 158 | struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); |
---|
| 159 | + unsigned long offset; |
---|
| 160 | + unsigned long gpio_mask; |
---|
| 161 | + void __iomem *ports[] = { |
---|
| 162 | + &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15, |
---|
| 163 | + }; |
---|
| 164 | + size_t index; |
---|
| 165 | + void __iomem *port_addr; |
---|
| 166 | + unsigned long bitmask; |
---|
189 | 167 | unsigned long flags; |
---|
190 | | - unsigned int out_state; |
---|
| 168 | + unsigned long out_state; |
---|
191 | 169 | |
---|
192 | | - raw_spin_lock_irqsave(&idio16gpio->lock, flags); |
---|
| 170 | + for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { |
---|
| 171 | + index = offset / 8; |
---|
| 172 | + port_addr = ports[index]; |
---|
193 | 173 | |
---|
194 | | - /* process output lines 0-7 */ |
---|
195 | | - if (*mask & 0xFF) { |
---|
196 | | - out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask; |
---|
197 | | - out_state |= *mask & *bits; |
---|
198 | | - iowrite8(out_state, &idio16gpio->reg->out0_7); |
---|
| 174 | + bitmask = bitmap_get_value8(bits, offset) & gpio_mask; |
---|
| 175 | + |
---|
| 176 | + raw_spin_lock_irqsave(&idio16gpio->lock, flags); |
---|
| 177 | + |
---|
| 178 | + out_state = ioread8(port_addr) & ~gpio_mask; |
---|
| 179 | + out_state |= bitmask; |
---|
| 180 | + iowrite8(out_state, port_addr); |
---|
| 181 | + |
---|
| 182 | + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); |
---|
199 | 183 | } |
---|
200 | | - |
---|
201 | | - /* shift to next output line word */ |
---|
202 | | - *mask >>= 8; |
---|
203 | | - |
---|
204 | | - /* process output lines 8-15 */ |
---|
205 | | - if (*mask & 0xFF) { |
---|
206 | | - *bits >>= 8; |
---|
207 | | - out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask; |
---|
208 | | - out_state |= *mask & *bits; |
---|
209 | | - iowrite8(out_state, &idio16gpio->reg->out8_15); |
---|
210 | | - } |
---|
211 | | - |
---|
212 | | - raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); |
---|
213 | 184 | } |
---|
214 | 185 | |
---|
215 | 186 | static void idio_16_irq_ack(struct irq_data *data) |
---|
.. | .. |
---|
309 | 280 | "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" |
---|
310 | 281 | }; |
---|
311 | 282 | |
---|
| 283 | +static int idio_16_irq_init_hw(struct gpio_chip *gc) |
---|
| 284 | +{ |
---|
| 285 | + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc); |
---|
| 286 | + |
---|
| 287 | + /* Disable IRQ by default and clear any pending interrupt */ |
---|
| 288 | + iowrite8(0, &idio16gpio->reg->irq_ctl); |
---|
| 289 | + iowrite8(0, &idio16gpio->reg->in0_7); |
---|
| 290 | + |
---|
| 291 | + return 0; |
---|
| 292 | +} |
---|
| 293 | + |
---|
312 | 294 | static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
---|
313 | 295 | { |
---|
314 | 296 | struct device *const dev = &pdev->dev; |
---|
.. | .. |
---|
316 | 298 | int err; |
---|
317 | 299 | const size_t pci_bar_index = 2; |
---|
318 | 300 | const char *const name = pci_name(pdev); |
---|
| 301 | + struct gpio_irq_chip *girq; |
---|
319 | 302 | |
---|
320 | 303 | idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); |
---|
321 | 304 | if (!idio16gpio) |
---|
.. | .. |
---|
352 | 335 | idio16gpio->chip.set = idio_16_gpio_set; |
---|
353 | 336 | idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; |
---|
354 | 337 | |
---|
| 338 | + girq = &idio16gpio->chip.irq; |
---|
| 339 | + girq->chip = &idio_16_irqchip; |
---|
| 340 | + /* This will let us handle the parent IRQ in the driver */ |
---|
| 341 | + girq->parent_handler = NULL; |
---|
| 342 | + girq->num_parents = 0; |
---|
| 343 | + girq->parents = NULL; |
---|
| 344 | + girq->default_type = IRQ_TYPE_NONE; |
---|
| 345 | + girq->handler = handle_edge_irq; |
---|
| 346 | + girq->init_hw = idio_16_irq_init_hw; |
---|
| 347 | + |
---|
355 | 348 | raw_spin_lock_init(&idio16gpio->lock); |
---|
356 | 349 | |
---|
357 | 350 | err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); |
---|
358 | 351 | if (err) { |
---|
359 | 352 | dev_err(dev, "GPIO registering failed (%d)\n", err); |
---|
360 | | - return err; |
---|
361 | | - } |
---|
362 | | - |
---|
363 | | - /* Disable IRQ by default and clear any pending interrupt */ |
---|
364 | | - iowrite8(0, &idio16gpio->reg->irq_ctl); |
---|
365 | | - iowrite8(0, &idio16gpio->reg->in0_7); |
---|
366 | | - |
---|
367 | | - err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0, |
---|
368 | | - handle_edge_irq, IRQ_TYPE_NONE); |
---|
369 | | - if (err) { |
---|
370 | | - dev_err(dev, "Could not add irqchip (%d)\n", err); |
---|
371 | 353 | return err; |
---|
372 | 354 | } |
---|
373 | 355 | |
---|