158556204SWilliam Breathitt Gray // SPDX-License-Identifier: GPL-2.0-only 258556204SWilliam Breathitt Gray /* 358556204SWilliam Breathitt Gray * GPIO driver for the ACCES PCIe-IDIO-24 family 458556204SWilliam Breathitt Gray * Copyright (C) 2018 William Breathitt Gray 558556204SWilliam Breathitt Gray * 658556204SWilliam Breathitt Gray * This program is free software; you can redistribute it and/or modify 758556204SWilliam Breathitt Gray * it under the terms of the GNU General Public License, version 2, as 858556204SWilliam Breathitt Gray * published by the Free Software Foundation. 958556204SWilliam Breathitt Gray * 1058556204SWilliam Breathitt Gray * This program is distributed in the hope that it will be useful, but 1158556204SWilliam Breathitt Gray * WITHOUT ANY WARRANTY; without even the implied warranty of 1258556204SWilliam Breathitt Gray * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1358556204SWilliam Breathitt Gray * General Public License for more details. 1458556204SWilliam Breathitt Gray * 1558556204SWilliam Breathitt Gray * This driver supports the following ACCES devices: PCIe-IDIO-24, 1658556204SWilliam Breathitt Gray * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. 1758556204SWilliam Breathitt Gray */ 1858556204SWilliam Breathitt Gray #include <linux/bitops.h> 1958556204SWilliam Breathitt Gray #include <linux/device.h> 2058556204SWilliam Breathitt Gray #include <linux/errno.h> 2158556204SWilliam Breathitt Gray #include <linux/gpio/driver.h> 2258556204SWilliam Breathitt Gray #include <linux/interrupt.h> 2358556204SWilliam Breathitt Gray #include <linux/irqdesc.h> 2458556204SWilliam Breathitt Gray #include <linux/kernel.h> 2558556204SWilliam Breathitt Gray #include <linux/module.h> 2658556204SWilliam Breathitt Gray #include <linux/pci.h> 2758556204SWilliam Breathitt Gray #include <linux/spinlock.h> 2858556204SWilliam Breathitt Gray #include <linux/types.h> 2958556204SWilliam Breathitt Gray 3058556204SWilliam Breathitt Gray /** 3158556204SWilliam Breathitt Gray * struct idio_24_gpio_reg - GPIO device registers structure 3258556204SWilliam Breathitt Gray * @out0_7: Read: FET Outputs 0-7 3358556204SWilliam Breathitt Gray * Write: FET Outputs 0-7 3458556204SWilliam Breathitt Gray * @out8_15: Read: FET Outputs 8-15 3558556204SWilliam Breathitt Gray * Write: FET Outputs 8-15 3658556204SWilliam Breathitt Gray * @out16_23: Read: FET Outputs 16-23 3758556204SWilliam Breathitt Gray * Write: FET Outputs 16-23 3858556204SWilliam Breathitt Gray * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7 3958556204SWilliam Breathitt Gray * Write: TTL/CMOS Outputs 0-7 4058556204SWilliam Breathitt Gray * @in0_7: Read: Isolated Inputs 0-7 4158556204SWilliam Breathitt Gray * Write: Reserved 4258556204SWilliam Breathitt Gray * @in8_15: Read: Isolated Inputs 8-15 4358556204SWilliam Breathitt Gray * Write: Reserved 4458556204SWilliam Breathitt Gray * @in16_23: Read: Isolated Inputs 16-23 4558556204SWilliam Breathitt Gray * Write: Reserved 4658556204SWilliam Breathitt Gray * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7 4758556204SWilliam Breathitt Gray * Write: Reserved 4858556204SWilliam Breathitt Gray * @cos0_7: Read: COS Status Inputs 0-7 4958556204SWilliam Breathitt Gray * Write: COS Clear Inputs 0-7 5058556204SWilliam Breathitt Gray * @cos8_15: Read: COS Status Inputs 8-15 5158556204SWilliam Breathitt Gray * Write: COS Clear Inputs 8-15 5258556204SWilliam Breathitt Gray * @cos16_23: Read: COS Status Inputs 16-23 5358556204SWilliam Breathitt Gray * Write: COS Clear Inputs 16-23 5458556204SWilliam Breathitt Gray * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7 5558556204SWilliam Breathitt Gray * Write: COS Clear TTL/CMOS 0-7 5658556204SWilliam Breathitt Gray * @ctl: Read: Control Register 5758556204SWilliam Breathitt Gray * Write: Control Register 5858556204SWilliam Breathitt Gray * @reserved: Read: Reserved 5958556204SWilliam Breathitt Gray * Write: Reserved 6058556204SWilliam Breathitt Gray * @cos_enable: Read: COS Enable 6158556204SWilliam Breathitt Gray * Write: COS Enable 6258556204SWilliam Breathitt Gray * @soft_reset: Read: IRQ Output Pin Status 6358556204SWilliam Breathitt Gray * Write: Software Board Reset 6458556204SWilliam Breathitt Gray */ 6558556204SWilliam Breathitt Gray struct idio_24_gpio_reg { 6658556204SWilliam Breathitt Gray u8 out0_7; 6758556204SWilliam Breathitt Gray u8 out8_15; 6858556204SWilliam Breathitt Gray u8 out16_23; 6958556204SWilliam Breathitt Gray u8 ttl_out0_7; 7058556204SWilliam Breathitt Gray u8 in0_7; 7158556204SWilliam Breathitt Gray u8 in8_15; 7258556204SWilliam Breathitt Gray u8 in16_23; 7358556204SWilliam Breathitt Gray u8 ttl_in0_7; 7458556204SWilliam Breathitt Gray u8 cos0_7; 7558556204SWilliam Breathitt Gray u8 cos8_15; 7658556204SWilliam Breathitt Gray u8 cos16_23; 7758556204SWilliam Breathitt Gray u8 cos_ttl0_7; 7858556204SWilliam Breathitt Gray u8 ctl; 7958556204SWilliam Breathitt Gray u8 reserved; 8058556204SWilliam Breathitt Gray u8 cos_enable; 8158556204SWilliam Breathitt Gray u8 soft_reset; 8258556204SWilliam Breathitt Gray }; 8358556204SWilliam Breathitt Gray 8458556204SWilliam Breathitt Gray /** 8558556204SWilliam Breathitt Gray * struct idio_24_gpio - GPIO device private data structure 8658556204SWilliam Breathitt Gray * @chip: instance of the gpio_chip 8758556204SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 8858556204SWilliam Breathitt Gray * @reg: I/O address offset for the GPIO device registers 8958556204SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 9058556204SWilliam Breathitt Gray */ 9158556204SWilliam Breathitt Gray struct idio_24_gpio { 9258556204SWilliam Breathitt Gray struct gpio_chip chip; 9358556204SWilliam Breathitt Gray raw_spinlock_t lock; 9458556204SWilliam Breathitt Gray struct idio_24_gpio_reg __iomem *reg; 9558556204SWilliam Breathitt Gray unsigned long irq_mask; 9658556204SWilliam Breathitt Gray }; 9758556204SWilliam Breathitt Gray 9858556204SWilliam Breathitt Gray static int idio_24_gpio_get_direction(struct gpio_chip *chip, 9958556204SWilliam Breathitt Gray unsigned int offset) 10058556204SWilliam Breathitt Gray { 10158556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 10258556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 10358556204SWilliam Breathitt Gray 10458556204SWilliam Breathitt Gray /* FET Outputs */ 10558556204SWilliam Breathitt Gray if (offset < 24) 10658556204SWilliam Breathitt Gray return 0; 10758556204SWilliam Breathitt Gray 10858556204SWilliam Breathitt Gray /* Isolated Inputs */ 10958556204SWilliam Breathitt Gray if (offset < 48) 11058556204SWilliam Breathitt Gray return 1; 11158556204SWilliam Breathitt Gray 11258556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 11358556204SWilliam Breathitt Gray /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ 11458556204SWilliam Breathitt Gray return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask); 11558556204SWilliam Breathitt Gray } 11658556204SWilliam Breathitt Gray 11758556204SWilliam Breathitt Gray static int idio_24_gpio_direction_input(struct gpio_chip *chip, 11858556204SWilliam Breathitt Gray unsigned int offset) 11958556204SWilliam Breathitt Gray { 12058556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 12158556204SWilliam Breathitt Gray unsigned long flags; 12258556204SWilliam Breathitt Gray unsigned int ctl_state; 12358556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 12458556204SWilliam Breathitt Gray 12558556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 12658556204SWilliam Breathitt Gray if (offset > 47) { 12758556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 12858556204SWilliam Breathitt Gray 12958556204SWilliam Breathitt Gray /* Clear TTL/CMOS Output Mode */ 13058556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask; 13158556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 13258556204SWilliam Breathitt Gray 13358556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 13458556204SWilliam Breathitt Gray } 13558556204SWilliam Breathitt Gray 13658556204SWilliam Breathitt Gray return 0; 13758556204SWilliam Breathitt Gray } 13858556204SWilliam Breathitt Gray 13958556204SWilliam Breathitt Gray static int idio_24_gpio_direction_output(struct gpio_chip *chip, 14058556204SWilliam Breathitt Gray unsigned int offset, int value) 14158556204SWilliam Breathitt Gray { 14258556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 14358556204SWilliam Breathitt Gray unsigned long flags; 14458556204SWilliam Breathitt Gray unsigned int ctl_state; 14558556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 14658556204SWilliam Breathitt Gray 14758556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 14858556204SWilliam Breathitt Gray if (offset > 47) { 14958556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 15058556204SWilliam Breathitt Gray 15158556204SWilliam Breathitt Gray /* Set TTL/CMOS Output Mode */ 15258556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask; 15358556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 15458556204SWilliam Breathitt Gray 15558556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 15658556204SWilliam Breathitt Gray } 15758556204SWilliam Breathitt Gray 15858556204SWilliam Breathitt Gray chip->set(chip, offset, value); 15958556204SWilliam Breathitt Gray return 0; 16058556204SWilliam Breathitt Gray } 16158556204SWilliam Breathitt Gray 16258556204SWilliam Breathitt Gray static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) 16358556204SWilliam Breathitt Gray { 16458556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 16558556204SWilliam Breathitt Gray const unsigned long offset_mask = BIT(offset % 8); 16658556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 16758556204SWilliam Breathitt Gray 16858556204SWilliam Breathitt Gray /* FET Outputs */ 16958556204SWilliam Breathitt Gray if (offset < 8) 17058556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask); 17158556204SWilliam Breathitt Gray 17258556204SWilliam Breathitt Gray if (offset < 16) 17358556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask); 17458556204SWilliam Breathitt Gray 17558556204SWilliam Breathitt Gray if (offset < 24) 17658556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask); 17758556204SWilliam Breathitt Gray 17858556204SWilliam Breathitt Gray /* Isolated Inputs */ 17958556204SWilliam Breathitt Gray if (offset < 32) 18058556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask); 18158556204SWilliam Breathitt Gray 18258556204SWilliam Breathitt Gray if (offset < 40) 18358556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask); 18458556204SWilliam Breathitt Gray 18558556204SWilliam Breathitt Gray if (offset < 48) 18658556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask); 18758556204SWilliam Breathitt Gray 18858556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 18958556204SWilliam Breathitt Gray if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 19058556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask); 19158556204SWilliam Breathitt Gray 19258556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 19358556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); 19458556204SWilliam Breathitt Gray } 19558556204SWilliam Breathitt Gray 19658556204SWilliam Breathitt Gray static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, 19758556204SWilliam Breathitt Gray int value) 19858556204SWilliam Breathitt Gray { 19958556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 20058556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 20158556204SWilliam Breathitt Gray void __iomem *base; 20258556204SWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 20358556204SWilliam Breathitt Gray unsigned long flags; 20458556204SWilliam Breathitt Gray unsigned int out_state; 20558556204SWilliam Breathitt Gray 20658556204SWilliam Breathitt Gray /* Isolated Inputs */ 20758556204SWilliam Breathitt Gray if (offset > 23 && offset < 48) 20858556204SWilliam Breathitt Gray return; 20958556204SWilliam Breathitt Gray 21058556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 21158556204SWilliam Breathitt Gray if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) 21258556204SWilliam Breathitt Gray return; 21358556204SWilliam Breathitt Gray 21458556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 21558556204SWilliam Breathitt Gray if (offset > 47) 21658556204SWilliam Breathitt Gray base = &idio24gpio->reg->ttl_out0_7; 21758556204SWilliam Breathitt Gray /* FET Outputs */ 21858556204SWilliam Breathitt Gray else if (offset > 15) 21958556204SWilliam Breathitt Gray base = &idio24gpio->reg->out16_23; 22058556204SWilliam Breathitt Gray else if (offset > 7) 22158556204SWilliam Breathitt Gray base = &idio24gpio->reg->out8_15; 22258556204SWilliam Breathitt Gray else 22358556204SWilliam Breathitt Gray base = &idio24gpio->reg->out0_7; 22458556204SWilliam Breathitt Gray 22558556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 22658556204SWilliam Breathitt Gray 22758556204SWilliam Breathitt Gray if (value) 22858556204SWilliam Breathitt Gray out_state = ioread8(base) | mask; 22958556204SWilliam Breathitt Gray else 23058556204SWilliam Breathitt Gray out_state = ioread8(base) & ~mask; 23158556204SWilliam Breathitt Gray 23258556204SWilliam Breathitt Gray iowrite8(out_state, base); 23358556204SWilliam Breathitt Gray 23458556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 23558556204SWilliam Breathitt Gray } 23658556204SWilliam Breathitt Gray 23758556204SWilliam Breathitt Gray static void idio_24_irq_ack(struct irq_data *data) 23858556204SWilliam Breathitt Gray { 23958556204SWilliam Breathitt Gray } 24058556204SWilliam Breathitt Gray 24158556204SWilliam Breathitt Gray static void idio_24_irq_mask(struct irq_data *data) 24258556204SWilliam Breathitt Gray { 24358556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 24458556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 24558556204SWilliam Breathitt Gray unsigned long flags; 24658556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 24758556204SWilliam Breathitt Gray unsigned char new_irq_mask; 24858556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 24958556204SWilliam Breathitt Gray unsigned char cos_enable_state; 25058556204SWilliam Breathitt Gray 25158556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 25258556204SWilliam Breathitt Gray 25358556204SWilliam Breathitt Gray idio24gpio->irq_mask &= BIT(bit_offset); 25458556204SWilliam Breathitt Gray new_irq_mask = idio24gpio->irq_mask >> bank_offset; 25558556204SWilliam Breathitt Gray 25658556204SWilliam Breathitt Gray if (!new_irq_mask) { 25758556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 25858556204SWilliam Breathitt Gray 25958556204SWilliam Breathitt Gray /* Disable Rising Edge detection */ 26058556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset); 26158556204SWilliam Breathitt Gray /* Disable Falling Edge detection */ 26258556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset + 4); 26358556204SWilliam Breathitt Gray 26458556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 26558556204SWilliam Breathitt Gray } 26658556204SWilliam Breathitt Gray 26758556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 26858556204SWilliam Breathitt Gray } 26958556204SWilliam Breathitt Gray 27058556204SWilliam Breathitt Gray static void idio_24_irq_unmask(struct irq_data *data) 27158556204SWilliam Breathitt Gray { 27258556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 27358556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 27458556204SWilliam Breathitt Gray unsigned long flags; 27558556204SWilliam Breathitt Gray unsigned char prev_irq_mask; 27658556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 27758556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 27858556204SWilliam Breathitt Gray unsigned char cos_enable_state; 27958556204SWilliam Breathitt Gray 28058556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 28158556204SWilliam Breathitt Gray 28258556204SWilliam Breathitt Gray prev_irq_mask = idio24gpio->irq_mask >> bank_offset; 28358556204SWilliam Breathitt Gray idio24gpio->irq_mask |= BIT(bit_offset); 28458556204SWilliam Breathitt Gray 28558556204SWilliam Breathitt Gray if (!prev_irq_mask) { 28658556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 28758556204SWilliam Breathitt Gray 28858556204SWilliam Breathitt Gray /* Enable Rising Edge detection */ 28958556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset); 29058556204SWilliam Breathitt Gray /* Enable Falling Edge detection */ 29158556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset + 4); 29258556204SWilliam Breathitt Gray 29358556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 29458556204SWilliam Breathitt Gray } 29558556204SWilliam Breathitt Gray 29658556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 29758556204SWilliam Breathitt Gray } 29858556204SWilliam Breathitt Gray 29958556204SWilliam Breathitt Gray static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) 30058556204SWilliam Breathitt Gray { 30158556204SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 30258556204SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 30358556204SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 30458556204SWilliam Breathitt Gray return -EINVAL; 30558556204SWilliam Breathitt Gray 30658556204SWilliam Breathitt Gray return 0; 30758556204SWilliam Breathitt Gray } 30858556204SWilliam Breathitt Gray 30958556204SWilliam Breathitt Gray static struct irq_chip idio_24_irqchip = { 31058556204SWilliam Breathitt Gray .name = "pcie-idio-24", 31158556204SWilliam Breathitt Gray .irq_ack = idio_24_irq_ack, 31258556204SWilliam Breathitt Gray .irq_mask = idio_24_irq_mask, 31358556204SWilliam Breathitt Gray .irq_unmask = idio_24_irq_unmask, 31458556204SWilliam Breathitt Gray .irq_set_type = idio_24_irq_set_type 31558556204SWilliam Breathitt Gray }; 31658556204SWilliam Breathitt Gray 31758556204SWilliam Breathitt Gray static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) 31858556204SWilliam Breathitt Gray { 31958556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = dev_id; 32058556204SWilliam Breathitt Gray unsigned long irq_status; 32158556204SWilliam Breathitt Gray struct gpio_chip *const chip = &idio24gpio->chip; 32258556204SWilliam Breathitt Gray unsigned long irq_mask; 32358556204SWilliam Breathitt Gray int gpio; 32458556204SWilliam Breathitt Gray 32558556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 32658556204SWilliam Breathitt Gray 32758556204SWilliam Breathitt Gray /* Read Change-Of-State status */ 32858556204SWilliam Breathitt Gray irq_status = ioread32(&idio24gpio->reg->cos0_7); 32958556204SWilliam Breathitt Gray 33058556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 33158556204SWilliam Breathitt Gray 33258556204SWilliam Breathitt Gray /* Make sure our device generated IRQ */ 33358556204SWilliam Breathitt Gray if (!irq_status) 33458556204SWilliam Breathitt Gray return IRQ_NONE; 33558556204SWilliam Breathitt Gray 33658556204SWilliam Breathitt Gray /* Handle only unmasked IRQ */ 33758556204SWilliam Breathitt Gray irq_mask = idio24gpio->irq_mask & irq_status; 33858556204SWilliam Breathitt Gray 33958556204SWilliam Breathitt Gray for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24) 34058556204SWilliam Breathitt Gray generic_handle_irq(irq_find_mapping(chip->irq.domain, 34158556204SWilliam Breathitt Gray gpio + 24)); 34258556204SWilliam Breathitt Gray 34358556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 34458556204SWilliam Breathitt Gray 34558556204SWilliam Breathitt Gray /* Clear Change-Of-State status */ 34658556204SWilliam Breathitt Gray iowrite32(irq_status, &idio24gpio->reg->cos0_7); 34758556204SWilliam Breathitt Gray 34858556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 34958556204SWilliam Breathitt Gray 35058556204SWilliam Breathitt Gray return IRQ_HANDLED; 35158556204SWilliam Breathitt Gray } 35258556204SWilliam Breathitt Gray 35358556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56 35458556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = { 35558556204SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 35658556204SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 35758556204SWilliam Breathitt Gray "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", 35858556204SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 35958556204SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", 36058556204SWilliam Breathitt Gray "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", 36158556204SWilliam Breathitt Gray "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" 36258556204SWilliam Breathitt Gray }; 36358556204SWilliam Breathitt Gray 36458556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) 36558556204SWilliam Breathitt Gray { 36658556204SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 36758556204SWilliam Breathitt Gray struct idio_24_gpio *idio24gpio; 36858556204SWilliam Breathitt Gray int err; 36958556204SWilliam Breathitt Gray const size_t pci_bar_index = 2; 37058556204SWilliam Breathitt Gray const char *const name = pci_name(pdev); 37158556204SWilliam Breathitt Gray 37258556204SWilliam Breathitt Gray idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); 37358556204SWilliam Breathitt Gray if (!idio24gpio) 37458556204SWilliam Breathitt Gray return -ENOMEM; 37558556204SWilliam Breathitt Gray 37658556204SWilliam Breathitt Gray err = pcim_enable_device(pdev); 37758556204SWilliam Breathitt Gray if (err) { 37858556204SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 37958556204SWilliam Breathitt Gray return err; 38058556204SWilliam Breathitt Gray } 38158556204SWilliam Breathitt Gray 38258556204SWilliam Breathitt Gray err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); 38358556204SWilliam Breathitt Gray if (err) { 38458556204SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 38558556204SWilliam Breathitt Gray return err; 38658556204SWilliam Breathitt Gray } 38758556204SWilliam Breathitt Gray 38858556204SWilliam Breathitt Gray idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; 38958556204SWilliam Breathitt Gray 39058556204SWilliam Breathitt Gray idio24gpio->chip.label = name; 39158556204SWilliam Breathitt Gray idio24gpio->chip.parent = dev; 39258556204SWilliam Breathitt Gray idio24gpio->chip.owner = THIS_MODULE; 39358556204SWilliam Breathitt Gray idio24gpio->chip.base = -1; 39458556204SWilliam Breathitt Gray idio24gpio->chip.ngpio = IDIO_24_NGPIO; 39558556204SWilliam Breathitt Gray idio24gpio->chip.names = idio_24_names; 39658556204SWilliam Breathitt Gray idio24gpio->chip.get_direction = idio_24_gpio_get_direction; 39758556204SWilliam Breathitt Gray idio24gpio->chip.direction_input = idio_24_gpio_direction_input; 39858556204SWilliam Breathitt Gray idio24gpio->chip.direction_output = idio_24_gpio_direction_output; 39958556204SWilliam Breathitt Gray idio24gpio->chip.get = idio_24_gpio_get; 40058556204SWilliam Breathitt Gray idio24gpio->chip.set = idio_24_gpio_set; 40158556204SWilliam Breathitt Gray 40258556204SWilliam Breathitt Gray raw_spin_lock_init(&idio24gpio->lock); 40358556204SWilliam Breathitt Gray 40458556204SWilliam Breathitt Gray /* Software board reset */ 40558556204SWilliam Breathitt Gray iowrite8(0, &idio24gpio->reg->soft_reset); 40658556204SWilliam Breathitt Gray 40758556204SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio); 40858556204SWilliam Breathitt Gray if (err) { 40958556204SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 41058556204SWilliam Breathitt Gray return err; 41158556204SWilliam Breathitt Gray } 41258556204SWilliam Breathitt Gray 41358556204SWilliam Breathitt Gray err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0, 41458556204SWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 41558556204SWilliam Breathitt Gray if (err) { 41658556204SWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 41758556204SWilliam Breathitt Gray return err; 41858556204SWilliam Breathitt Gray } 41958556204SWilliam Breathitt Gray 42058556204SWilliam Breathitt Gray err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED, 42158556204SWilliam Breathitt Gray name, idio24gpio); 42258556204SWilliam Breathitt Gray if (err) { 42358556204SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 42458556204SWilliam Breathitt Gray return err; 42558556204SWilliam Breathitt Gray } 42658556204SWilliam Breathitt Gray 42758556204SWilliam Breathitt Gray return 0; 42858556204SWilliam Breathitt Gray } 42958556204SWilliam Breathitt Gray 43058556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = { 43158556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, 43258556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, 43358556204SWilliam Breathitt Gray { 0 } 43458556204SWilliam Breathitt Gray }; 43558556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); 43658556204SWilliam Breathitt Gray 43758556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = { 43858556204SWilliam Breathitt Gray .name = "pcie-idio-24", 43958556204SWilliam Breathitt Gray .id_table = idio_24_pci_dev_id, 44058556204SWilliam Breathitt Gray .probe = idio_24_probe 44158556204SWilliam Breathitt Gray }; 44258556204SWilliam Breathitt Gray 44358556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver); 44458556204SWilliam Breathitt Gray 44558556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 44658556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); 44758556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 448