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 */ 18ca370815SWilliam Breathitt Gray #include <linux/bitmap.h> 1958556204SWilliam Breathitt Gray #include <linux/bitops.h> 2058556204SWilliam Breathitt Gray #include <linux/device.h> 2158556204SWilliam Breathitt Gray #include <linux/errno.h> 2258556204SWilliam Breathitt Gray #include <linux/gpio/driver.h> 2358556204SWilliam Breathitt Gray #include <linux/interrupt.h> 2458556204SWilliam Breathitt Gray #include <linux/irqdesc.h> 2558556204SWilliam Breathitt Gray #include <linux/kernel.h> 2658556204SWilliam Breathitt Gray #include <linux/module.h> 2758556204SWilliam Breathitt Gray #include <linux/pci.h> 2858556204SWilliam Breathitt Gray #include <linux/spinlock.h> 2958556204SWilliam Breathitt Gray #include <linux/types.h> 3058556204SWilliam Breathitt Gray 3158556204SWilliam Breathitt Gray /** 3258556204SWilliam Breathitt Gray * struct idio_24_gpio_reg - GPIO device registers structure 3358556204SWilliam Breathitt Gray * @out0_7: Read: FET Outputs 0-7 3458556204SWilliam Breathitt Gray * Write: FET Outputs 0-7 3558556204SWilliam Breathitt Gray * @out8_15: Read: FET Outputs 8-15 3658556204SWilliam Breathitt Gray * Write: FET Outputs 8-15 3758556204SWilliam Breathitt Gray * @out16_23: Read: FET Outputs 16-23 3858556204SWilliam Breathitt Gray * Write: FET Outputs 16-23 3958556204SWilliam Breathitt Gray * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7 4058556204SWilliam Breathitt Gray * Write: TTL/CMOS Outputs 0-7 4158556204SWilliam Breathitt Gray * @in0_7: Read: Isolated Inputs 0-7 4258556204SWilliam Breathitt Gray * Write: Reserved 4358556204SWilliam Breathitt Gray * @in8_15: Read: Isolated Inputs 8-15 4458556204SWilliam Breathitt Gray * Write: Reserved 4558556204SWilliam Breathitt Gray * @in16_23: Read: Isolated Inputs 16-23 4658556204SWilliam Breathitt Gray * Write: Reserved 4758556204SWilliam Breathitt Gray * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7 4858556204SWilliam Breathitt Gray * Write: Reserved 4958556204SWilliam Breathitt Gray * @cos0_7: Read: COS Status Inputs 0-7 5058556204SWilliam Breathitt Gray * Write: COS Clear Inputs 0-7 5158556204SWilliam Breathitt Gray * @cos8_15: Read: COS Status Inputs 8-15 5258556204SWilliam Breathitt Gray * Write: COS Clear Inputs 8-15 5358556204SWilliam Breathitt Gray * @cos16_23: Read: COS Status Inputs 16-23 5458556204SWilliam Breathitt Gray * Write: COS Clear Inputs 16-23 5558556204SWilliam Breathitt Gray * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7 5658556204SWilliam Breathitt Gray * Write: COS Clear TTL/CMOS 0-7 5758556204SWilliam Breathitt Gray * @ctl: Read: Control Register 5858556204SWilliam Breathitt Gray * Write: Control Register 5958556204SWilliam Breathitt Gray * @reserved: Read: Reserved 6058556204SWilliam Breathitt Gray * Write: Reserved 6158556204SWilliam Breathitt Gray * @cos_enable: Read: COS Enable 6258556204SWilliam Breathitt Gray * Write: COS Enable 6358556204SWilliam Breathitt Gray * @soft_reset: Read: IRQ Output Pin Status 6458556204SWilliam Breathitt Gray * Write: Software Board Reset 6558556204SWilliam Breathitt Gray */ 6658556204SWilliam Breathitt Gray struct idio_24_gpio_reg { 6758556204SWilliam Breathitt Gray u8 out0_7; 6858556204SWilliam Breathitt Gray u8 out8_15; 6958556204SWilliam Breathitt Gray u8 out16_23; 7058556204SWilliam Breathitt Gray u8 ttl_out0_7; 7158556204SWilliam Breathitt Gray u8 in0_7; 7258556204SWilliam Breathitt Gray u8 in8_15; 7358556204SWilliam Breathitt Gray u8 in16_23; 7458556204SWilliam Breathitt Gray u8 ttl_in0_7; 7558556204SWilliam Breathitt Gray u8 cos0_7; 7658556204SWilliam Breathitt Gray u8 cos8_15; 7758556204SWilliam Breathitt Gray u8 cos16_23; 7858556204SWilliam Breathitt Gray u8 cos_ttl0_7; 7958556204SWilliam Breathitt Gray u8 ctl; 8058556204SWilliam Breathitt Gray u8 reserved; 8158556204SWilliam Breathitt Gray u8 cos_enable; 8258556204SWilliam Breathitt Gray u8 soft_reset; 8358556204SWilliam Breathitt Gray }; 8458556204SWilliam Breathitt Gray 8558556204SWilliam Breathitt Gray /** 8658556204SWilliam Breathitt Gray * struct idio_24_gpio - GPIO device private data structure 8758556204SWilliam Breathitt Gray * @chip: instance of the gpio_chip 8858556204SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 8958556204SWilliam Breathitt Gray * @reg: I/O address offset for the GPIO device registers 9058556204SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 9158556204SWilliam Breathitt Gray */ 9258556204SWilliam Breathitt Gray struct idio_24_gpio { 9358556204SWilliam Breathitt Gray struct gpio_chip chip; 9458556204SWilliam Breathitt Gray raw_spinlock_t lock; 9558556204SWilliam Breathitt Gray struct idio_24_gpio_reg __iomem *reg; 9658556204SWilliam Breathitt Gray unsigned long irq_mask; 9758556204SWilliam Breathitt Gray }; 9858556204SWilliam Breathitt Gray 9958556204SWilliam Breathitt Gray static int idio_24_gpio_get_direction(struct gpio_chip *chip, 10058556204SWilliam Breathitt Gray unsigned int offset) 10158556204SWilliam Breathitt Gray { 10258556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 10358556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 10458556204SWilliam Breathitt Gray 10558556204SWilliam Breathitt Gray /* FET Outputs */ 10658556204SWilliam Breathitt Gray if (offset < 24) 10758556204SWilliam Breathitt Gray return 0; 10858556204SWilliam Breathitt Gray 10958556204SWilliam Breathitt Gray /* Isolated Inputs */ 11058556204SWilliam Breathitt Gray if (offset < 48) 11158556204SWilliam Breathitt Gray return 1; 11258556204SWilliam Breathitt Gray 11358556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 11458556204SWilliam Breathitt Gray /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ 11558556204SWilliam Breathitt Gray return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask); 11658556204SWilliam Breathitt Gray } 11758556204SWilliam Breathitt Gray 11858556204SWilliam Breathitt Gray static int idio_24_gpio_direction_input(struct gpio_chip *chip, 11958556204SWilliam Breathitt Gray unsigned int offset) 12058556204SWilliam Breathitt Gray { 12158556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 12258556204SWilliam Breathitt Gray unsigned long flags; 12358556204SWilliam Breathitt Gray unsigned int ctl_state; 12458556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 12558556204SWilliam Breathitt Gray 12658556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 12758556204SWilliam Breathitt Gray if (offset > 47) { 12858556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 12958556204SWilliam Breathitt Gray 13058556204SWilliam Breathitt Gray /* Clear TTL/CMOS Output Mode */ 13158556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask; 13258556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 13358556204SWilliam Breathitt Gray 13458556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 13558556204SWilliam Breathitt Gray } 13658556204SWilliam Breathitt Gray 13758556204SWilliam Breathitt Gray return 0; 13858556204SWilliam Breathitt Gray } 13958556204SWilliam Breathitt Gray 14058556204SWilliam Breathitt Gray static int idio_24_gpio_direction_output(struct gpio_chip *chip, 14158556204SWilliam Breathitt Gray unsigned int offset, int value) 14258556204SWilliam Breathitt Gray { 14358556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 14458556204SWilliam Breathitt Gray unsigned long flags; 14558556204SWilliam Breathitt Gray unsigned int ctl_state; 14658556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 14758556204SWilliam Breathitt Gray 14858556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 14958556204SWilliam Breathitt Gray if (offset > 47) { 15058556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 15158556204SWilliam Breathitt Gray 15258556204SWilliam Breathitt Gray /* Set TTL/CMOS Output Mode */ 15358556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask; 15458556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 15558556204SWilliam Breathitt Gray 15658556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 15758556204SWilliam Breathitt Gray } 15858556204SWilliam Breathitt Gray 15958556204SWilliam Breathitt Gray chip->set(chip, offset, value); 16058556204SWilliam Breathitt Gray return 0; 16158556204SWilliam Breathitt Gray } 16258556204SWilliam Breathitt Gray 16358556204SWilliam Breathitt Gray static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) 16458556204SWilliam Breathitt Gray { 16558556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 16658556204SWilliam Breathitt Gray const unsigned long offset_mask = BIT(offset % 8); 16758556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 16858556204SWilliam Breathitt Gray 16958556204SWilliam Breathitt Gray /* FET Outputs */ 17058556204SWilliam Breathitt Gray if (offset < 8) 17158556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask); 17258556204SWilliam Breathitt Gray 17358556204SWilliam Breathitt Gray if (offset < 16) 17458556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask); 17558556204SWilliam Breathitt Gray 17658556204SWilliam Breathitt Gray if (offset < 24) 17758556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask); 17858556204SWilliam Breathitt Gray 17958556204SWilliam Breathitt Gray /* Isolated Inputs */ 18058556204SWilliam Breathitt Gray if (offset < 32) 18158556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask); 18258556204SWilliam Breathitt Gray 18358556204SWilliam Breathitt Gray if (offset < 40) 18458556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask); 18558556204SWilliam Breathitt Gray 18658556204SWilliam Breathitt Gray if (offset < 48) 18758556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask); 18858556204SWilliam Breathitt Gray 18958556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 19058556204SWilliam Breathitt Gray if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 19158556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask); 19258556204SWilliam Breathitt Gray 19358556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 19458556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); 19558556204SWilliam Breathitt Gray } 19658556204SWilliam Breathitt Gray 197ca370815SWilliam Breathitt Gray static int idio_24_gpio_get_multiple(struct gpio_chip *chip, 198ca370815SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 199ca370815SWilliam Breathitt Gray { 200ca370815SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 201ca370815SWilliam Breathitt Gray size_t i; 202ca370815SWilliam Breathitt Gray const unsigned int gpio_reg_size = 8; 203ca370815SWilliam Breathitt Gray unsigned int bits_offset; 204ca370815SWilliam Breathitt Gray size_t word_index; 205ca370815SWilliam Breathitt Gray unsigned int word_offset; 206ca370815SWilliam Breathitt Gray unsigned long word_mask; 207ca370815SWilliam Breathitt Gray const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); 208ca370815SWilliam Breathitt Gray unsigned long port_state; 209*304440aaSWilliam Breathitt Gray void __iomem *ports[] = { 210*304440aaSWilliam Breathitt Gray &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15, 211*304440aaSWilliam Breathitt Gray &idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7, 212*304440aaSWilliam Breathitt Gray &idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23, 213ca370815SWilliam Breathitt Gray }; 214ca370815SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 215ca370815SWilliam Breathitt Gray 216ca370815SWilliam Breathitt Gray /* clear bits array to a clean slate */ 217ca370815SWilliam Breathitt Gray bitmap_zero(bits, chip->ngpio); 218ca370815SWilliam Breathitt Gray 219ca370815SWilliam Breathitt Gray /* get bits are evaluated a gpio port register at a time */ 220ca370815SWilliam Breathitt Gray for (i = 0; i < ARRAY_SIZE(ports); i++) { 221ca370815SWilliam Breathitt Gray /* gpio offset in bits array */ 222ca370815SWilliam Breathitt Gray bits_offset = i * gpio_reg_size; 223ca370815SWilliam Breathitt Gray 224ca370815SWilliam Breathitt Gray /* word index for bits array */ 225ca370815SWilliam Breathitt Gray word_index = BIT_WORD(bits_offset); 226ca370815SWilliam Breathitt Gray 227ca370815SWilliam Breathitt Gray /* gpio offset within current word of bits array */ 228ca370815SWilliam Breathitt Gray word_offset = bits_offset % BITS_PER_LONG; 229ca370815SWilliam Breathitt Gray 230ca370815SWilliam Breathitt Gray /* mask of get bits for current gpio within current word */ 231ca370815SWilliam Breathitt Gray word_mask = mask[word_index] & (port_mask << word_offset); 232ca370815SWilliam Breathitt Gray if (!word_mask) { 233ca370815SWilliam Breathitt Gray /* no get bits in this port so skip to next one */ 234ca370815SWilliam Breathitt Gray continue; 235ca370815SWilliam Breathitt Gray } 236ca370815SWilliam Breathitt Gray 237ca370815SWilliam Breathitt Gray /* read bits from current gpio port (port 6 is TTL GPIO) */ 238ca370815SWilliam Breathitt Gray if (i < 6) 239*304440aaSWilliam Breathitt Gray port_state = ioread8(ports[i]); 240ca370815SWilliam Breathitt Gray else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 241ca370815SWilliam Breathitt Gray port_state = ioread8(&idio24gpio->reg->ttl_out0_7); 242ca370815SWilliam Breathitt Gray else 243ca370815SWilliam Breathitt Gray port_state = ioread8(&idio24gpio->reg->ttl_in0_7); 244ca370815SWilliam Breathitt Gray 245ca370815SWilliam Breathitt Gray /* store acquired bits at respective bits array offset */ 246ca370815SWilliam Breathitt Gray bits[word_index] |= port_state << word_offset; 247ca370815SWilliam Breathitt Gray } 248ca370815SWilliam Breathitt Gray 249ca370815SWilliam Breathitt Gray return 0; 250ca370815SWilliam Breathitt Gray } 251ca370815SWilliam Breathitt Gray 25258556204SWilliam Breathitt Gray static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, 25358556204SWilliam Breathitt Gray int value) 25458556204SWilliam Breathitt Gray { 25558556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 25658556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 25758556204SWilliam Breathitt Gray void __iomem *base; 25858556204SWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 25958556204SWilliam Breathitt Gray unsigned long flags; 26058556204SWilliam Breathitt Gray unsigned int out_state; 26158556204SWilliam Breathitt Gray 26258556204SWilliam Breathitt Gray /* Isolated Inputs */ 26358556204SWilliam Breathitt Gray if (offset > 23 && offset < 48) 26458556204SWilliam Breathitt Gray return; 26558556204SWilliam Breathitt Gray 26658556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 26758556204SWilliam Breathitt Gray if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) 26858556204SWilliam Breathitt Gray return; 26958556204SWilliam Breathitt Gray 27058556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 27158556204SWilliam Breathitt Gray if (offset > 47) 27258556204SWilliam Breathitt Gray base = &idio24gpio->reg->ttl_out0_7; 27358556204SWilliam Breathitt Gray /* FET Outputs */ 27458556204SWilliam Breathitt Gray else if (offset > 15) 27558556204SWilliam Breathitt Gray base = &idio24gpio->reg->out16_23; 27658556204SWilliam Breathitt Gray else if (offset > 7) 27758556204SWilliam Breathitt Gray base = &idio24gpio->reg->out8_15; 27858556204SWilliam Breathitt Gray else 27958556204SWilliam Breathitt Gray base = &idio24gpio->reg->out0_7; 28058556204SWilliam Breathitt Gray 28158556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 28258556204SWilliam Breathitt Gray 28358556204SWilliam Breathitt Gray if (value) 28458556204SWilliam Breathitt Gray out_state = ioread8(base) | mask; 28558556204SWilliam Breathitt Gray else 28658556204SWilliam Breathitt Gray out_state = ioread8(base) & ~mask; 28758556204SWilliam Breathitt Gray 28858556204SWilliam Breathitt Gray iowrite8(out_state, base); 28958556204SWilliam Breathitt Gray 29058556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 29158556204SWilliam Breathitt Gray } 29258556204SWilliam Breathitt Gray 293ca370815SWilliam Breathitt Gray static void idio_24_gpio_set_multiple(struct gpio_chip *chip, 294ca370815SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 295ca370815SWilliam Breathitt Gray { 296ca370815SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 297ca370815SWilliam Breathitt Gray size_t i; 298ca370815SWilliam Breathitt Gray unsigned long bits_offset; 299ca370815SWilliam Breathitt Gray unsigned long gpio_mask; 300ca370815SWilliam Breathitt Gray const unsigned int gpio_reg_size = 8; 301ca370815SWilliam Breathitt Gray const unsigned long port_mask = GENMASK(gpio_reg_size, 0); 302ca370815SWilliam Breathitt Gray unsigned long flags; 303ca370815SWilliam Breathitt Gray unsigned int out_state; 304*304440aaSWilliam Breathitt Gray void __iomem *ports[] = { 305*304440aaSWilliam Breathitt Gray &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15, 306*304440aaSWilliam Breathitt Gray &idio24gpio->reg->out16_23 307ca370815SWilliam Breathitt Gray }; 308ca370815SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 309ca370815SWilliam Breathitt Gray const unsigned int ttl_offset = 48; 310ca370815SWilliam Breathitt Gray const size_t ttl_i = BIT_WORD(ttl_offset); 311ca370815SWilliam Breathitt Gray const unsigned int word_offset = ttl_offset % BITS_PER_LONG; 312ca370815SWilliam Breathitt Gray const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask; 313ca370815SWilliam Breathitt Gray const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask; 314ca370815SWilliam Breathitt Gray 315ca370815SWilliam Breathitt Gray /* set bits are processed a gpio port register at a time */ 316ca370815SWilliam Breathitt Gray for (i = 0; i < ARRAY_SIZE(ports); i++) { 317ca370815SWilliam Breathitt Gray /* gpio offset in bits array */ 318ca370815SWilliam Breathitt Gray bits_offset = i * gpio_reg_size; 319ca370815SWilliam Breathitt Gray 320ca370815SWilliam Breathitt Gray /* check if any set bits for current port */ 321ca370815SWilliam Breathitt Gray gpio_mask = (*mask >> bits_offset) & port_mask; 322ca370815SWilliam Breathitt Gray if (!gpio_mask) { 323ca370815SWilliam Breathitt Gray /* no set bits for this port so move on to next port */ 324ca370815SWilliam Breathitt Gray continue; 325ca370815SWilliam Breathitt Gray } 326ca370815SWilliam Breathitt Gray 327ca370815SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 328ca370815SWilliam Breathitt Gray 329ca370815SWilliam Breathitt Gray /* process output lines */ 330*304440aaSWilliam Breathitt Gray out_state = ioread8(ports[i]) & ~gpio_mask; 331ca370815SWilliam Breathitt Gray out_state |= (*bits >> bits_offset) & gpio_mask; 332*304440aaSWilliam Breathitt Gray iowrite8(out_state, ports[i]); 333ca370815SWilliam Breathitt Gray 334ca370815SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 335ca370815SWilliam Breathitt Gray } 336ca370815SWilliam Breathitt Gray 337ca370815SWilliam Breathitt Gray /* check if setting TTL lines and if they are in output mode */ 338ca370815SWilliam Breathitt Gray if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) 339ca370815SWilliam Breathitt Gray return; 340ca370815SWilliam Breathitt Gray 341ca370815SWilliam Breathitt Gray /* handle TTL output */ 342ca370815SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 343ca370815SWilliam Breathitt Gray 344ca370815SWilliam Breathitt Gray /* process output lines */ 345ca370815SWilliam Breathitt Gray out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask; 346ca370815SWilliam Breathitt Gray out_state |= ttl_bits; 347ca370815SWilliam Breathitt Gray iowrite8(out_state, &idio24gpio->reg->ttl_out0_7); 348ca370815SWilliam Breathitt Gray 349ca370815SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 350ca370815SWilliam Breathitt Gray } 351ca370815SWilliam Breathitt Gray 35258556204SWilliam Breathitt Gray static void idio_24_irq_ack(struct irq_data *data) 35358556204SWilliam Breathitt Gray { 35458556204SWilliam Breathitt Gray } 35558556204SWilliam Breathitt Gray 35658556204SWilliam Breathitt Gray static void idio_24_irq_mask(struct irq_data *data) 35758556204SWilliam Breathitt Gray { 35858556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 35958556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 36058556204SWilliam Breathitt Gray unsigned long flags; 36158556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 36258556204SWilliam Breathitt Gray unsigned char new_irq_mask; 36358556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 36458556204SWilliam Breathitt Gray unsigned char cos_enable_state; 36558556204SWilliam Breathitt Gray 36658556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 36758556204SWilliam Breathitt Gray 36858556204SWilliam Breathitt Gray idio24gpio->irq_mask &= BIT(bit_offset); 36958556204SWilliam Breathitt Gray new_irq_mask = idio24gpio->irq_mask >> bank_offset; 37058556204SWilliam Breathitt Gray 37158556204SWilliam Breathitt Gray if (!new_irq_mask) { 37258556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 37358556204SWilliam Breathitt Gray 37458556204SWilliam Breathitt Gray /* Disable Rising Edge detection */ 37558556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset); 37658556204SWilliam Breathitt Gray /* Disable Falling Edge detection */ 37758556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset + 4); 37858556204SWilliam Breathitt Gray 37958556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 38058556204SWilliam Breathitt Gray } 38158556204SWilliam Breathitt Gray 38258556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 38358556204SWilliam Breathitt Gray } 38458556204SWilliam Breathitt Gray 38558556204SWilliam Breathitt Gray static void idio_24_irq_unmask(struct irq_data *data) 38658556204SWilliam Breathitt Gray { 38758556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 38858556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 38958556204SWilliam Breathitt Gray unsigned long flags; 39058556204SWilliam Breathitt Gray unsigned char prev_irq_mask; 39158556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 39258556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 39358556204SWilliam Breathitt Gray unsigned char cos_enable_state; 39458556204SWilliam Breathitt Gray 39558556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 39658556204SWilliam Breathitt Gray 39758556204SWilliam Breathitt Gray prev_irq_mask = idio24gpio->irq_mask >> bank_offset; 39858556204SWilliam Breathitt Gray idio24gpio->irq_mask |= BIT(bit_offset); 39958556204SWilliam Breathitt Gray 40058556204SWilliam Breathitt Gray if (!prev_irq_mask) { 40158556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 40258556204SWilliam Breathitt Gray 40358556204SWilliam Breathitt Gray /* Enable Rising Edge detection */ 40458556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset); 40558556204SWilliam Breathitt Gray /* Enable Falling Edge detection */ 40658556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset + 4); 40758556204SWilliam Breathitt Gray 40858556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 40958556204SWilliam Breathitt Gray } 41058556204SWilliam Breathitt Gray 41158556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 41258556204SWilliam Breathitt Gray } 41358556204SWilliam Breathitt Gray 41458556204SWilliam Breathitt Gray static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) 41558556204SWilliam Breathitt Gray { 41658556204SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 41758556204SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 41858556204SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 41958556204SWilliam Breathitt Gray return -EINVAL; 42058556204SWilliam Breathitt Gray 42158556204SWilliam Breathitt Gray return 0; 42258556204SWilliam Breathitt Gray } 42358556204SWilliam Breathitt Gray 42458556204SWilliam Breathitt Gray static struct irq_chip idio_24_irqchip = { 42558556204SWilliam Breathitt Gray .name = "pcie-idio-24", 42658556204SWilliam Breathitt Gray .irq_ack = idio_24_irq_ack, 42758556204SWilliam Breathitt Gray .irq_mask = idio_24_irq_mask, 42858556204SWilliam Breathitt Gray .irq_unmask = idio_24_irq_unmask, 42958556204SWilliam Breathitt Gray .irq_set_type = idio_24_irq_set_type 43058556204SWilliam Breathitt Gray }; 43158556204SWilliam Breathitt Gray 43258556204SWilliam Breathitt Gray static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) 43358556204SWilliam Breathitt Gray { 43458556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = dev_id; 43558556204SWilliam Breathitt Gray unsigned long irq_status; 43658556204SWilliam Breathitt Gray struct gpio_chip *const chip = &idio24gpio->chip; 43758556204SWilliam Breathitt Gray unsigned long irq_mask; 43858556204SWilliam Breathitt Gray int gpio; 43958556204SWilliam Breathitt Gray 44058556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 44158556204SWilliam Breathitt Gray 44258556204SWilliam Breathitt Gray /* Read Change-Of-State status */ 44358556204SWilliam Breathitt Gray irq_status = ioread32(&idio24gpio->reg->cos0_7); 44458556204SWilliam Breathitt Gray 44558556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 44658556204SWilliam Breathitt Gray 44758556204SWilliam Breathitt Gray /* Make sure our device generated IRQ */ 44858556204SWilliam Breathitt Gray if (!irq_status) 44958556204SWilliam Breathitt Gray return IRQ_NONE; 45058556204SWilliam Breathitt Gray 45158556204SWilliam Breathitt Gray /* Handle only unmasked IRQ */ 45258556204SWilliam Breathitt Gray irq_mask = idio24gpio->irq_mask & irq_status; 45358556204SWilliam Breathitt Gray 45458556204SWilliam Breathitt Gray for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24) 45558556204SWilliam Breathitt Gray generic_handle_irq(irq_find_mapping(chip->irq.domain, 45658556204SWilliam Breathitt Gray gpio + 24)); 45758556204SWilliam Breathitt Gray 45858556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 45958556204SWilliam Breathitt Gray 46058556204SWilliam Breathitt Gray /* Clear Change-Of-State status */ 46158556204SWilliam Breathitt Gray iowrite32(irq_status, &idio24gpio->reg->cos0_7); 46258556204SWilliam Breathitt Gray 46358556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 46458556204SWilliam Breathitt Gray 46558556204SWilliam Breathitt Gray return IRQ_HANDLED; 46658556204SWilliam Breathitt Gray } 46758556204SWilliam Breathitt Gray 46858556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56 46958556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = { 47058556204SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 47158556204SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 47258556204SWilliam Breathitt Gray "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", 47358556204SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 47458556204SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", 47558556204SWilliam Breathitt Gray "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", 47658556204SWilliam Breathitt Gray "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" 47758556204SWilliam Breathitt Gray }; 47858556204SWilliam Breathitt Gray 47958556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) 48058556204SWilliam Breathitt Gray { 48158556204SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 48258556204SWilliam Breathitt Gray struct idio_24_gpio *idio24gpio; 48358556204SWilliam Breathitt Gray int err; 48458556204SWilliam Breathitt Gray const size_t pci_bar_index = 2; 48558556204SWilliam Breathitt Gray const char *const name = pci_name(pdev); 48658556204SWilliam Breathitt Gray 48758556204SWilliam Breathitt Gray idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); 48858556204SWilliam Breathitt Gray if (!idio24gpio) 48958556204SWilliam Breathitt Gray return -ENOMEM; 49058556204SWilliam Breathitt Gray 49158556204SWilliam Breathitt Gray err = pcim_enable_device(pdev); 49258556204SWilliam Breathitt Gray if (err) { 49358556204SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 49458556204SWilliam Breathitt Gray return err; 49558556204SWilliam Breathitt Gray } 49658556204SWilliam Breathitt Gray 49758556204SWilliam Breathitt Gray err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); 49858556204SWilliam Breathitt Gray if (err) { 49958556204SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 50058556204SWilliam Breathitt Gray return err; 50158556204SWilliam Breathitt Gray } 50258556204SWilliam Breathitt Gray 50358556204SWilliam Breathitt Gray idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; 50458556204SWilliam Breathitt Gray 50558556204SWilliam Breathitt Gray idio24gpio->chip.label = name; 50658556204SWilliam Breathitt Gray idio24gpio->chip.parent = dev; 50758556204SWilliam Breathitt Gray idio24gpio->chip.owner = THIS_MODULE; 50858556204SWilliam Breathitt Gray idio24gpio->chip.base = -1; 50958556204SWilliam Breathitt Gray idio24gpio->chip.ngpio = IDIO_24_NGPIO; 51058556204SWilliam Breathitt Gray idio24gpio->chip.names = idio_24_names; 51158556204SWilliam Breathitt Gray idio24gpio->chip.get_direction = idio_24_gpio_get_direction; 51258556204SWilliam Breathitt Gray idio24gpio->chip.direction_input = idio_24_gpio_direction_input; 51358556204SWilliam Breathitt Gray idio24gpio->chip.direction_output = idio_24_gpio_direction_output; 51458556204SWilliam Breathitt Gray idio24gpio->chip.get = idio_24_gpio_get; 515ca370815SWilliam Breathitt Gray idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple; 51658556204SWilliam Breathitt Gray idio24gpio->chip.set = idio_24_gpio_set; 517ca370815SWilliam Breathitt Gray idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple; 51858556204SWilliam Breathitt Gray 51958556204SWilliam Breathitt Gray raw_spin_lock_init(&idio24gpio->lock); 52058556204SWilliam Breathitt Gray 52158556204SWilliam Breathitt Gray /* Software board reset */ 52258556204SWilliam Breathitt Gray iowrite8(0, &idio24gpio->reg->soft_reset); 52358556204SWilliam Breathitt Gray 52458556204SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio); 52558556204SWilliam Breathitt Gray if (err) { 52658556204SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 52758556204SWilliam Breathitt Gray return err; 52858556204SWilliam Breathitt Gray } 52958556204SWilliam Breathitt Gray 53058556204SWilliam Breathitt Gray err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0, 53158556204SWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 53258556204SWilliam Breathitt Gray if (err) { 53358556204SWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 53458556204SWilliam Breathitt Gray return err; 53558556204SWilliam Breathitt Gray } 53658556204SWilliam Breathitt Gray 53758556204SWilliam Breathitt Gray err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED, 53858556204SWilliam Breathitt Gray name, idio24gpio); 53958556204SWilliam Breathitt Gray if (err) { 54058556204SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 54158556204SWilliam Breathitt Gray return err; 54258556204SWilliam Breathitt Gray } 54358556204SWilliam Breathitt Gray 54458556204SWilliam Breathitt Gray return 0; 54558556204SWilliam Breathitt Gray } 54658556204SWilliam Breathitt Gray 54758556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = { 54858556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, 54958556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, 55058556204SWilliam Breathitt Gray { 0 } 55158556204SWilliam Breathitt Gray }; 55258556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); 55358556204SWilliam Breathitt Gray 55458556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = { 55558556204SWilliam Breathitt Gray .name = "pcie-idio-24", 55658556204SWilliam Breathitt Gray .id_table = idio_24_pci_dev_id, 55758556204SWilliam Breathitt Gray .probe = idio_24_probe 55858556204SWilliam Breathitt Gray }; 55958556204SWilliam Breathitt Gray 56058556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver); 56158556204SWilliam Breathitt Gray 56258556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 56358556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); 56458556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 565