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 31*10a2f11dSArnaud de Turckheim /* 32*10a2f11dSArnaud de Turckheim * PLX PEX8311 PCI LCS_INTCSR Interrupt Control/Status 33*10a2f11dSArnaud de Turckheim * 34*10a2f11dSArnaud de Turckheim * Bit: Description 35*10a2f11dSArnaud de Turckheim * 0: Enable Interrupt Sources (Bit 0) 36*10a2f11dSArnaud de Turckheim * 1: Enable Interrupt Sources (Bit 1) 37*10a2f11dSArnaud de Turckheim * 2: Generate Internal PCI Bus Internal SERR# Interrupt 38*10a2f11dSArnaud de Turckheim * 3: Mailbox Interrupt Enable 39*10a2f11dSArnaud de Turckheim * 4: Power Management Interrupt Enable 40*10a2f11dSArnaud de Turckheim * 5: Power Management Interrupt 41*10a2f11dSArnaud de Turckheim * 6: Slave Read Local Data Parity Check Error Enable 42*10a2f11dSArnaud de Turckheim * 7: Slave Read Local Data Parity Check Error Status 43*10a2f11dSArnaud de Turckheim * 8: Internal PCI Wire Interrupt Enable 44*10a2f11dSArnaud de Turckheim * 9: PCI Express Doorbell Interrupt Enable 45*10a2f11dSArnaud de Turckheim * 10: PCI Abort Interrupt Enable 46*10a2f11dSArnaud de Turckheim * 11: Local Interrupt Input Enable 47*10a2f11dSArnaud de Turckheim * 12: Retry Abort Enable 48*10a2f11dSArnaud de Turckheim * 13: PCI Express Doorbell Interrupt Active 49*10a2f11dSArnaud de Turckheim * 14: PCI Abort Interrupt Active 50*10a2f11dSArnaud de Turckheim * 15: Local Interrupt Input Active 51*10a2f11dSArnaud de Turckheim * 16: Local Interrupt Output Enable 52*10a2f11dSArnaud de Turckheim * 17: Local Doorbell Interrupt Enable 53*10a2f11dSArnaud de Turckheim * 18: DMA Channel 0 Interrupt Enable 54*10a2f11dSArnaud de Turckheim * 19: DMA Channel 1 Interrupt Enable 55*10a2f11dSArnaud de Turckheim * 20: Local Doorbell Interrupt Active 56*10a2f11dSArnaud de Turckheim * 21: DMA Channel 0 Interrupt Active 57*10a2f11dSArnaud de Turckheim * 22: DMA Channel 1 Interrupt Active 58*10a2f11dSArnaud de Turckheim * 23: Built-In Self-Test (BIST) Interrupt Active 59*10a2f11dSArnaud de Turckheim * 24: Direct Master was the Bus Master during a Master or Target Abort 60*10a2f11dSArnaud de Turckheim * 25: DMA Channel 0 was the Bus Master during a Master or Target Abort 61*10a2f11dSArnaud de Turckheim * 26: DMA Channel 1 was the Bus Master during a Master or Target Abort 62*10a2f11dSArnaud de Turckheim * 27: Target Abort after internal 256 consecutive Master Retrys 63*10a2f11dSArnaud de Turckheim * 28: PCI Bus wrote data to LCS_MBOX0 64*10a2f11dSArnaud de Turckheim * 29: PCI Bus wrote data to LCS_MBOX1 65*10a2f11dSArnaud de Turckheim * 30: PCI Bus wrote data to LCS_MBOX2 66*10a2f11dSArnaud de Turckheim * 31: PCI Bus wrote data to LCS_MBOX3 67*10a2f11dSArnaud de Turckheim */ 68*10a2f11dSArnaud de Turckheim #define PLX_PEX8311_PCI_LCS_INTCSR 0x68 69*10a2f11dSArnaud de Turckheim #define INTCSR_INTERNAL_PCI_WIRE BIT(8) 70*10a2f11dSArnaud de Turckheim #define INTCSR_LOCAL_INPUT BIT(11) 71*10a2f11dSArnaud de Turckheim 7258556204SWilliam Breathitt Gray /** 7358556204SWilliam Breathitt Gray * struct idio_24_gpio_reg - GPIO device registers structure 7458556204SWilliam Breathitt Gray * @out0_7: Read: FET Outputs 0-7 7558556204SWilliam Breathitt Gray * Write: FET Outputs 0-7 7658556204SWilliam Breathitt Gray * @out8_15: Read: FET Outputs 8-15 7758556204SWilliam Breathitt Gray * Write: FET Outputs 8-15 7858556204SWilliam Breathitt Gray * @out16_23: Read: FET Outputs 16-23 7958556204SWilliam Breathitt Gray * Write: FET Outputs 16-23 8058556204SWilliam Breathitt Gray * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7 8158556204SWilliam Breathitt Gray * Write: TTL/CMOS Outputs 0-7 8258556204SWilliam Breathitt Gray * @in0_7: Read: Isolated Inputs 0-7 8358556204SWilliam Breathitt Gray * Write: Reserved 8458556204SWilliam Breathitt Gray * @in8_15: Read: Isolated Inputs 8-15 8558556204SWilliam Breathitt Gray * Write: Reserved 8658556204SWilliam Breathitt Gray * @in16_23: Read: Isolated Inputs 16-23 8758556204SWilliam Breathitt Gray * Write: Reserved 8858556204SWilliam Breathitt Gray * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7 8958556204SWilliam Breathitt Gray * Write: Reserved 9058556204SWilliam Breathitt Gray * @cos0_7: Read: COS Status Inputs 0-7 9158556204SWilliam Breathitt Gray * Write: COS Clear Inputs 0-7 9258556204SWilliam Breathitt Gray * @cos8_15: Read: COS Status Inputs 8-15 9358556204SWilliam Breathitt Gray * Write: COS Clear Inputs 8-15 9458556204SWilliam Breathitt Gray * @cos16_23: Read: COS Status Inputs 16-23 9558556204SWilliam Breathitt Gray * Write: COS Clear Inputs 16-23 9658556204SWilliam Breathitt Gray * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7 9758556204SWilliam Breathitt Gray * Write: COS Clear TTL/CMOS 0-7 9858556204SWilliam Breathitt Gray * @ctl: Read: Control Register 9958556204SWilliam Breathitt Gray * Write: Control Register 10058556204SWilliam Breathitt Gray * @reserved: Read: Reserved 10158556204SWilliam Breathitt Gray * Write: Reserved 10258556204SWilliam Breathitt Gray * @cos_enable: Read: COS Enable 10358556204SWilliam Breathitt Gray * Write: COS Enable 10458556204SWilliam Breathitt Gray * @soft_reset: Read: IRQ Output Pin Status 10558556204SWilliam Breathitt Gray * Write: Software Board Reset 10658556204SWilliam Breathitt Gray */ 10758556204SWilliam Breathitt Gray struct idio_24_gpio_reg { 10858556204SWilliam Breathitt Gray u8 out0_7; 10958556204SWilliam Breathitt Gray u8 out8_15; 11058556204SWilliam Breathitt Gray u8 out16_23; 11158556204SWilliam Breathitt Gray u8 ttl_out0_7; 11258556204SWilliam Breathitt Gray u8 in0_7; 11358556204SWilliam Breathitt Gray u8 in8_15; 11458556204SWilliam Breathitt Gray u8 in16_23; 11558556204SWilliam Breathitt Gray u8 ttl_in0_7; 11658556204SWilliam Breathitt Gray u8 cos0_7; 11758556204SWilliam Breathitt Gray u8 cos8_15; 11858556204SWilliam Breathitt Gray u8 cos16_23; 11958556204SWilliam Breathitt Gray u8 cos_ttl0_7; 12058556204SWilliam Breathitt Gray u8 ctl; 12158556204SWilliam Breathitt Gray u8 reserved; 12258556204SWilliam Breathitt Gray u8 cos_enable; 12358556204SWilliam Breathitt Gray u8 soft_reset; 12458556204SWilliam Breathitt Gray }; 12558556204SWilliam Breathitt Gray 12658556204SWilliam Breathitt Gray /** 12758556204SWilliam Breathitt Gray * struct idio_24_gpio - GPIO device private data structure 12858556204SWilliam Breathitt Gray * @chip: instance of the gpio_chip 12958556204SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 13058556204SWilliam Breathitt Gray * @reg: I/O address offset for the GPIO device registers 13158556204SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 13258556204SWilliam Breathitt Gray */ 13358556204SWilliam Breathitt Gray struct idio_24_gpio { 13458556204SWilliam Breathitt Gray struct gpio_chip chip; 13558556204SWilliam Breathitt Gray raw_spinlock_t lock; 136*10a2f11dSArnaud de Turckheim __u8 __iomem *plx; 13758556204SWilliam Breathitt Gray struct idio_24_gpio_reg __iomem *reg; 13858556204SWilliam Breathitt Gray unsigned long irq_mask; 13958556204SWilliam Breathitt Gray }; 14058556204SWilliam Breathitt Gray 14158556204SWilliam Breathitt Gray static int idio_24_gpio_get_direction(struct gpio_chip *chip, 14258556204SWilliam Breathitt Gray unsigned int offset) 14358556204SWilliam Breathitt Gray { 14458556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 14558556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 14658556204SWilliam Breathitt Gray 14758556204SWilliam Breathitt Gray /* FET Outputs */ 14858556204SWilliam Breathitt Gray if (offset < 24) 149e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 15058556204SWilliam Breathitt Gray 15158556204SWilliam Breathitt Gray /* Isolated Inputs */ 15258556204SWilliam Breathitt Gray if (offset < 48) 153e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 15458556204SWilliam Breathitt Gray 15558556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 15658556204SWilliam Breathitt Gray /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ 157e42615ecSMatti Vaittinen if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 158e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 159e42615ecSMatti Vaittinen 160e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 16158556204SWilliam Breathitt Gray } 16258556204SWilliam Breathitt Gray 16358556204SWilliam Breathitt Gray static int idio_24_gpio_direction_input(struct gpio_chip *chip, 16458556204SWilliam Breathitt Gray unsigned int offset) 16558556204SWilliam Breathitt Gray { 16658556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 16758556204SWilliam Breathitt Gray unsigned long flags; 16858556204SWilliam Breathitt Gray unsigned int ctl_state; 16958556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 17058556204SWilliam Breathitt Gray 17158556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 17258556204SWilliam Breathitt Gray if (offset > 47) { 17358556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 17458556204SWilliam Breathitt Gray 17558556204SWilliam Breathitt Gray /* Clear TTL/CMOS Output Mode */ 17658556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask; 17758556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 17858556204SWilliam Breathitt Gray 17958556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 18058556204SWilliam Breathitt Gray } 18158556204SWilliam Breathitt Gray 18258556204SWilliam Breathitt Gray return 0; 18358556204SWilliam Breathitt Gray } 18458556204SWilliam Breathitt Gray 18558556204SWilliam Breathitt Gray static int idio_24_gpio_direction_output(struct gpio_chip *chip, 18658556204SWilliam Breathitt Gray unsigned int offset, int value) 18758556204SWilliam Breathitt Gray { 18858556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 18958556204SWilliam Breathitt Gray unsigned long flags; 19058556204SWilliam Breathitt Gray unsigned int ctl_state; 19158556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 19258556204SWilliam Breathitt Gray 19358556204SWilliam Breathitt Gray /* TTL/CMOS I/O */ 19458556204SWilliam Breathitt Gray if (offset > 47) { 19558556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 19658556204SWilliam Breathitt Gray 19758556204SWilliam Breathitt Gray /* Set TTL/CMOS Output Mode */ 19858556204SWilliam Breathitt Gray ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask; 19958556204SWilliam Breathitt Gray iowrite8(ctl_state, &idio24gpio->reg->ctl); 20058556204SWilliam Breathitt Gray 20158556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 20258556204SWilliam Breathitt Gray } 20358556204SWilliam Breathitt Gray 20458556204SWilliam Breathitt Gray chip->set(chip, offset, value); 20558556204SWilliam Breathitt Gray return 0; 20658556204SWilliam Breathitt Gray } 20758556204SWilliam Breathitt Gray 20858556204SWilliam Breathitt Gray static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) 20958556204SWilliam Breathitt Gray { 21058556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 21158556204SWilliam Breathitt Gray const unsigned long offset_mask = BIT(offset % 8); 21258556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 21358556204SWilliam Breathitt Gray 21458556204SWilliam Breathitt Gray /* FET Outputs */ 21558556204SWilliam Breathitt Gray if (offset < 8) 21658556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask); 21758556204SWilliam Breathitt Gray 21858556204SWilliam Breathitt Gray if (offset < 16) 21958556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask); 22058556204SWilliam Breathitt Gray 22158556204SWilliam Breathitt Gray if (offset < 24) 22258556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask); 22358556204SWilliam Breathitt Gray 22458556204SWilliam Breathitt Gray /* Isolated Inputs */ 22558556204SWilliam Breathitt Gray if (offset < 32) 22658556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask); 22758556204SWilliam Breathitt Gray 22858556204SWilliam Breathitt Gray if (offset < 40) 22958556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask); 23058556204SWilliam Breathitt Gray 23158556204SWilliam Breathitt Gray if (offset < 48) 23258556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask); 23358556204SWilliam Breathitt Gray 23458556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 23558556204SWilliam Breathitt Gray if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 23658556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask); 23758556204SWilliam Breathitt Gray 23858556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 23958556204SWilliam Breathitt Gray return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); 24058556204SWilliam Breathitt Gray } 24158556204SWilliam Breathitt Gray 242ca370815SWilliam Breathitt Gray static int idio_24_gpio_get_multiple(struct gpio_chip *chip, 243ca370815SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 244ca370815SWilliam Breathitt Gray { 245ca370815SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 246c586aa8fSWilliam Breathitt Gray unsigned long offset; 247c586aa8fSWilliam Breathitt Gray unsigned long gpio_mask; 248304440aaSWilliam Breathitt Gray void __iomem *ports[] = { 249304440aaSWilliam Breathitt Gray &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15, 250304440aaSWilliam Breathitt Gray &idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7, 251304440aaSWilliam Breathitt Gray &idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23, 252ca370815SWilliam Breathitt Gray }; 253c586aa8fSWilliam Breathitt Gray size_t index; 254c586aa8fSWilliam Breathitt Gray unsigned long port_state; 255ca370815SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 256ca370815SWilliam Breathitt Gray 257ca370815SWilliam Breathitt Gray /* clear bits array to a clean slate */ 258ca370815SWilliam Breathitt Gray bitmap_zero(bits, chip->ngpio); 259ca370815SWilliam Breathitt Gray 260c586aa8fSWilliam Breathitt Gray for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { 261c586aa8fSWilliam Breathitt Gray index = offset / 8; 262ca370815SWilliam Breathitt Gray 263ca370815SWilliam Breathitt Gray /* read bits from current gpio port (port 6 is TTL GPIO) */ 264c586aa8fSWilliam Breathitt Gray if (index < 6) 265c586aa8fSWilliam Breathitt Gray port_state = ioread8(ports[index]); 266ca370815SWilliam Breathitt Gray else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) 267ca370815SWilliam Breathitt Gray port_state = ioread8(&idio24gpio->reg->ttl_out0_7); 268ca370815SWilliam Breathitt Gray else 269ca370815SWilliam Breathitt Gray port_state = ioread8(&idio24gpio->reg->ttl_in0_7); 270ca370815SWilliam Breathitt Gray 271c586aa8fSWilliam Breathitt Gray port_state &= gpio_mask; 272c586aa8fSWilliam Breathitt Gray 273c586aa8fSWilliam Breathitt Gray bitmap_set_value8(bits, port_state, offset); 274ca370815SWilliam Breathitt Gray } 275ca370815SWilliam Breathitt Gray 276ca370815SWilliam Breathitt Gray return 0; 277ca370815SWilliam Breathitt Gray } 278ca370815SWilliam Breathitt Gray 27958556204SWilliam Breathitt Gray static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, 28058556204SWilliam Breathitt Gray int value) 28158556204SWilliam Breathitt Gray { 28258556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 28358556204SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 28458556204SWilliam Breathitt Gray void __iomem *base; 28558556204SWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 28658556204SWilliam Breathitt Gray unsigned long flags; 28758556204SWilliam Breathitt Gray unsigned int out_state; 28858556204SWilliam Breathitt Gray 28958556204SWilliam Breathitt Gray /* Isolated Inputs */ 29058556204SWilliam Breathitt Gray if (offset > 23 && offset < 48) 29158556204SWilliam Breathitt Gray return; 29258556204SWilliam Breathitt Gray 29358556204SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 29458556204SWilliam Breathitt Gray if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) 29558556204SWilliam Breathitt Gray return; 29658556204SWilliam Breathitt Gray 29758556204SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 29858556204SWilliam Breathitt Gray if (offset > 47) 29958556204SWilliam Breathitt Gray base = &idio24gpio->reg->ttl_out0_7; 30058556204SWilliam Breathitt Gray /* FET Outputs */ 30158556204SWilliam Breathitt Gray else if (offset > 15) 30258556204SWilliam Breathitt Gray base = &idio24gpio->reg->out16_23; 30358556204SWilliam Breathitt Gray else if (offset > 7) 30458556204SWilliam Breathitt Gray base = &idio24gpio->reg->out8_15; 30558556204SWilliam Breathitt Gray else 30658556204SWilliam Breathitt Gray base = &idio24gpio->reg->out0_7; 30758556204SWilliam Breathitt Gray 30858556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 30958556204SWilliam Breathitt Gray 31058556204SWilliam Breathitt Gray if (value) 31158556204SWilliam Breathitt Gray out_state = ioread8(base) | mask; 31258556204SWilliam Breathitt Gray else 31358556204SWilliam Breathitt Gray out_state = ioread8(base) & ~mask; 31458556204SWilliam Breathitt Gray 31558556204SWilliam Breathitt Gray iowrite8(out_state, base); 31658556204SWilliam Breathitt Gray 31758556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 31858556204SWilliam Breathitt Gray } 31958556204SWilliam Breathitt Gray 320ca370815SWilliam Breathitt Gray static void idio_24_gpio_set_multiple(struct gpio_chip *chip, 321ca370815SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 322ca370815SWilliam Breathitt Gray { 323ca370815SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 324c586aa8fSWilliam Breathitt Gray unsigned long offset; 325ca370815SWilliam Breathitt Gray unsigned long gpio_mask; 326304440aaSWilliam Breathitt Gray void __iomem *ports[] = { 327304440aaSWilliam Breathitt Gray &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15, 328304440aaSWilliam Breathitt Gray &idio24gpio->reg->out16_23 329ca370815SWilliam Breathitt Gray }; 330c586aa8fSWilliam Breathitt Gray size_t index; 331c586aa8fSWilliam Breathitt Gray unsigned long bitmask; 332c586aa8fSWilliam Breathitt Gray unsigned long flags; 333c586aa8fSWilliam Breathitt Gray unsigned long out_state; 334ca370815SWilliam Breathitt Gray const unsigned long out_mode_mask = BIT(1); 335ca370815SWilliam Breathitt Gray 336c586aa8fSWilliam Breathitt Gray for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { 337c586aa8fSWilliam Breathitt Gray index = offset / 8; 338ca370815SWilliam Breathitt Gray 339c586aa8fSWilliam Breathitt Gray bitmask = bitmap_get_value8(bits, offset) & gpio_mask; 340c586aa8fSWilliam Breathitt Gray 341c586aa8fSWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 342c586aa8fSWilliam Breathitt Gray 343c586aa8fSWilliam Breathitt Gray /* read bits from current gpio port (port 6 is TTL GPIO) */ 344c586aa8fSWilliam Breathitt Gray if (index < 6) { 345c586aa8fSWilliam Breathitt Gray out_state = ioread8(ports[index]); 346c586aa8fSWilliam Breathitt Gray } else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) { 347c586aa8fSWilliam Breathitt Gray out_state = ioread8(&idio24gpio->reg->ttl_out0_7); 348c586aa8fSWilliam Breathitt Gray } else { 349c586aa8fSWilliam Breathitt Gray /* skip TTL GPIO if set for input */ 350c586aa8fSWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 351ca370815SWilliam Breathitt Gray continue; 352ca370815SWilliam Breathitt Gray } 353ca370815SWilliam Breathitt Gray 354c586aa8fSWilliam Breathitt Gray /* set requested bit states */ 355c586aa8fSWilliam Breathitt Gray out_state &= ~gpio_mask; 356c586aa8fSWilliam Breathitt Gray out_state |= bitmask; 357ca370815SWilliam Breathitt Gray 358c586aa8fSWilliam Breathitt Gray /* write bits for current gpio port (port 6 is TTL GPIO) */ 359c586aa8fSWilliam Breathitt Gray if (index < 6) 360c586aa8fSWilliam Breathitt Gray iowrite8(out_state, ports[index]); 361c586aa8fSWilliam Breathitt Gray else 362ca370815SWilliam Breathitt Gray iowrite8(out_state, &idio24gpio->reg->ttl_out0_7); 363ca370815SWilliam Breathitt Gray 364ca370815SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 365ca370815SWilliam Breathitt Gray } 366c586aa8fSWilliam Breathitt Gray } 367ca370815SWilliam Breathitt Gray 36858556204SWilliam Breathitt Gray static void idio_24_irq_ack(struct irq_data *data) 36958556204SWilliam Breathitt Gray { 37058556204SWilliam Breathitt Gray } 37158556204SWilliam Breathitt Gray 37258556204SWilliam Breathitt Gray static void idio_24_irq_mask(struct irq_data *data) 37358556204SWilliam Breathitt Gray { 37458556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 37558556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 37658556204SWilliam Breathitt Gray unsigned long flags; 37758556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 37858556204SWilliam Breathitt Gray unsigned char new_irq_mask; 37923a7fdc0SArnaud de Turckheim const unsigned long bank_offset = bit_offset / 8; 38058556204SWilliam Breathitt Gray unsigned char cos_enable_state; 38158556204SWilliam Breathitt Gray 38258556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 38358556204SWilliam Breathitt Gray 384d8f270efSArnaud de Turckheim idio24gpio->irq_mask &= ~BIT(bit_offset); 38523a7fdc0SArnaud de Turckheim new_irq_mask = idio24gpio->irq_mask >> bank_offset * 8; 38658556204SWilliam Breathitt Gray 38758556204SWilliam Breathitt Gray if (!new_irq_mask) { 38858556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 38958556204SWilliam Breathitt Gray 39058556204SWilliam Breathitt Gray /* Disable Rising Edge detection */ 39158556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset); 39258556204SWilliam Breathitt Gray /* Disable Falling Edge detection */ 39358556204SWilliam Breathitt Gray cos_enable_state &= ~BIT(bank_offset + 4); 39458556204SWilliam Breathitt Gray 39558556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 39658556204SWilliam Breathitt Gray } 39758556204SWilliam Breathitt Gray 39858556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 39958556204SWilliam Breathitt Gray } 40058556204SWilliam Breathitt Gray 40158556204SWilliam Breathitt Gray static void idio_24_irq_unmask(struct irq_data *data) 40258556204SWilliam Breathitt Gray { 40358556204SWilliam Breathitt Gray struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); 40458556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); 40558556204SWilliam Breathitt Gray unsigned long flags; 40658556204SWilliam Breathitt Gray unsigned char prev_irq_mask; 40758556204SWilliam Breathitt Gray const unsigned long bit_offset = irqd_to_hwirq(data) - 24; 40823a7fdc0SArnaud de Turckheim const unsigned long bank_offset = bit_offset / 8; 40958556204SWilliam Breathitt Gray unsigned char cos_enable_state; 41058556204SWilliam Breathitt Gray 41158556204SWilliam Breathitt Gray raw_spin_lock_irqsave(&idio24gpio->lock, flags); 41258556204SWilliam Breathitt Gray 41323a7fdc0SArnaud de Turckheim prev_irq_mask = idio24gpio->irq_mask >> bank_offset * 8; 41458556204SWilliam Breathitt Gray idio24gpio->irq_mask |= BIT(bit_offset); 41558556204SWilliam Breathitt Gray 41658556204SWilliam Breathitt Gray if (!prev_irq_mask) { 41758556204SWilliam Breathitt Gray cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); 41858556204SWilliam Breathitt Gray 41958556204SWilliam Breathitt Gray /* Enable Rising Edge detection */ 42058556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset); 42158556204SWilliam Breathitt Gray /* Enable Falling Edge detection */ 42258556204SWilliam Breathitt Gray cos_enable_state |= BIT(bank_offset + 4); 42358556204SWilliam Breathitt Gray 42458556204SWilliam Breathitt Gray iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); 42558556204SWilliam Breathitt Gray } 42658556204SWilliam Breathitt Gray 42758556204SWilliam Breathitt Gray raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); 42858556204SWilliam Breathitt Gray } 42958556204SWilliam Breathitt Gray 43058556204SWilliam Breathitt Gray static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) 43158556204SWilliam Breathitt Gray { 43258556204SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 43358556204SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 43458556204SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 43558556204SWilliam Breathitt Gray return -EINVAL; 43658556204SWilliam Breathitt Gray 43758556204SWilliam Breathitt Gray return 0; 43858556204SWilliam Breathitt Gray } 43958556204SWilliam Breathitt Gray 44058556204SWilliam Breathitt Gray static struct irq_chip idio_24_irqchip = { 44158556204SWilliam Breathitt Gray .name = "pcie-idio-24", 44258556204SWilliam Breathitt Gray .irq_ack = idio_24_irq_ack, 44358556204SWilliam Breathitt Gray .irq_mask = idio_24_irq_mask, 44458556204SWilliam Breathitt Gray .irq_unmask = idio_24_irq_unmask, 44558556204SWilliam Breathitt Gray .irq_set_type = idio_24_irq_set_type 44658556204SWilliam Breathitt Gray }; 44758556204SWilliam Breathitt Gray 44858556204SWilliam Breathitt Gray static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) 44958556204SWilliam Breathitt Gray { 45058556204SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = dev_id; 45158556204SWilliam Breathitt Gray unsigned long irq_status; 45258556204SWilliam Breathitt Gray struct gpio_chip *const chip = &idio24gpio->chip; 45358556204SWilliam Breathitt Gray unsigned long irq_mask; 45458556204SWilliam Breathitt Gray int gpio; 45558556204SWilliam Breathitt Gray 45658556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 45758556204SWilliam Breathitt Gray 45858556204SWilliam Breathitt Gray /* Read Change-Of-State status */ 45958556204SWilliam Breathitt Gray irq_status = ioread32(&idio24gpio->reg->cos0_7); 46058556204SWilliam Breathitt Gray 46158556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 46258556204SWilliam Breathitt Gray 46358556204SWilliam Breathitt Gray /* Make sure our device generated IRQ */ 46458556204SWilliam Breathitt Gray if (!irq_status) 46558556204SWilliam Breathitt Gray return IRQ_NONE; 46658556204SWilliam Breathitt Gray 46758556204SWilliam Breathitt Gray /* Handle only unmasked IRQ */ 46858556204SWilliam Breathitt Gray irq_mask = idio24gpio->irq_mask & irq_status; 46958556204SWilliam Breathitt Gray 47058556204SWilliam Breathitt Gray for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24) 47158556204SWilliam Breathitt Gray generic_handle_irq(irq_find_mapping(chip->irq.domain, 47258556204SWilliam Breathitt Gray gpio + 24)); 47358556204SWilliam Breathitt Gray 47458556204SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 47558556204SWilliam Breathitt Gray 47658556204SWilliam Breathitt Gray /* Clear Change-Of-State status */ 47758556204SWilliam Breathitt Gray iowrite32(irq_status, &idio24gpio->reg->cos0_7); 47858556204SWilliam Breathitt Gray 47958556204SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 48058556204SWilliam Breathitt Gray 48158556204SWilliam Breathitt Gray return IRQ_HANDLED; 48258556204SWilliam Breathitt Gray } 48358556204SWilliam Breathitt Gray 48458556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56 48558556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = { 48658556204SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 48758556204SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 48858556204SWilliam Breathitt Gray "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", 48958556204SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 49058556204SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", 49158556204SWilliam Breathitt Gray "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", 49258556204SWilliam Breathitt Gray "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" 49358556204SWilliam Breathitt Gray }; 49458556204SWilliam Breathitt Gray 49558556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) 49658556204SWilliam Breathitt Gray { 49758556204SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 49858556204SWilliam Breathitt Gray struct idio_24_gpio *idio24gpio; 49958556204SWilliam Breathitt Gray int err; 500*10a2f11dSArnaud de Turckheim const size_t pci_plx_bar_index = 1; 50158556204SWilliam Breathitt Gray const size_t pci_bar_index = 2; 50258556204SWilliam Breathitt Gray const char *const name = pci_name(pdev); 503866e863eSLinus Walleij struct gpio_irq_chip *girq; 50458556204SWilliam Breathitt Gray 50558556204SWilliam Breathitt Gray idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); 50658556204SWilliam Breathitt Gray if (!idio24gpio) 50758556204SWilliam Breathitt Gray return -ENOMEM; 50858556204SWilliam Breathitt Gray 50958556204SWilliam Breathitt Gray err = pcim_enable_device(pdev); 51058556204SWilliam Breathitt Gray if (err) { 51158556204SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 51258556204SWilliam Breathitt Gray return err; 51358556204SWilliam Breathitt Gray } 51458556204SWilliam Breathitt Gray 515*10a2f11dSArnaud de Turckheim err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name); 51658556204SWilliam Breathitt Gray if (err) { 51758556204SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 51858556204SWilliam Breathitt Gray return err; 51958556204SWilliam Breathitt Gray } 52058556204SWilliam Breathitt Gray 521*10a2f11dSArnaud de Turckheim idio24gpio->plx = pcim_iomap_table(pdev)[pci_plx_bar_index]; 52258556204SWilliam Breathitt Gray idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; 52358556204SWilliam Breathitt Gray 52458556204SWilliam Breathitt Gray idio24gpio->chip.label = name; 52558556204SWilliam Breathitt Gray idio24gpio->chip.parent = dev; 52658556204SWilliam Breathitt Gray idio24gpio->chip.owner = THIS_MODULE; 52758556204SWilliam Breathitt Gray idio24gpio->chip.base = -1; 52858556204SWilliam Breathitt Gray idio24gpio->chip.ngpio = IDIO_24_NGPIO; 52958556204SWilliam Breathitt Gray idio24gpio->chip.names = idio_24_names; 53058556204SWilliam Breathitt Gray idio24gpio->chip.get_direction = idio_24_gpio_get_direction; 53158556204SWilliam Breathitt Gray idio24gpio->chip.direction_input = idio_24_gpio_direction_input; 53258556204SWilliam Breathitt Gray idio24gpio->chip.direction_output = idio_24_gpio_direction_output; 53358556204SWilliam Breathitt Gray idio24gpio->chip.get = idio_24_gpio_get; 534ca370815SWilliam Breathitt Gray idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple; 53558556204SWilliam Breathitt Gray idio24gpio->chip.set = idio_24_gpio_set; 536ca370815SWilliam Breathitt Gray idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple; 53758556204SWilliam Breathitt Gray 538866e863eSLinus Walleij girq = &idio24gpio->chip.irq; 539866e863eSLinus Walleij girq->chip = &idio_24_irqchip; 540866e863eSLinus Walleij /* This will let us handle the parent IRQ in the driver */ 541866e863eSLinus Walleij girq->parent_handler = NULL; 542866e863eSLinus Walleij girq->num_parents = 0; 543866e863eSLinus Walleij girq->parents = NULL; 544866e863eSLinus Walleij girq->default_type = IRQ_TYPE_NONE; 545866e863eSLinus Walleij girq->handler = handle_edge_irq; 546866e863eSLinus Walleij 54758556204SWilliam Breathitt Gray raw_spin_lock_init(&idio24gpio->lock); 54858556204SWilliam Breathitt Gray 54958556204SWilliam Breathitt Gray /* Software board reset */ 55058556204SWilliam Breathitt Gray iowrite8(0, &idio24gpio->reg->soft_reset); 551*10a2f11dSArnaud de Turckheim /* 552*10a2f11dSArnaud de Turckheim * enable PLX PEX8311 internal PCI wire interrupt and local interrupt 553*10a2f11dSArnaud de Turckheim * input 554*10a2f11dSArnaud de Turckheim */ 555*10a2f11dSArnaud de Turckheim iowrite8((INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT) >> 8, 556*10a2f11dSArnaud de Turckheim idio24gpio->plx + PLX_PEX8311_PCI_LCS_INTCSR + 1); 55758556204SWilliam Breathitt Gray 55858556204SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio); 55958556204SWilliam Breathitt Gray if (err) { 56058556204SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 56158556204SWilliam Breathitt Gray return err; 56258556204SWilliam Breathitt Gray } 56358556204SWilliam Breathitt Gray 56458556204SWilliam Breathitt Gray err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED, 56558556204SWilliam Breathitt Gray name, idio24gpio); 56658556204SWilliam Breathitt Gray if (err) { 56758556204SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 56858556204SWilliam Breathitt Gray return err; 56958556204SWilliam Breathitt Gray } 57058556204SWilliam Breathitt Gray 57158556204SWilliam Breathitt Gray return 0; 57258556204SWilliam Breathitt Gray } 57358556204SWilliam Breathitt Gray 57458556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = { 57558556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, 57658556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, 57758556204SWilliam Breathitt Gray { 0 } 57858556204SWilliam Breathitt Gray }; 57958556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); 58058556204SWilliam Breathitt Gray 58158556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = { 58258556204SWilliam Breathitt Gray .name = "pcie-idio-24", 58358556204SWilliam Breathitt Gray .id_table = idio_24_pci_dev_id, 58458556204SWilliam Breathitt Gray .probe = idio_24_probe 58558556204SWilliam Breathitt Gray }; 58658556204SWilliam Breathitt Gray 58758556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver); 58858556204SWilliam Breathitt Gray 58958556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 59058556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); 59158556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 592