1*58556204SWilliam Breathitt Gray // SPDX-License-Identifier: GPL-2.0-only 2*58556204SWilliam Breathitt Gray /* 3*58556204SWilliam Breathitt Gray * GPIO driver for the ACCES PCIe-IDIO-24 family 4*58556204SWilliam Breathitt Gray * Copyright (C) 2018 William Breathitt Gray 5*58556204SWilliam Breathitt Gray * 6*58556204SWilliam Breathitt Gray * This program is free software; you can redistribute it and/or modify 7*58556204SWilliam Breathitt Gray * it under the terms of the GNU General Public License, version 2, as 8*58556204SWilliam Breathitt Gray * published by the Free Software Foundation. 9*58556204SWilliam Breathitt Gray * 10*58556204SWilliam Breathitt Gray * This program is distributed in the hope that it will be useful, but 11*58556204SWilliam Breathitt Gray * WITHOUT ANY WARRANTY; without even the implied warranty of 12*58556204SWilliam Breathitt Gray * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13*58556204SWilliam Breathitt Gray * General Public License for more details. 14*58556204SWilliam Breathitt Gray * 15*58556204SWilliam Breathitt Gray * This driver supports the following ACCES devices: PCIe-IDIO-24, 16*58556204SWilliam Breathitt Gray * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. 17*58556204SWilliam Breathitt Gray */ 18*58556204SWilliam Breathitt Gray #include <linux/bitops.h> 19*58556204SWilliam Breathitt Gray #include <linux/device.h> 20*58556204SWilliam Breathitt Gray #include <linux/errno.h> 21*58556204SWilliam Breathitt Gray #include <linux/gpio/driver.h> 22*58556204SWilliam Breathitt Gray #include <linux/interrupt.h> 23*58556204SWilliam Breathitt Gray #include <linux/irqdesc.h> 24*58556204SWilliam Breathitt Gray #include <linux/kernel.h> 25*58556204SWilliam Breathitt Gray #include <linux/module.h> 26*58556204SWilliam Breathitt Gray #include <linux/pci.h> 27*58556204SWilliam Breathitt Gray #include <linux/spinlock.h> 28*58556204SWilliam Breathitt Gray #include <linux/types.h> 29*58556204SWilliam Breathitt Gray 30*58556204SWilliam Breathitt Gray /** 31*58556204SWilliam Breathitt Gray * struct idio_24_gpio_reg - GPIO device registers structure 32*58556204SWilliam Breathitt Gray * @out0_7: Read: FET Outputs 0-7 33*58556204SWilliam Breathitt Gray * Write: FET Outputs 0-7 34*58556204SWilliam Breathitt Gray * @out8_15: Read: FET Outputs 8-15 35*58556204SWilliam Breathitt Gray * Write: FET Outputs 8-15 36*58556204SWilliam Breathitt Gray * @out16_23: Read: FET Outputs 16-23 37*58556204SWilliam Breathitt Gray * Write: FET Outputs 16-23 38*58556204SWilliam Breathitt Gray * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7 39*58556204SWilliam Breathitt Gray * Write: TTL/CMOS Outputs 0-7 40*58556204SWilliam Breathitt Gray * @in0_7: Read: Isolated Inputs 0-7 41*58556204SWilliam Breathitt Gray * Write: Reserved 42*58556204SWilliam Breathitt Gray * @in8_15: Read: Isolated Inputs 8-15 43*58556204SWilliam Breathitt Gray * Write: Reserved 44*58556204SWilliam Breathitt Gray * @in16_23: Read: Isolated Inputs 16-23 45*58556204SWilliam Breathitt Gray * Write: Reserved 46*58556204SWilliam Breathitt Gray * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7 47*58556204SWilliam Breathitt Gray * Write: Reserved 48*58556204SWilliam Breathitt Gray * @cos0_7: Read: COS Status Inputs 0-7 49*58556204SWilliam Breathitt Gray * Write: COS Clear Inputs 0-7 50*58556204SWilliam Breathitt Gray * @cos8_15: Read: COS Status Inputs 8-15 51*58556204SWilliam Breathitt Gray * Write: COS Clear Inputs 8-15 52*58556204SWilliam Breathitt Gray * @cos16_23: Read: COS Status Inputs 16-23 53*58556204SWilliam Breathitt Gray * Write: COS Clear Inputs 16-23 54*58556204SWilliam Breathitt Gray * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7 55*58556204SWilliam Breathitt Gray * Write: COS Clear TTL/CMOS 0-7 56*58556204SWilliam Breathitt Gray * @ctl: Read: Control Register 57*58556204SWilliam Breathitt Gray * Write: Control Register 58*58556204SWilliam Breathitt Gray * @reserved: Read: Reserved 59*58556204SWilliam Breathitt Gray * Write: Reserved 60*58556204SWilliam Breathitt Gray * @cos_enable: Read: COS Enable 61*58556204SWilliam Breathitt Gray * Write: COS Enable 62*58556204SWilliam Breathitt Gray * @soft_reset: Read: IRQ Output Pin Status 63*58556204SWilliam Breathitt Gray * Write: Software Board Reset 64*58556204SWilliam Breathitt Gray */ 65*58556204SWilliam Breathitt Gray struct idio_24_gpio_reg { 66*58556204SWilliam Breathitt Gray u8 out0_7; 67*58556204SWilliam Breathitt Gray u8 out8_15; 68*58556204SWilliam Breathitt Gray u8 out16_23; 69*58556204SWilliam Breathitt Gray u8 ttl_out0_7; 70*58556204SWilliam Breathitt Gray u8 in0_7; 71*58556204SWilliam Breathitt Gray u8 in8_15; 72*58556204SWilliam Breathitt Gray u8 in16_23; 73*58556204SWilliam Breathitt Gray u8 ttl_in0_7; 74*58556204SWilliam Breathitt Gray u8 cos0_7; 75*58556204SWilliam Breathitt Gray u8 cos8_15; 76*58556204SWilliam Breathitt Gray u8 cos16_23; 77*58556204SWilliam Breathitt Gray u8 cos_ttl0_7; 78*58556204SWilliam Breathitt Gray u8 ctl; 79*58556204SWilliam Breathitt Gray u8 reserved; 80*58556204SWilliam Breathitt Gray u8 cos_enable; 81*58556204SWilliam Breathitt Gray u8 soft_reset; 82*58556204SWilliam Breathitt Gray }; 83*58556204SWilliam Breathitt Gray 84*58556204SWilliam Breathitt Gray /** 85*58556204SWilliam Breathitt Gray * struct idio_24_gpio - GPIO device private data structure 86*58556204SWilliam Breathitt Gray * @chip: instance of the gpio_chip 87*58556204SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 88*58556204SWilliam Breathitt Gray * @reg: I/O address offset for the GPIO device registers 89*58556204SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 90*58556204SWilliam Breathitt Gray */ 91*58556204SWilliam Breathitt Gray struct idio_24_gpio { 92*58556204SWilliam Breathitt Gray struct gpio_chip chip; 93*58556204SWilliam Breathitt Gray raw_spinlock_t lock; 94*58556204SWilliam Breathitt Gray struct idio_24_gpio_reg __iomem *reg; 95*58556204SWilliam Breathitt Gray unsigned long irq_mask; 96*58556204SWilliam Breathitt Gray }; 97*58556204SWilliam Breathitt Gray 98*58556204SWilliam Breathitt Gray static int idio_24_gpio_get_direction(struct gpio_chip *chip, 99*58556204SWilliam Breathitt Gray unsigned int offset) 100*58556204SWilliam Breathitt Gray { 101*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 102*58556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 103*58556204SWilliam Breathitt Gray 104*58556204SWilliam Breathitt Gray /* FET Outputs */ 105*58556204SWilliam Breathitt Gray if (offset < 24) 106*58556204SWilliam Breathitt Gray return 0; 107*58556204SWilliam Breathitt Gray 108*58556204SWilliam Breathitt Gray /* Isolated Inputs */ 109*58556204SWilliam Breathitt Gray if (offset < 48) 110*58556204SWilliam Breathitt Gray return 1; 111*58556204SWilliam Breathitt Gray 112*58556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 113*58556204SWilliam Breathitt Gray /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ 114*58556204SWilliam Breathitt Gray return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask); 115*58556204SWilliam Breathitt Gray } 116*58556204SWilliam Breathitt Gray 117*58556204SWilliam Breathitt Gray static int idio_24_gpio_direction_input(struct gpio_chip *chip, 118*58556204SWilliam Breathitt Gray unsigned int offset) 119*58556204SWilliam Breathitt Gray { 120*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 121*58556204SWilliam Breathitt Gray unsigned long flags; 122*58556204SWilliam Breathitt Gray unsigned int ctl_state; 123*58556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 124*58556204SWilliam Breathitt Gray 125*58556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 126*58556204SWilliam Breathitt Gray if (offset > 47) { 127*58556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 128*58556204SWilliam Breathitt Gray 129*58556204SWilliam Breathitt Gray /* Clear TTL/CMOS Output Mode */ 130*58556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask; 131*58556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 132*58556204SWilliam Breathitt Gray 133*58556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 134*58556204SWilliam Breathitt Gray } 135*58556204SWilliam Breathitt Gray 136*58556204SWilliam Breathitt Gray return 0; 137*58556204SWilliam Breathitt Gray } 138*58556204SWilliam Breathitt Gray 139*58556204SWilliam Breathitt Gray static int idio_24_gpio_direction_output(struct gpio_chip *chip, 140*58556204SWilliam Breathitt Gray unsigned int offset, int value) 141*58556204SWilliam Breathitt Gray { 142*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 143*58556204SWilliam Breathitt Gray unsigned long flags; 144*58556204SWilliam Breathitt Gray unsigned int ctl_state; 145*58556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 146*58556204SWilliam Breathitt Gray 147*58556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 148*58556204SWilliam Breathitt Gray if (offset > 47) { 149*58556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 150*58556204SWilliam Breathitt Gray 151*58556204SWilliam Breathitt Gray /* Set TTL/CMOS Output Mode */ 152*58556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask; 153*58556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 154*58556204SWilliam Breathitt Gray 155*58556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 156*58556204SWilliam Breathitt Gray } 157*58556204SWilliam Breathitt Gray 158*58556204SWilliam Breathitt Gray chip->set(chip, offset, value); 159*58556204SWilliam Breathitt Gray return 0; 160*58556204SWilliam Breathitt Gray } 161*58556204SWilliam Breathitt Gray 162*58556204SWilliam Breathitt Gray static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) 163*58556204SWilliam Breathitt Gray { 164*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 165*58556204SWilliam Breathitt Gray const unsigned long offset_mask = BIT(offset % 8); 166*58556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 167*58556204SWilliam Breathitt Gray 168*58556204SWilliam Breathitt Gray /* FET Outputs */ 169*58556204SWilliam Breathitt Gray if (offset < 8) 170*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask); 171*58556204SWilliam Breathitt Gray 172*58556204SWilliam Breathitt Gray if (offset < 16) 173*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask); 174*58556204SWilliam Breathitt Gray 175*58556204SWilliam Breathitt Gray if (offset < 24) 176*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask); 177*58556204SWilliam Breathitt Gray 178*58556204SWilliam Breathitt Gray /* Isolated Inputs */ 179*58556204SWilliam Breathitt Gray if (offset < 32) 180*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask); 181*58556204SWilliam Breathitt Gray 182*58556204SWilliam Breathitt Gray if (offset < 40) 183*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask); 184*58556204SWilliam Breathitt Gray 185*58556204SWilliam Breathitt Gray if (offset < 48) 186*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask); 187*58556204SWilliam Breathitt Gray 188*58556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 189*58556204SWilliam Breathitt Gray if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 190*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask); 191*58556204SWilliam Breathitt Gray 192*58556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 193*58556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); 194*58556204SWilliam Breathitt Gray } 195*58556204SWilliam Breathitt Gray 196*58556204SWilliam Breathitt Gray static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, 197*58556204SWilliam Breathitt Gray int value) 198*58556204SWilliam Breathitt Gray { 199*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 200*58556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 201*58556204SWilliam Breathitt Gray void __iomem *base; 202*58556204SWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 203*58556204SWilliam Breathitt Gray unsigned long flags; 204*58556204SWilliam Breathitt Gray unsigned int out_state; 205*58556204SWilliam Breathitt Gray 206*58556204SWilliam Breathitt Gray /* Isolated Inputs */ 207*58556204SWilliam Breathitt Gray if (offset > 23 && offset < 48) 208*58556204SWilliam Breathitt Gray return; 209*58556204SWilliam Breathitt Gray 210*58556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 211*58556204SWilliam Breathitt Gray if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) 212*58556204SWilliam Breathitt Gray return; 213*58556204SWilliam Breathitt Gray 214*58556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 215*58556204SWilliam Breathitt Gray if (offset > 47) 216*58556204SWilliam Breathitt Gray base = &idio24gpio->reg->ttl_out0_7; 217*58556204SWilliam Breathitt Gray /* FET Outputs */ 218*58556204SWilliam Breathitt Gray else if (offset > 15) 219*58556204SWilliam Breathitt Gray base = &idio24gpio->reg->out16_23; 220*58556204SWilliam Breathitt Gray else if (offset > 7) 221*58556204SWilliam Breathitt Gray base = &idio24gpio->reg->out8_15; 222*58556204SWilliam Breathitt Gray else 223*58556204SWilliam Breathitt Gray base = &idio24gpio->reg->out0_7; 224*58556204SWilliam Breathitt Gray 225*58556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 226*58556204SWilliam Breathitt Gray 227*58556204SWilliam Breathitt Gray if (value) 228*58556204SWilliam Breathitt Gray out_state = ioread8(base) | mask; 229*58556204SWilliam Breathitt Gray else 230*58556204SWilliam Breathitt Gray out_state = ioread8(base) & ~mask; 231*58556204SWilliam Breathitt Gray 232*58556204SWilliam Breathitt Gray iowrite8(out_state, base); 233*58556204SWilliam Breathitt Gray 234*58556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 235*58556204SWilliam Breathitt Gray } 236*58556204SWilliam Breathitt Gray 237*58556204SWilliam Breathitt Gray static void idio_24_irq_ack(struct irq_data *data) 238*58556204SWilliam Breathitt Gray { 239*58556204SWilliam Breathitt Gray } 240*58556204SWilliam Breathitt Gray 241*58556204SWilliam Breathitt Gray static void idio_24_irq_mask(struct irq_data *data) 242*58556204SWilliam Breathitt Gray { 243*58556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 244*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 245*58556204SWilliam Breathitt Gray unsigned long flags; 246*58556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 247*58556204SWilliam Breathitt Gray unsigned char new_irq_mask; 248*58556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 249*58556204SWilliam Breathitt Gray unsigned char cos_enable_state; 250*58556204SWilliam Breathitt Gray 251*58556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 252*58556204SWilliam Breathitt Gray 253*58556204SWilliam Breathitt Gray idio24gpio->irq_mask &= BIT(bit_offset); 254*58556204SWilliam Breathitt Gray new_irq_mask = idio24gpio->irq_mask >> bank_offset; 255*58556204SWilliam Breathitt Gray 256*58556204SWilliam Breathitt Gray if (!new_irq_mask) { 257*58556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 258*58556204SWilliam Breathitt Gray 259*58556204SWilliam Breathitt Gray /* Disable Rising Edge detection */ 260*58556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset); 261*58556204SWilliam Breathitt Gray /* Disable Falling Edge detection */ 262*58556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset + 4); 263*58556204SWilliam Breathitt Gray 264*58556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 265*58556204SWilliam Breathitt Gray } 266*58556204SWilliam Breathitt Gray 267*58556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 268*58556204SWilliam Breathitt Gray } 269*58556204SWilliam Breathitt Gray 270*58556204SWilliam Breathitt Gray static void idio_24_irq_unmask(struct irq_data *data) 271*58556204SWilliam Breathitt Gray { 272*58556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 273*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 274*58556204SWilliam Breathitt Gray unsigned long flags; 275*58556204SWilliam Breathitt Gray unsigned char prev_irq_mask; 276*58556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 277*58556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 278*58556204SWilliam Breathitt Gray unsigned char cos_enable_state; 279*58556204SWilliam Breathitt Gray 280*58556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 281*58556204SWilliam Breathitt Gray 282*58556204SWilliam Breathitt Gray prev_irq_mask = idio24gpio->irq_mask >> bank_offset; 283*58556204SWilliam Breathitt Gray idio24gpio->irq_mask |= BIT(bit_offset); 284*58556204SWilliam Breathitt Gray 285*58556204SWilliam Breathitt Gray if (!prev_irq_mask) { 286*58556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 287*58556204SWilliam Breathitt Gray 288*58556204SWilliam Breathitt Gray /* Enable Rising Edge detection */ 289*58556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset); 290*58556204SWilliam Breathitt Gray /* Enable Falling Edge detection */ 291*58556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset + 4); 292*58556204SWilliam Breathitt Gray 293*58556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 294*58556204SWilliam Breathitt Gray } 295*58556204SWilliam Breathitt Gray 296*58556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 297*58556204SWilliam Breathitt Gray } 298*58556204SWilliam Breathitt Gray 299*58556204SWilliam Breathitt Gray static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) 300*58556204SWilliam Breathitt Gray { 301*58556204SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 302*58556204SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 303*58556204SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 304*58556204SWilliam Breathitt Gray return -EINVAL; 305*58556204SWilliam Breathitt Gray 306*58556204SWilliam Breathitt Gray return 0; 307*58556204SWilliam Breathitt Gray } 308*58556204SWilliam Breathitt Gray 309*58556204SWilliam Breathitt Gray static struct irq_chip idio_24_irqchip = { 310*58556204SWilliam Breathitt Gray .name = "pcie-idio-24", 311*58556204SWilliam Breathitt Gray .irq_ack = idio_24_irq_ack, 312*58556204SWilliam Breathitt Gray .irq_mask = idio_24_irq_mask, 313*58556204SWilliam Breathitt Gray .irq_unmask = idio_24_irq_unmask, 314*58556204SWilliam Breathitt Gray .irq_set_type = idio_24_irq_set_type 315*58556204SWilliam Breathitt Gray }; 316*58556204SWilliam Breathitt Gray 317*58556204SWilliam Breathitt Gray static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) 318*58556204SWilliam Breathitt Gray { 319*58556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = dev_id; 320*58556204SWilliam Breathitt Gray unsigned long irq_status; 321*58556204SWilliam Breathitt Gray struct gpio_chip *const chip = &idio24gpio->chip; 322*58556204SWilliam Breathitt Gray unsigned long irq_mask; 323*58556204SWilliam Breathitt Gray int gpio; 324*58556204SWilliam Breathitt Gray 325*58556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 326*58556204SWilliam Breathitt Gray 327*58556204SWilliam Breathitt Gray /* Read Change-Of-State status */ 328*58556204SWilliam Breathitt Gray irq_status = ioread32(&idio24gpio->reg->cos0_7); 329*58556204SWilliam Breathitt Gray 330*58556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 331*58556204SWilliam Breathitt Gray 332*58556204SWilliam Breathitt Gray /* Make sure our device generated IRQ */ 333*58556204SWilliam Breathitt Gray if (!irq_status) 334*58556204SWilliam Breathitt Gray return IRQ_NONE; 335*58556204SWilliam Breathitt Gray 336*58556204SWilliam Breathitt Gray /* Handle only unmasked IRQ */ 337*58556204SWilliam Breathitt Gray irq_mask = idio24gpio->irq_mask & irq_status; 338*58556204SWilliam Breathitt Gray 339*58556204SWilliam Breathitt Gray for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24) 340*58556204SWilliam Breathitt Gray generic_handle_irq(irq_find_mapping(chip->irq.domain, 341*58556204SWilliam Breathitt Gray gpio + 24)); 342*58556204SWilliam Breathitt Gray 343*58556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 344*58556204SWilliam Breathitt Gray 345*58556204SWilliam Breathitt Gray /* Clear Change-Of-State status */ 346*58556204SWilliam Breathitt Gray iowrite32(irq_status, &idio24gpio->reg->cos0_7); 347*58556204SWilliam Breathitt Gray 348*58556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 349*58556204SWilliam Breathitt Gray 350*58556204SWilliam Breathitt Gray return IRQ_HANDLED; 351*58556204SWilliam Breathitt Gray } 352*58556204SWilliam Breathitt Gray 353*58556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56 354*58556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = { 355*58556204SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 356*58556204SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 357*58556204SWilliam Breathitt Gray "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", 358*58556204SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 359*58556204SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", 360*58556204SWilliam Breathitt Gray "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", 361*58556204SWilliam Breathitt Gray "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" 362*58556204SWilliam Breathitt Gray }; 363*58556204SWilliam Breathitt Gray 364*58556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) 365*58556204SWilliam Breathitt Gray { 366*58556204SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 367*58556204SWilliam Breathitt Gray struct idio_24_gpio *idio24gpio; 368*58556204SWilliam Breathitt Gray int err; 369*58556204SWilliam Breathitt Gray const size_t pci_bar_index = 2; 370*58556204SWilliam Breathitt Gray const char *const name = pci_name(pdev); 371*58556204SWilliam Breathitt Gray 372*58556204SWilliam Breathitt Gray idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); 373*58556204SWilliam Breathitt Gray if (!idio24gpio) 374*58556204SWilliam Breathitt Gray return -ENOMEM; 375*58556204SWilliam Breathitt Gray 376*58556204SWilliam Breathitt Gray err = pcim_enable_device(pdev); 377*58556204SWilliam Breathitt Gray if (err) { 378*58556204SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 379*58556204SWilliam Breathitt Gray return err; 380*58556204SWilliam Breathitt Gray } 381*58556204SWilliam Breathitt Gray 382*58556204SWilliam Breathitt Gray err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); 383*58556204SWilliam Breathitt Gray if (err) { 384*58556204SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 385*58556204SWilliam Breathitt Gray return err; 386*58556204SWilliam Breathitt Gray } 387*58556204SWilliam Breathitt Gray 388*58556204SWilliam Breathitt Gray idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; 389*58556204SWilliam Breathitt Gray 390*58556204SWilliam Breathitt Gray idio24gpio->chip.label = name; 391*58556204SWilliam Breathitt Gray idio24gpio->chip.parent = dev; 392*58556204SWilliam Breathitt Gray idio24gpio->chip.owner = THIS_MODULE; 393*58556204SWilliam Breathitt Gray idio24gpio->chip.base = -1; 394*58556204SWilliam Breathitt Gray idio24gpio->chip.ngpio = IDIO_24_NGPIO; 395*58556204SWilliam Breathitt Gray idio24gpio->chip.names = idio_24_names; 396*58556204SWilliam Breathitt Gray idio24gpio->chip.get_direction = idio_24_gpio_get_direction; 397*58556204SWilliam Breathitt Gray idio24gpio->chip.direction_input = idio_24_gpio_direction_input; 398*58556204SWilliam Breathitt Gray idio24gpio->chip.direction_output = idio_24_gpio_direction_output; 399*58556204SWilliam Breathitt Gray idio24gpio->chip.get = idio_24_gpio_get; 400*58556204SWilliam Breathitt Gray idio24gpio->chip.set = idio_24_gpio_set; 401*58556204SWilliam Breathitt Gray 402*58556204SWilliam Breathitt Gray raw_spin_lock_init(&idio24gpio->lock); 403*58556204SWilliam Breathitt Gray 404*58556204SWilliam Breathitt Gray /* Software board reset */ 405*58556204SWilliam Breathitt Gray iowrite8(0, &idio24gpio->reg->soft_reset); 406*58556204SWilliam Breathitt Gray 407*58556204SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio); 408*58556204SWilliam Breathitt Gray if (err) { 409*58556204SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 410*58556204SWilliam Breathitt Gray return err; 411*58556204SWilliam Breathitt Gray } 412*58556204SWilliam Breathitt Gray 413*58556204SWilliam Breathitt Gray err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0, 414*58556204SWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 415*58556204SWilliam Breathitt Gray if (err) { 416*58556204SWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 417*58556204SWilliam Breathitt Gray return err; 418*58556204SWilliam Breathitt Gray } 419*58556204SWilliam Breathitt Gray 420*58556204SWilliam Breathitt Gray err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED, 421*58556204SWilliam Breathitt Gray name, idio24gpio); 422*58556204SWilliam Breathitt Gray if (err) { 423*58556204SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 424*58556204SWilliam Breathitt Gray return err; 425*58556204SWilliam Breathitt Gray } 426*58556204SWilliam Breathitt Gray 427*58556204SWilliam Breathitt Gray return 0; 428*58556204SWilliam Breathitt Gray } 429*58556204SWilliam Breathitt Gray 430*58556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = { 431*58556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, 432*58556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, 433*58556204SWilliam Breathitt Gray { 0 } 434*58556204SWilliam Breathitt Gray }; 435*58556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); 436*58556204SWilliam Breathitt Gray 437*58556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = { 438*58556204SWilliam Breathitt Gray .name = "pcie-idio-24", 439*58556204SWilliam Breathitt Gray .id_table = idio_24_pci_dev_id, 440*58556204SWilliam Breathitt Gray .probe = idio_24_probe 441*58556204SWilliam Breathitt Gray }; 442*58556204SWilliam Breathitt Gray 443*58556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver); 444*58556204SWilliam Breathitt Gray 445*58556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 446*58556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); 447*58556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 448