^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * GPIO driver for the ACCES 104-IDI-48 family
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2015 William Breathitt Gray
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This driver supports the following ACCES devices: 104-IDI-48A,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/bitmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/gpio/driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/irqdesc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/isa.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define IDI_48_EXTENT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static unsigned int base[MAX_NUM_IDI_48];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static unsigned int num_idi_48;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) module_param_hw_array(base, uint, ioport, &num_idi_48, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static unsigned int irq[MAX_NUM_IDI_48];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) module_param_hw_array(irq, uint, irq, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * struct idi_48_gpio - GPIO device private data structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * @chip: instance of the gpio_chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * @lock: synchronization lock to prevent I/O race conditions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * @ack_lock: synchronization lock to prevent IRQ handler race conditions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * @irq_mask: input bits affected by interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * @base: base port address of the GPIO device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * @cos_enb: Change-Of-State IRQ enable boundaries mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct idi_48_gpio {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct gpio_chip chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) raw_spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) spinlock_t ack_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) unsigned char irq_mask[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned char cos_enb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return GPIO_LINE_DIRECTION_IN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) unsigned base_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) unsigned mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) for (i = 0; i < 48; i += 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (offset < i + 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) base_offset = register_offset[i / 8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) mask = BIT(offset - i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return !!(inb(idi48gpio->base + base_offset) & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* The following line should never execute since offset < 48 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned long *bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long gpio_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned int port_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned long port_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* clear bits array to a clean slate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) bitmap_zero(bits, chip->ngpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) port_addr = idi48gpio->base + ports[offset / 8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) port_state = inb(port_addr) & gpio_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) bitmap_set_value8(bits, port_state, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static void idi_48_irq_ack(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static void idi_48_irq_mask(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) const unsigned offset = irqd_to_hwirq(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) unsigned boundary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) for (i = 0; i < 48; i += 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (offset < i + 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) mask = BIT(offset - i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) boundary = i / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) idi48gpio->irq_mask[boundary] &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (!idi48gpio->irq_mask[boundary]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) idi48gpio->cos_enb &= ~BIT(boundary);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) raw_spin_lock_irqsave(&idi48gpio->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) outb(idi48gpio->cos_enb, idi48gpio->base + 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) raw_spin_unlock_irqrestore(&idi48gpio->lock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static void idi_48_irq_unmask(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) const unsigned offset = irqd_to_hwirq(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) unsigned mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) unsigned boundary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) unsigned prev_irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) for (i = 0; i < 48; i += 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (offset < i + 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) mask = BIT(offset - i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) boundary = i / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) prev_irq_mask = idi48gpio->irq_mask[boundary];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) idi48gpio->irq_mask[boundary] |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (!prev_irq_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) idi48gpio->cos_enb |= BIT(boundary);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) raw_spin_lock_irqsave(&idi48gpio->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) outb(idi48gpio->cos_enb, idi48gpio->base + 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) raw_spin_unlock_irqrestore(&idi48gpio->lock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* The only valid irq types are none and both-edges */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (flow_type != IRQ_TYPE_NONE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static struct irq_chip idi_48_irqchip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .name = "104-idi-48",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .irq_ack = idi_48_irq_ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .irq_mask = idi_48_irq_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .irq_unmask = idi_48_irq_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .irq_set_type = idi_48_irq_set_type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct idi_48_gpio *const idi48gpio = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) unsigned long cos_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) unsigned long boundary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) unsigned long irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) unsigned long bit_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) unsigned long gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct gpio_chip *const chip = &idi48gpio->chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) spin_lock(&idi48gpio->ack_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) raw_spin_lock(&idi48gpio->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) cos_status = inb(idi48gpio->base + 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) raw_spin_unlock(&idi48gpio->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (cos_status & BIT(6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) spin_unlock(&idi48gpio->ack_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) cos_status &= 0x3F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) for_each_set_bit(boundary, &cos_status, 6) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) irq_mask = idi48gpio->irq_mask[boundary];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) for_each_set_bit(bit_num, &irq_mask, 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) gpio = bit_num + boundary * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) generic_handle_irq(irq_find_mapping(chip->irq.domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) gpio));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) spin_unlock(&idi48gpio->ack_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) #define IDI48_NGPIO 48
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static const char *idi48_names[IDI48_NGPIO] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) "Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A", "Bit 16 A", "Bit 17 A",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) "Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) "Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) "Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) "Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B", "Bit 16 B", "Bit 17 B",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static int idi_48_irq_init_hw(struct gpio_chip *gc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* Disable IRQ by default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) outb(0, idi48gpio->base + 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) inb(idi48gpio->base + 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static int idi_48_probe(struct device *dev, unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct idi_48_gpio *idi48gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) const char *const name = dev_name(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct gpio_irq_chip *girq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (!idi48gpio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) base[id], base[id] + IDI_48_EXTENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) idi48gpio->chip.label = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) idi48gpio->chip.parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) idi48gpio->chip.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) idi48gpio->chip.base = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) idi48gpio->chip.ngpio = IDI48_NGPIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) idi48gpio->chip.names = idi48_names;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) idi48gpio->chip.get = idi_48_gpio_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) idi48gpio->base = base[id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) girq = &idi48gpio->chip.irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) girq->chip = &idi_48_irqchip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* This will let us handle the parent IRQ in the driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) girq->parent_handler = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) girq->num_parents = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) girq->parents = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) girq->default_type = IRQ_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) girq->handler = handle_edge_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) girq->init_hw = idi_48_irq_init_hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) raw_spin_lock_init(&idi48gpio->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) spin_lock_init(&idi48gpio->ack_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) dev_err(dev, "GPIO registering failed (%d)\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) name, idi48gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) dev_err(dev, "IRQ handler registering failed (%d)\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static struct isa_driver idi_48_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .probe = idi_48_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .name = "104-idi-48"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) module_isa_driver(idi_48_driver, num_idi_48);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) MODULE_LICENSE("GPL v2");