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) 107*e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 10858556204SWilliam Breathitt Gray 10958556204SWilliam Breathitt Gray /* Isolated Inputs */ 11058556204SWilliam Breathitt Gray if (offset < 48) 111*e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 11258556204SWilliam Breathitt Gray 11358556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 11458556204SWilliam Breathitt Gray /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ 115*e42615ecSMatti Vaittinen if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 116*e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 117*e42615ecSMatti Vaittinen 118*e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 11958556204SWilliam Breathitt Gray } 12058556204SWilliam Breathitt Gray 12158556204SWilliam Breathitt Gray static int idio_24_gpio_direction_input(struct gpio_chip *chip, 12258556204SWilliam Breathitt Gray unsigned int offset) 12358556204SWilliam Breathitt Gray { 12458556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 12558556204SWilliam Breathitt Gray unsigned long flags; 12658556204SWilliam Breathitt Gray unsigned int ctl_state; 12758556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 12858556204SWilliam Breathitt Gray 12958556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 13058556204SWilliam Breathitt Gray if (offset > 47) { 13158556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 13258556204SWilliam Breathitt Gray 13358556204SWilliam Breathitt Gray /* Clear TTL/CMOS Output Mode */ 13458556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask; 13558556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 13658556204SWilliam Breathitt Gray 13758556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 13858556204SWilliam Breathitt Gray } 13958556204SWilliam Breathitt Gray 14058556204SWilliam Breathitt Gray return 0; 14158556204SWilliam Breathitt Gray } 14258556204SWilliam Breathitt Gray 14358556204SWilliam Breathitt Gray static int idio_24_gpio_direction_output(struct gpio_chip *chip, 14458556204SWilliam Breathitt Gray unsigned int offset, int value) 14558556204SWilliam Breathitt Gray { 14658556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 14758556204SWilliam Breathitt Gray unsigned long flags; 14858556204SWilliam Breathitt Gray unsigned int ctl_state; 14958556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 15058556204SWilliam Breathitt Gray 15158556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 15258556204SWilliam Breathitt Gray if (offset > 47) { 15358556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 15458556204SWilliam Breathitt Gray 15558556204SWilliam Breathitt Gray /* Set TTL/CMOS Output Mode */ 15658556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask; 15758556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 15858556204SWilliam Breathitt Gray 15958556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 16058556204SWilliam Breathitt Gray } 16158556204SWilliam Breathitt Gray 16258556204SWilliam Breathitt Gray chip->set(chip, offset, value); 16358556204SWilliam Breathitt Gray return 0; 16458556204SWilliam Breathitt Gray } 16558556204SWilliam Breathitt Gray 16658556204SWilliam Breathitt Gray static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) 16758556204SWilliam Breathitt Gray { 16858556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 16958556204SWilliam Breathitt Gray const unsigned long offset_mask = BIT(offset % 8); 17058556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 17158556204SWilliam Breathitt Gray 17258556204SWilliam Breathitt Gray /* FET Outputs */ 17358556204SWilliam Breathitt Gray if (offset < 8) 17458556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask); 17558556204SWilliam Breathitt Gray 17658556204SWilliam Breathitt Gray if (offset < 16) 17758556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask); 17858556204SWilliam Breathitt Gray 17958556204SWilliam Breathitt Gray if (offset < 24) 18058556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask); 18158556204SWilliam Breathitt Gray 18258556204SWilliam Breathitt Gray /* Isolated Inputs */ 18358556204SWilliam Breathitt Gray if (offset < 32) 18458556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask); 18558556204SWilliam Breathitt Gray 18658556204SWilliam Breathitt Gray if (offset < 40) 18758556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask); 18858556204SWilliam Breathitt Gray 18958556204SWilliam Breathitt Gray if (offset < 48) 19058556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask); 19158556204SWilliam Breathitt Gray 19258556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 19358556204SWilliam Breathitt Gray if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 19458556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask); 19558556204SWilliam Breathitt Gray 19658556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 19758556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); 19858556204SWilliam Breathitt Gray } 19958556204SWilliam Breathitt Gray 200ca370815SWilliam Breathitt Gray static int idio_24_gpio_get_multiple(struct gpio_chip *chip, 201ca370815SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 202ca370815SWilliam Breathitt Gray { 203ca370815SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 204ca370815SWilliam Breathitt Gray size_t i; 205ca370815SWilliam Breathitt Gray const unsigned int gpio_reg_size = 8; 206ca370815SWilliam Breathitt Gray unsigned int bits_offset; 207ca370815SWilliam Breathitt Gray size_t word_index; 208ca370815SWilliam Breathitt Gray unsigned int word_offset; 209ca370815SWilliam Breathitt Gray unsigned long word_mask; 210ca370815SWilliam Breathitt Gray const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); 211ca370815SWilliam Breathitt Gray unsigned long port_state; 212304440aaSWilliam Breathitt Gray void __iomem *ports[] = { 213304440aaSWilliam Breathitt Gray &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15, 214304440aaSWilliam Breathitt Gray &idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7, 215304440aaSWilliam Breathitt Gray &idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23, 216ca370815SWilliam Breathitt Gray }; 217ca370815SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 218ca370815SWilliam Breathitt Gray 219ca370815SWilliam Breathitt Gray /* clear bits array to a clean slate */ 220ca370815SWilliam Breathitt Gray bitmap_zero(bits, chip->ngpio); 221ca370815SWilliam Breathitt Gray 222ca370815SWilliam Breathitt Gray /* get bits are evaluated a gpio port register at a time */ 223e026646cSWilliam Breathitt Gray for (i = 0; i < ARRAY_SIZE(ports) + 1; i++) { 224ca370815SWilliam Breathitt Gray /* gpio offset in bits array */ 225ca370815SWilliam Breathitt Gray bits_offset = i * gpio_reg_size; 226ca370815SWilliam Breathitt Gray 227ca370815SWilliam Breathitt Gray /* word index for bits array */ 228ca370815SWilliam Breathitt Gray word_index = BIT_WORD(bits_offset); 229ca370815SWilliam Breathitt Gray 230ca370815SWilliam Breathitt Gray /* gpio offset within current word of bits array */ 231ca370815SWilliam Breathitt Gray word_offset = bits_offset % BITS_PER_LONG; 232ca370815SWilliam Breathitt Gray 233ca370815SWilliam Breathitt Gray /* mask of get bits for current gpio within current word */ 234ca370815SWilliam Breathitt Gray word_mask = mask[word_index] & (port_mask << word_offset); 235ca370815SWilliam Breathitt Gray if (!word_mask) { 236ca370815SWilliam Breathitt Gray /* no get bits in this port so skip to next one */ 237ca370815SWilliam Breathitt Gray continue; 238ca370815SWilliam Breathitt Gray } 239ca370815SWilliam Breathitt Gray 240ca370815SWilliam Breathitt Gray /* read bits from current gpio port (port 6 is TTL GPIO) */ 241ca370815SWilliam Breathitt Gray if (i < 6) 242304440aaSWilliam Breathitt Gray port_state = ioread8(ports[i]); 243ca370815SWilliam Breathitt Gray else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 244ca370815SWilliam Breathitt Gray port_state = ioread8(&idio24gpio->reg->ttl_out0_7); 245ca370815SWilliam Breathitt Gray else 246ca370815SWilliam Breathitt Gray port_state = ioread8(&idio24gpio->reg->ttl_in0_7); 247ca370815SWilliam Breathitt Gray 248ca370815SWilliam Breathitt Gray /* store acquired bits at respective bits array offset */ 24925451945SWilliam Breathitt Gray bits[word_index] |= (port_state << word_offset) & word_mask; 250ca370815SWilliam Breathitt Gray } 251ca370815SWilliam Breathitt Gray 252ca370815SWilliam Breathitt Gray return 0; 253ca370815SWilliam Breathitt Gray } 254ca370815SWilliam Breathitt Gray 25558556204SWilliam Breathitt Gray static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, 25658556204SWilliam Breathitt Gray int value) 25758556204SWilliam Breathitt Gray { 25858556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 25958556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 26058556204SWilliam Breathitt Gray void __iomem *base; 26158556204SWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 26258556204SWilliam Breathitt Gray unsigned long flags; 26358556204SWilliam Breathitt Gray unsigned int out_state; 26458556204SWilliam Breathitt Gray 26558556204SWilliam Breathitt Gray /* Isolated Inputs */ 26658556204SWilliam Breathitt Gray if (offset > 23 && offset < 48) 26758556204SWilliam Breathitt Gray return; 26858556204SWilliam Breathitt Gray 26958556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 27058556204SWilliam Breathitt Gray if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) 27158556204SWilliam Breathitt Gray return; 27258556204SWilliam Breathitt Gray 27358556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 27458556204SWilliam Breathitt Gray if (offset > 47) 27558556204SWilliam Breathitt Gray base = &idio24gpio->reg->ttl_out0_7; 27658556204SWilliam Breathitt Gray /* FET Outputs */ 27758556204SWilliam Breathitt Gray else if (offset > 15) 27858556204SWilliam Breathitt Gray base = &idio24gpio->reg->out16_23; 27958556204SWilliam Breathitt Gray else if (offset > 7) 28058556204SWilliam Breathitt Gray base = &idio24gpio->reg->out8_15; 28158556204SWilliam Breathitt Gray else 28258556204SWilliam Breathitt Gray base = &idio24gpio->reg->out0_7; 28358556204SWilliam Breathitt Gray 28458556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 28558556204SWilliam Breathitt Gray 28658556204SWilliam Breathitt Gray if (value) 28758556204SWilliam Breathitt Gray out_state = ioread8(base) | mask; 28858556204SWilliam Breathitt Gray else 28958556204SWilliam Breathitt Gray out_state = ioread8(base) & ~mask; 29058556204SWilliam Breathitt Gray 29158556204SWilliam Breathitt Gray iowrite8(out_state, base); 29258556204SWilliam Breathitt Gray 29358556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 29458556204SWilliam Breathitt Gray } 29558556204SWilliam Breathitt Gray 296ca370815SWilliam Breathitt Gray static void idio_24_gpio_set_multiple(struct gpio_chip *chip, 297ca370815SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 298ca370815SWilliam Breathitt Gray { 299ca370815SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 300ca370815SWilliam Breathitt Gray size_t i; 301ca370815SWilliam Breathitt Gray unsigned long bits_offset; 302ca370815SWilliam Breathitt Gray unsigned long gpio_mask; 303ca370815SWilliam Breathitt Gray const unsigned int gpio_reg_size = 8; 304ca370815SWilliam Breathitt Gray const unsigned long port_mask = GENMASK(gpio_reg_size, 0); 305ca370815SWilliam Breathitt Gray unsigned long flags; 306ca370815SWilliam Breathitt Gray unsigned int out_state; 307304440aaSWilliam Breathitt Gray void __iomem *ports[] = { 308304440aaSWilliam Breathitt Gray &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15, 309304440aaSWilliam Breathitt Gray &idio24gpio->reg->out16_23 310ca370815SWilliam Breathitt Gray }; 311ca370815SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 312ca370815SWilliam Breathitt Gray const unsigned int ttl_offset = 48; 313ca370815SWilliam Breathitt Gray const size_t ttl_i = BIT_WORD(ttl_offset); 314ca370815SWilliam Breathitt Gray const unsigned int word_offset = ttl_offset % BITS_PER_LONG; 315ca370815SWilliam Breathitt Gray const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask; 316ca370815SWilliam Breathitt Gray const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask; 317ca370815SWilliam Breathitt Gray 318ca370815SWilliam Breathitt Gray /* set bits are processed a gpio port register at a time */ 319ca370815SWilliam Breathitt Gray for (i = 0; i < ARRAY_SIZE(ports); i++) { 320ca370815SWilliam Breathitt Gray /* gpio offset in bits array */ 321ca370815SWilliam Breathitt Gray bits_offset = i * gpio_reg_size; 322ca370815SWilliam Breathitt Gray 323ca370815SWilliam Breathitt Gray /* check if any set bits for current port */ 324ca370815SWilliam Breathitt Gray gpio_mask = (*mask >> bits_offset) & port_mask; 325ca370815SWilliam Breathitt Gray if (!gpio_mask) { 326ca370815SWilliam Breathitt Gray /* no set bits for this port so move on to next port */ 327ca370815SWilliam Breathitt Gray continue; 328ca370815SWilliam Breathitt Gray } 329ca370815SWilliam Breathitt Gray 330ca370815SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 331ca370815SWilliam Breathitt Gray 332ca370815SWilliam Breathitt Gray /* process output lines */ 333304440aaSWilliam Breathitt Gray out_state = ioread8(ports[i]) & ~gpio_mask; 334ca370815SWilliam Breathitt Gray out_state |= (*bits >> bits_offset) & gpio_mask; 335304440aaSWilliam Breathitt Gray iowrite8(out_state, ports[i]); 336ca370815SWilliam Breathitt Gray 337ca370815SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 338ca370815SWilliam Breathitt Gray } 339ca370815SWilliam Breathitt Gray 340ca370815SWilliam Breathitt Gray /* check if setting TTL lines and if they are in output mode */ 341ca370815SWilliam Breathitt Gray if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) 342ca370815SWilliam Breathitt Gray return; 343ca370815SWilliam Breathitt Gray 344ca370815SWilliam Breathitt Gray /* handle TTL output */ 345ca370815SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 346ca370815SWilliam Breathitt Gray 347ca370815SWilliam Breathitt Gray /* process output lines */ 348ca370815SWilliam Breathitt Gray out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask; 349ca370815SWilliam Breathitt Gray out_state |= ttl_bits; 350ca370815SWilliam Breathitt Gray iowrite8(out_state, &idio24gpio->reg->ttl_out0_7); 351ca370815SWilliam Breathitt Gray 352ca370815SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 353ca370815SWilliam Breathitt Gray } 354ca370815SWilliam Breathitt Gray 35558556204SWilliam Breathitt Gray static void idio_24_irq_ack(struct irq_data *data) 35658556204SWilliam Breathitt Gray { 35758556204SWilliam Breathitt Gray } 35858556204SWilliam Breathitt Gray 35958556204SWilliam Breathitt Gray static void idio_24_irq_mask(struct irq_data *data) 36058556204SWilliam Breathitt Gray { 36158556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 36258556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 36358556204SWilliam Breathitt Gray unsigned long flags; 36458556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 36558556204SWilliam Breathitt Gray unsigned char new_irq_mask; 36658556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 36758556204SWilliam Breathitt Gray unsigned char cos_enable_state; 36858556204SWilliam Breathitt Gray 36958556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 37058556204SWilliam Breathitt Gray 37158556204SWilliam Breathitt Gray idio24gpio->irq_mask &= BIT(bit_offset); 37258556204SWilliam Breathitt Gray new_irq_mask = idio24gpio->irq_mask >> bank_offset; 37358556204SWilliam Breathitt Gray 37458556204SWilliam Breathitt Gray if (!new_irq_mask) { 37558556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 37658556204SWilliam Breathitt Gray 37758556204SWilliam Breathitt Gray /* Disable Rising Edge detection */ 37858556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset); 37958556204SWilliam Breathitt Gray /* Disable Falling Edge detection */ 38058556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset + 4); 38158556204SWilliam Breathitt Gray 38258556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 38358556204SWilliam Breathitt Gray } 38458556204SWilliam Breathitt Gray 38558556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 38658556204SWilliam Breathitt Gray } 38758556204SWilliam Breathitt Gray 38858556204SWilliam Breathitt Gray static void idio_24_irq_unmask(struct irq_data *data) 38958556204SWilliam Breathitt Gray { 39058556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 39158556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 39258556204SWilliam Breathitt Gray unsigned long flags; 39358556204SWilliam Breathitt Gray unsigned char prev_irq_mask; 39458556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 39558556204SWilliam Breathitt Gray const unsigned long bank_offset = bit_offset/8 * 8; 39658556204SWilliam Breathitt Gray unsigned char cos_enable_state; 39758556204SWilliam Breathitt Gray 39858556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 39958556204SWilliam Breathitt Gray 40058556204SWilliam Breathitt Gray prev_irq_mask = idio24gpio->irq_mask >> bank_offset; 40158556204SWilliam Breathitt Gray idio24gpio->irq_mask |= BIT(bit_offset); 40258556204SWilliam Breathitt Gray 40358556204SWilliam Breathitt Gray if (!prev_irq_mask) { 40458556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 40558556204SWilliam Breathitt Gray 40658556204SWilliam Breathitt Gray /* Enable Rising Edge detection */ 40758556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset); 40858556204SWilliam Breathitt Gray /* Enable Falling Edge detection */ 40958556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset + 4); 41058556204SWilliam Breathitt Gray 41158556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 41258556204SWilliam Breathitt Gray } 41358556204SWilliam Breathitt Gray 41458556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 41558556204SWilliam Breathitt Gray } 41658556204SWilliam Breathitt Gray 41758556204SWilliam Breathitt Gray static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) 41858556204SWilliam Breathitt Gray { 41958556204SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 42058556204SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 42158556204SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 42258556204SWilliam Breathitt Gray return -EINVAL; 42358556204SWilliam Breathitt Gray 42458556204SWilliam Breathitt Gray return 0; 42558556204SWilliam Breathitt Gray } 42658556204SWilliam Breathitt Gray 42758556204SWilliam Breathitt Gray static struct irq_chip idio_24_irqchip = { 42858556204SWilliam Breathitt Gray .name = "pcie-idio-24", 42958556204SWilliam Breathitt Gray .irq_ack = idio_24_irq_ack, 43058556204SWilliam Breathitt Gray .irq_mask = idio_24_irq_mask, 43158556204SWilliam Breathitt Gray .irq_unmask = idio_24_irq_unmask, 43258556204SWilliam Breathitt Gray .irq_set_type = idio_24_irq_set_type 43358556204SWilliam Breathitt Gray }; 43458556204SWilliam Breathitt Gray 43558556204SWilliam Breathitt Gray static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) 43658556204SWilliam Breathitt Gray { 43758556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = dev_id; 43858556204SWilliam Breathitt Gray unsigned long irq_status; 43958556204SWilliam Breathitt Gray struct gpio_chip *const chip = &idio24gpio->chip; 44058556204SWilliam Breathitt Gray unsigned long irq_mask; 44158556204SWilliam Breathitt Gray int gpio; 44258556204SWilliam Breathitt Gray 44358556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 44458556204SWilliam Breathitt Gray 44558556204SWilliam Breathitt Gray /* Read Change-Of-State status */ 44658556204SWilliam Breathitt Gray irq_status = ioread32(&idio24gpio->reg->cos0_7); 44758556204SWilliam Breathitt Gray 44858556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 44958556204SWilliam Breathitt Gray 45058556204SWilliam Breathitt Gray /* Make sure our device generated IRQ */ 45158556204SWilliam Breathitt Gray if (!irq_status) 45258556204SWilliam Breathitt Gray return IRQ_NONE; 45358556204SWilliam Breathitt Gray 45458556204SWilliam Breathitt Gray /* Handle only unmasked IRQ */ 45558556204SWilliam Breathitt Gray irq_mask = idio24gpio->irq_mask & irq_status; 45658556204SWilliam Breathitt Gray 45758556204SWilliam Breathitt Gray for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24) 45858556204SWilliam Breathitt Gray generic_handle_irq(irq_find_mapping(chip->irq.domain, 45958556204SWilliam Breathitt Gray gpio + 24)); 46058556204SWilliam Breathitt Gray 46158556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 46258556204SWilliam Breathitt Gray 46358556204SWilliam Breathitt Gray /* Clear Change-Of-State status */ 46458556204SWilliam Breathitt Gray iowrite32(irq_status, &idio24gpio->reg->cos0_7); 46558556204SWilliam Breathitt Gray 46658556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 46758556204SWilliam Breathitt Gray 46858556204SWilliam Breathitt Gray return IRQ_HANDLED; 46958556204SWilliam Breathitt Gray } 47058556204SWilliam Breathitt Gray 47158556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56 47258556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = { 47358556204SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 47458556204SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 47558556204SWilliam Breathitt Gray "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", 47658556204SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 47758556204SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", 47858556204SWilliam Breathitt Gray "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", 47958556204SWilliam Breathitt Gray "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" 48058556204SWilliam Breathitt Gray }; 48158556204SWilliam Breathitt Gray 48258556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) 48358556204SWilliam Breathitt Gray { 48458556204SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 48558556204SWilliam Breathitt Gray struct idio_24_gpio *idio24gpio; 48658556204SWilliam Breathitt Gray int err; 48758556204SWilliam Breathitt Gray const size_t pci_bar_index = 2; 48858556204SWilliam Breathitt Gray const char *const name = pci_name(pdev); 48958556204SWilliam Breathitt Gray 49058556204SWilliam Breathitt Gray idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); 49158556204SWilliam Breathitt Gray if (!idio24gpio) 49258556204SWilliam Breathitt Gray return -ENOMEM; 49358556204SWilliam Breathitt Gray 49458556204SWilliam Breathitt Gray err = pcim_enable_device(pdev); 49558556204SWilliam Breathitt Gray if (err) { 49658556204SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 49758556204SWilliam Breathitt Gray return err; 49858556204SWilliam Breathitt Gray } 49958556204SWilliam Breathitt Gray 50058556204SWilliam Breathitt Gray err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); 50158556204SWilliam Breathitt Gray if (err) { 50258556204SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 50358556204SWilliam Breathitt Gray return err; 50458556204SWilliam Breathitt Gray } 50558556204SWilliam Breathitt Gray 50658556204SWilliam Breathitt Gray idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; 50758556204SWilliam Breathitt Gray 50858556204SWilliam Breathitt Gray idio24gpio->chip.label = name; 50958556204SWilliam Breathitt Gray idio24gpio->chip.parent = dev; 51058556204SWilliam Breathitt Gray idio24gpio->chip.owner = THIS_MODULE; 51158556204SWilliam Breathitt Gray idio24gpio->chip.base = -1; 51258556204SWilliam Breathitt Gray idio24gpio->chip.ngpio = IDIO_24_NGPIO; 51358556204SWilliam Breathitt Gray idio24gpio->chip.names = idio_24_names; 51458556204SWilliam Breathitt Gray idio24gpio->chip.get_direction = idio_24_gpio_get_direction; 51558556204SWilliam Breathitt Gray idio24gpio->chip.direction_input = idio_24_gpio_direction_input; 51658556204SWilliam Breathitt Gray idio24gpio->chip.direction_output = idio_24_gpio_direction_output; 51758556204SWilliam Breathitt Gray idio24gpio->chip.get = idio_24_gpio_get; 518ca370815SWilliam Breathitt Gray idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple; 51958556204SWilliam Breathitt Gray idio24gpio->chip.set = idio_24_gpio_set; 520ca370815SWilliam Breathitt Gray idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple; 52158556204SWilliam Breathitt Gray 52258556204SWilliam Breathitt Gray raw_spin_lock_init(&idio24gpio->lock); 52358556204SWilliam Breathitt Gray 52458556204SWilliam Breathitt Gray /* Software board reset */ 52558556204SWilliam Breathitt Gray iowrite8(0, &idio24gpio->reg->soft_reset); 52658556204SWilliam Breathitt Gray 52758556204SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio); 52858556204SWilliam Breathitt Gray if (err) { 52958556204SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 53058556204SWilliam Breathitt Gray return err; 53158556204SWilliam Breathitt Gray } 53258556204SWilliam Breathitt Gray 53358556204SWilliam Breathitt Gray err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0, 53458556204SWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 53558556204SWilliam Breathitt Gray if (err) { 53658556204SWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 53758556204SWilliam Breathitt Gray return err; 53858556204SWilliam Breathitt Gray } 53958556204SWilliam Breathitt Gray 54058556204SWilliam Breathitt Gray err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED, 54158556204SWilliam Breathitt Gray name, idio24gpio); 54258556204SWilliam Breathitt Gray if (err) { 54358556204SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 54458556204SWilliam Breathitt Gray return err; 54558556204SWilliam Breathitt Gray } 54658556204SWilliam Breathitt Gray 54758556204SWilliam Breathitt Gray return 0; 54858556204SWilliam Breathitt Gray } 54958556204SWilliam Breathitt Gray 55058556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = { 55158556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, 55258556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, 55358556204SWilliam Breathitt Gray { 0 } 55458556204SWilliam Breathitt Gray }; 55558556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); 55658556204SWilliam Breathitt Gray 55758556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = { 55858556204SWilliam Breathitt Gray .name = "pcie-idio-24", 55958556204SWilliam Breathitt Gray .id_table = idio_24_pci_dev_id, 56058556204SWilliam Breathitt Gray .probe = idio_24_probe 56158556204SWilliam Breathitt Gray }; 56258556204SWilliam Breathitt Gray 56358556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver); 56458556204SWilliam Breathitt Gray 56558556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 56658556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); 56758556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 568