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 driver supports the following ACCES devices: PCIe-IDIO-24, 758556204SWilliam Breathitt Gray * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. 858556204SWilliam Breathitt Gray */ 9*1a200a39SWilliam Breathitt Gray #include <linux/bits.h> 1058556204SWilliam Breathitt Gray #include <linux/device.h> 11*1a200a39SWilliam Breathitt Gray #include <linux/err.h> 12*1a200a39SWilliam Breathitt Gray #include <linux/gpio/regmap.h> 13*1a200a39SWilliam Breathitt Gray #include <linux/irq.h> 1458556204SWilliam Breathitt Gray #include <linux/kernel.h> 1558556204SWilliam Breathitt Gray #include <linux/module.h> 1658556204SWilliam Breathitt Gray #include <linux/pci.h> 17*1a200a39SWilliam Breathitt Gray #include <linux/regmap.h> 1858556204SWilliam Breathitt Gray #include <linux/spinlock.h> 1958556204SWilliam Breathitt Gray #include <linux/types.h> 2058556204SWilliam Breathitt Gray 2110a2f11dSArnaud de Turckheim /* 2210a2f11dSArnaud de Turckheim * PLX PEX8311 PCI LCS_INTCSR Interrupt Control/Status 2310a2f11dSArnaud de Turckheim * 2410a2f11dSArnaud de Turckheim * Bit: Description 2510a2f11dSArnaud de Turckheim * 0: Enable Interrupt Sources (Bit 0) 2610a2f11dSArnaud de Turckheim * 1: Enable Interrupt Sources (Bit 1) 2710a2f11dSArnaud de Turckheim * 2: Generate Internal PCI Bus Internal SERR# Interrupt 2810a2f11dSArnaud de Turckheim * 3: Mailbox Interrupt Enable 2910a2f11dSArnaud de Turckheim * 4: Power Management Interrupt Enable 3010a2f11dSArnaud de Turckheim * 5: Power Management Interrupt 3110a2f11dSArnaud de Turckheim * 6: Slave Read Local Data Parity Check Error Enable 3210a2f11dSArnaud de Turckheim * 7: Slave Read Local Data Parity Check Error Status 3310a2f11dSArnaud de Turckheim * 8: Internal PCI Wire Interrupt Enable 3410a2f11dSArnaud de Turckheim * 9: PCI Express Doorbell Interrupt Enable 3510a2f11dSArnaud de Turckheim * 10: PCI Abort Interrupt Enable 3610a2f11dSArnaud de Turckheim * 11: Local Interrupt Input Enable 3710a2f11dSArnaud de Turckheim * 12: Retry Abort Enable 3810a2f11dSArnaud de Turckheim * 13: PCI Express Doorbell Interrupt Active 3910a2f11dSArnaud de Turckheim * 14: PCI Abort Interrupt Active 4010a2f11dSArnaud de Turckheim * 15: Local Interrupt Input Active 4110a2f11dSArnaud de Turckheim * 16: Local Interrupt Output Enable 4210a2f11dSArnaud de Turckheim * 17: Local Doorbell Interrupt Enable 4310a2f11dSArnaud de Turckheim * 18: DMA Channel 0 Interrupt Enable 4410a2f11dSArnaud de Turckheim * 19: DMA Channel 1 Interrupt Enable 4510a2f11dSArnaud de Turckheim * 20: Local Doorbell Interrupt Active 4610a2f11dSArnaud de Turckheim * 21: DMA Channel 0 Interrupt Active 4710a2f11dSArnaud de Turckheim * 22: DMA Channel 1 Interrupt Active 4810a2f11dSArnaud de Turckheim * 23: Built-In Self-Test (BIST) Interrupt Active 4910a2f11dSArnaud de Turckheim * 24: Direct Master was the Bus Master during a Master or Target Abort 5010a2f11dSArnaud de Turckheim * 25: DMA Channel 0 was the Bus Master during a Master or Target Abort 5110a2f11dSArnaud de Turckheim * 26: DMA Channel 1 was the Bus Master during a Master or Target Abort 5210a2f11dSArnaud de Turckheim * 27: Target Abort after internal 256 consecutive Master Retrys 5310a2f11dSArnaud de Turckheim * 28: PCI Bus wrote data to LCS_MBOX0 5410a2f11dSArnaud de Turckheim * 29: PCI Bus wrote data to LCS_MBOX1 5510a2f11dSArnaud de Turckheim * 30: PCI Bus wrote data to LCS_MBOX2 5610a2f11dSArnaud de Turckheim * 31: PCI Bus wrote data to LCS_MBOX3 5710a2f11dSArnaud de Turckheim */ 5810a2f11dSArnaud de Turckheim #define PLX_PEX8311_PCI_LCS_INTCSR 0x68 5910a2f11dSArnaud de Turckheim #define INTCSR_INTERNAL_PCI_WIRE BIT(8) 6010a2f11dSArnaud de Turckheim #define INTCSR_LOCAL_INPUT BIT(11) 61*1a200a39SWilliam Breathitt Gray #define IDIO_24_ENABLE_IRQ (INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT) 6210a2f11dSArnaud de Turckheim 63*1a200a39SWilliam Breathitt Gray #define IDIO_24_OUT_BASE 0x0 64*1a200a39SWilliam Breathitt Gray #define IDIO_24_TTLCMOS_OUT_REG 0x3 65*1a200a39SWilliam Breathitt Gray #define IDIO_24_IN_BASE 0x4 66*1a200a39SWilliam Breathitt Gray #define IDIO_24_TTLCMOS_IN_REG 0x7 67*1a200a39SWilliam Breathitt Gray #define IDIO_24_COS_STATUS_BASE 0x8 68*1a200a39SWilliam Breathitt Gray #define IDIO_24_CONTROL_REG 0xC 69*1a200a39SWilliam Breathitt Gray #define IDIO_24_COS_ENABLE 0xE 70*1a200a39SWilliam Breathitt Gray #define IDIO_24_SOFT_RESET 0xF 71*1a200a39SWilliam Breathitt Gray 72*1a200a39SWilliam Breathitt Gray #define CONTROL_REG_OUT_MODE BIT(1) 73*1a200a39SWilliam Breathitt Gray 74*1a200a39SWilliam Breathitt Gray #define COS_ENABLE_RISING BIT(1) 75*1a200a39SWilliam Breathitt Gray #define COS_ENABLE_FALLING BIT(4) 76*1a200a39SWilliam Breathitt Gray #define COS_ENABLE_BOTH (COS_ENABLE_RISING | COS_ENABLE_FALLING) 77*1a200a39SWilliam Breathitt Gray 78*1a200a39SWilliam Breathitt Gray static const struct regmap_config pex8311_intcsr_regmap_config = { 79*1a200a39SWilliam Breathitt Gray .name = "pex8311_intcsr", 80*1a200a39SWilliam Breathitt Gray .reg_bits = 32, 81*1a200a39SWilliam Breathitt Gray .reg_stride = 1, 82*1a200a39SWilliam Breathitt Gray .reg_base = PLX_PEX8311_PCI_LCS_INTCSR, 83*1a200a39SWilliam Breathitt Gray .val_bits = 32, 84*1a200a39SWilliam Breathitt Gray .io_port = true, 85*1a200a39SWilliam Breathitt Gray }; 86*1a200a39SWilliam Breathitt Gray 87*1a200a39SWilliam Breathitt Gray static const struct regmap_range idio_24_wr_ranges[] = { 88*1a200a39SWilliam Breathitt Gray regmap_reg_range(0x0, 0x3), regmap_reg_range(0x8, 0xC), 89*1a200a39SWilliam Breathitt Gray regmap_reg_range(0xE, 0xF), 90*1a200a39SWilliam Breathitt Gray }; 91*1a200a39SWilliam Breathitt Gray static const struct regmap_range idio_24_rd_ranges[] = { 92*1a200a39SWilliam Breathitt Gray regmap_reg_range(0x0, 0xC), regmap_reg_range(0xE, 0xF), 93*1a200a39SWilliam Breathitt Gray }; 94*1a200a39SWilliam Breathitt Gray static const struct regmap_range idio_24_volatile_ranges[] = { 95*1a200a39SWilliam Breathitt Gray regmap_reg_range(0x4, 0xB), regmap_reg_range(0xF, 0xF), 96*1a200a39SWilliam Breathitt Gray }; 97*1a200a39SWilliam Breathitt Gray static const struct regmap_access_table idio_24_wr_table = { 98*1a200a39SWilliam Breathitt Gray .yes_ranges = idio_24_wr_ranges, 99*1a200a39SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(idio_24_wr_ranges), 100*1a200a39SWilliam Breathitt Gray }; 101*1a200a39SWilliam Breathitt Gray static const struct regmap_access_table idio_24_rd_table = { 102*1a200a39SWilliam Breathitt Gray .yes_ranges = idio_24_rd_ranges, 103*1a200a39SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(idio_24_rd_ranges), 104*1a200a39SWilliam Breathitt Gray }; 105*1a200a39SWilliam Breathitt Gray static const struct regmap_access_table idio_24_volatile_table = { 106*1a200a39SWilliam Breathitt Gray .yes_ranges = idio_24_volatile_ranges, 107*1a200a39SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(idio_24_volatile_ranges), 108*1a200a39SWilliam Breathitt Gray }; 109*1a200a39SWilliam Breathitt Gray 110*1a200a39SWilliam Breathitt Gray static const struct regmap_config idio_24_regmap_config = { 111*1a200a39SWilliam Breathitt Gray .reg_bits = 8, 112*1a200a39SWilliam Breathitt Gray .reg_stride = 1, 113*1a200a39SWilliam Breathitt Gray .val_bits = 8, 114*1a200a39SWilliam Breathitt Gray .io_port = true, 115*1a200a39SWilliam Breathitt Gray .wr_table = &idio_24_wr_table, 116*1a200a39SWilliam Breathitt Gray .rd_table = &idio_24_rd_table, 117*1a200a39SWilliam Breathitt Gray .volatile_table = &idio_24_volatile_table, 118*1a200a39SWilliam Breathitt Gray .cache_type = REGCACHE_FLAT, 119*1a200a39SWilliam Breathitt Gray .use_raw_spinlock = true, 120*1a200a39SWilliam Breathitt Gray }; 121*1a200a39SWilliam Breathitt Gray 122*1a200a39SWilliam Breathitt Gray #define IDIO_24_NGPIO_PER_REG 8 123*1a200a39SWilliam Breathitt Gray #define IDIO_24_REGMAP_IRQ(_id) \ 124*1a200a39SWilliam Breathitt Gray [24 + _id] = { \ 125*1a200a39SWilliam Breathitt Gray .reg_offset = (_id) / IDIO_24_NGPIO_PER_REG, \ 126*1a200a39SWilliam Breathitt Gray .mask = BIT((_id) % IDIO_24_NGPIO_PER_REG), \ 127*1a200a39SWilliam Breathitt Gray .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \ 128*1a200a39SWilliam Breathitt Gray } 129*1a200a39SWilliam Breathitt Gray #define IDIO_24_IIN_IRQ(_id) IDIO_24_REGMAP_IRQ(_id) 130*1a200a39SWilliam Breathitt Gray #define IDIO_24_TTL_IRQ(_id) IDIO_24_REGMAP_IRQ(24 + _id) 131*1a200a39SWilliam Breathitt Gray 132*1a200a39SWilliam Breathitt Gray static const struct regmap_irq idio_24_regmap_irqs[] = { 133*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(0), IDIO_24_IIN_IRQ(1), IDIO_24_IIN_IRQ(2), /* IIN 0-2 */ 134*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(3), IDIO_24_IIN_IRQ(4), IDIO_24_IIN_IRQ(5), /* IIN 3-5 */ 135*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(6), IDIO_24_IIN_IRQ(7), IDIO_24_IIN_IRQ(8), /* IIN 6-8 */ 136*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(9), IDIO_24_IIN_IRQ(10), IDIO_24_IIN_IRQ(11), /* IIN 9-11 */ 137*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(12), IDIO_24_IIN_IRQ(13), IDIO_24_IIN_IRQ(14), /* IIN 12-14 */ 138*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(15), IDIO_24_IIN_IRQ(16), IDIO_24_IIN_IRQ(17), /* IIN 15-17 */ 139*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(18), IDIO_24_IIN_IRQ(19), IDIO_24_IIN_IRQ(20), /* IIN 18-20 */ 140*1a200a39SWilliam Breathitt Gray IDIO_24_IIN_IRQ(21), IDIO_24_IIN_IRQ(22), IDIO_24_IIN_IRQ(23), /* IIN 21-23 */ 141*1a200a39SWilliam Breathitt Gray IDIO_24_TTL_IRQ(0), IDIO_24_TTL_IRQ(1), IDIO_24_TTL_IRQ(2), /* TTL 0-2 */ 142*1a200a39SWilliam Breathitt Gray IDIO_24_TTL_IRQ(3), IDIO_24_TTL_IRQ(4), IDIO_24_TTL_IRQ(5), /* TTL 3-5 */ 143*1a200a39SWilliam Breathitt Gray IDIO_24_TTL_IRQ(6), IDIO_24_TTL_IRQ(7), /* TTL 6-7 */ 14458556204SWilliam Breathitt Gray }; 14558556204SWilliam Breathitt Gray 14658556204SWilliam Breathitt Gray /** 14758556204SWilliam Breathitt Gray * struct idio_24_gpio - GPIO device private data structure 148*1a200a39SWilliam Breathitt Gray * @map: regmap for the device 14958556204SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 150*1a200a39SWilliam Breathitt Gray * @irq_type: type configuration for IRQs 15158556204SWilliam Breathitt Gray */ 15258556204SWilliam Breathitt Gray struct idio_24_gpio { 153*1a200a39SWilliam Breathitt Gray struct regmap *map; 15458556204SWilliam Breathitt Gray raw_spinlock_t lock; 155*1a200a39SWilliam Breathitt Gray u8 irq_type; 15658556204SWilliam Breathitt Gray }; 15758556204SWilliam Breathitt Gray 158*1a200a39SWilliam Breathitt Gray static int idio_24_handle_mask_sync(const int index, const unsigned int mask_buf_def, 159*1a200a39SWilliam Breathitt Gray const unsigned int mask_buf, void *const irq_drv_data) 16058556204SWilliam Breathitt Gray { 161*1a200a39SWilliam Breathitt Gray const unsigned int type_mask = COS_ENABLE_BOTH << index; 162*1a200a39SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = irq_drv_data; 163*1a200a39SWilliam Breathitt Gray u8 type; 164*1a200a39SWilliam Breathitt Gray int ret; 16558556204SWilliam Breathitt Gray 166*1a200a39SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 16758556204SWilliam Breathitt Gray 168*1a200a39SWilliam Breathitt Gray /* if all are masked, then disable interrupts, else set to type */ 169*1a200a39SWilliam Breathitt Gray type = (mask_buf == mask_buf_def) ? ~type_mask : idio24gpio->irq_type; 17058556204SWilliam Breathitt Gray 171*1a200a39SWilliam Breathitt Gray ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, type_mask, type); 172e42615ecSMatti Vaittinen 173*1a200a39SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 174*1a200a39SWilliam Breathitt Gray 175*1a200a39SWilliam Breathitt Gray return ret; 17658556204SWilliam Breathitt Gray } 17758556204SWilliam Breathitt Gray 178*1a200a39SWilliam Breathitt Gray static int idio_24_set_type_config(unsigned int **const buf, const unsigned int type, 179*1a200a39SWilliam Breathitt Gray const struct regmap_irq *const irq_data, const int idx, 180*1a200a39SWilliam Breathitt Gray void *const irq_drv_data) 18158556204SWilliam Breathitt Gray { 182*1a200a39SWilliam Breathitt Gray const unsigned int offset = irq_data->reg_offset; 183*1a200a39SWilliam Breathitt Gray const unsigned int rising = COS_ENABLE_RISING << offset; 184*1a200a39SWilliam Breathitt Gray const unsigned int falling = COS_ENABLE_FALLING << offset; 185*1a200a39SWilliam Breathitt Gray const unsigned int mask = COS_ENABLE_BOTH << offset; 186*1a200a39SWilliam Breathitt Gray struct idio_24_gpio *const idio24gpio = irq_drv_data; 187*1a200a39SWilliam Breathitt Gray unsigned int new; 188*1a200a39SWilliam Breathitt Gray unsigned int cos_enable; 189*1a200a39SWilliam Breathitt Gray int ret; 19058556204SWilliam Breathitt Gray 191*1a200a39SWilliam Breathitt Gray switch (type) { 192*1a200a39SWilliam Breathitt Gray case IRQ_TYPE_EDGE_RISING: 193*1a200a39SWilliam Breathitt Gray new = rising; 194*1a200a39SWilliam Breathitt Gray break; 195*1a200a39SWilliam Breathitt Gray case IRQ_TYPE_EDGE_FALLING: 196*1a200a39SWilliam Breathitt Gray new = falling; 197*1a200a39SWilliam Breathitt Gray break; 198*1a200a39SWilliam Breathitt Gray case IRQ_TYPE_EDGE_BOTH: 199*1a200a39SWilliam Breathitt Gray new = mask; 200*1a200a39SWilliam Breathitt Gray break; 201*1a200a39SWilliam Breathitt Gray default: 20258556204SWilliam Breathitt Gray return -EINVAL; 203*1a200a39SWilliam Breathitt Gray } 20458556204SWilliam Breathitt Gray 205*1a200a39SWilliam Breathitt Gray raw_spin_lock(&idio24gpio->lock); 206*1a200a39SWilliam Breathitt Gray 207*1a200a39SWilliam Breathitt Gray /* replace old bitmap with new bitmap */ 208*1a200a39SWilliam Breathitt Gray idio24gpio->irq_type = (idio24gpio->irq_type & ~mask) | (new & mask); 209*1a200a39SWilliam Breathitt Gray 210*1a200a39SWilliam Breathitt Gray ret = regmap_read(idio24gpio->map, IDIO_24_COS_ENABLE, &cos_enable); 211*1a200a39SWilliam Breathitt Gray if (ret) 212*1a200a39SWilliam Breathitt Gray goto exit_unlock; 213*1a200a39SWilliam Breathitt Gray 214*1a200a39SWilliam Breathitt Gray /* if COS is currently enabled then update the edge type */ 215*1a200a39SWilliam Breathitt Gray if (cos_enable & mask) { 216*1a200a39SWilliam Breathitt Gray ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, mask, 217*1a200a39SWilliam Breathitt Gray idio24gpio->irq_type); 218*1a200a39SWilliam Breathitt Gray if (ret) 219*1a200a39SWilliam Breathitt Gray goto exit_unlock; 220*1a200a39SWilliam Breathitt Gray } 221*1a200a39SWilliam Breathitt Gray 222*1a200a39SWilliam Breathitt Gray exit_unlock: 223*1a200a39SWilliam Breathitt Gray raw_spin_unlock(&idio24gpio->lock); 224*1a200a39SWilliam Breathitt Gray 225*1a200a39SWilliam Breathitt Gray return ret; 226*1a200a39SWilliam Breathitt Gray } 227*1a200a39SWilliam Breathitt Gray 228*1a200a39SWilliam Breathitt Gray static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base, 229*1a200a39SWilliam Breathitt Gray const unsigned int offset, unsigned int *const reg, 230*1a200a39SWilliam Breathitt Gray unsigned int *const mask) 231*1a200a39SWilliam Breathitt Gray { 232*1a200a39SWilliam Breathitt Gray const unsigned int out_stride = offset / IDIO_24_NGPIO_PER_REG; 233*1a200a39SWilliam Breathitt Gray const unsigned int in_stride = (offset - 24) / IDIO_24_NGPIO_PER_REG; 234*1a200a39SWilliam Breathitt Gray struct regmap *const map = gpio_regmap_get_drvdata(gpio); 235*1a200a39SWilliam Breathitt Gray int err; 236*1a200a39SWilliam Breathitt Gray unsigned int ctrl_reg; 237*1a200a39SWilliam Breathitt Gray 238*1a200a39SWilliam Breathitt Gray switch (base) { 239*1a200a39SWilliam Breathitt Gray case IDIO_24_OUT_BASE: 240*1a200a39SWilliam Breathitt Gray *mask = BIT(offset % IDIO_24_NGPIO_PER_REG); 241*1a200a39SWilliam Breathitt Gray 242*1a200a39SWilliam Breathitt Gray /* FET Outputs */ 243*1a200a39SWilliam Breathitt Gray if (offset < 24) { 244*1a200a39SWilliam Breathitt Gray *reg = IDIO_24_OUT_BASE + out_stride; 24558556204SWilliam Breathitt Gray return 0; 24658556204SWilliam Breathitt Gray } 24758556204SWilliam Breathitt Gray 248*1a200a39SWilliam Breathitt Gray /* Isolated Inputs */ 249*1a200a39SWilliam Breathitt Gray if (offset < 48) { 250*1a200a39SWilliam Breathitt Gray *reg = IDIO_24_IN_BASE + in_stride; 251*1a200a39SWilliam Breathitt Gray return 0; 252*1a200a39SWilliam Breathitt Gray } 25358556204SWilliam Breathitt Gray 254*1a200a39SWilliam Breathitt Gray err = regmap_read(map, IDIO_24_CONTROL_REG, &ctrl_reg); 255*1a200a39SWilliam Breathitt Gray if (err) 256*1a200a39SWilliam Breathitt Gray return err; 25758556204SWilliam Breathitt Gray 258*1a200a39SWilliam Breathitt Gray /* TTL/CMOS Outputs */ 259*1a200a39SWilliam Breathitt Gray if (ctrl_reg & CONTROL_REG_OUT_MODE) { 260*1a200a39SWilliam Breathitt Gray *reg = IDIO_24_TTLCMOS_OUT_REG; 261*1a200a39SWilliam Breathitt Gray return 0; 262*1a200a39SWilliam Breathitt Gray } 26358556204SWilliam Breathitt Gray 264*1a200a39SWilliam Breathitt Gray /* TTL/CMOS Inputs */ 265*1a200a39SWilliam Breathitt Gray *reg = IDIO_24_TTLCMOS_IN_REG; 266*1a200a39SWilliam Breathitt Gray return 0; 267*1a200a39SWilliam Breathitt Gray case IDIO_24_CONTROL_REG: 268*1a200a39SWilliam Breathitt Gray /* We can only set direction for TTL/CMOS lines */ 269*1a200a39SWilliam Breathitt Gray if (offset < 48) 270*1a200a39SWilliam Breathitt Gray return -EOPNOTSUPP; 27158556204SWilliam Breathitt Gray 272*1a200a39SWilliam Breathitt Gray *reg = IDIO_24_CONTROL_REG; 273*1a200a39SWilliam Breathitt Gray *mask = CONTROL_REG_OUT_MODE; 274*1a200a39SWilliam Breathitt Gray return 0; 275*1a200a39SWilliam Breathitt Gray default: 276*1a200a39SWilliam Breathitt Gray /* Should never reach this path */ 277*1a200a39SWilliam Breathitt Gray return -EINVAL; 278*1a200a39SWilliam Breathitt Gray } 27958556204SWilliam Breathitt Gray } 28058556204SWilliam Breathitt Gray 28158556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56 28258556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = { 28358556204SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 28458556204SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 28558556204SWilliam Breathitt Gray "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", 28658556204SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 28758556204SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", 28858556204SWilliam Breathitt Gray "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", 28958556204SWilliam Breathitt Gray "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" 29058556204SWilliam Breathitt Gray }; 29158556204SWilliam Breathitt Gray 29258556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) 29358556204SWilliam Breathitt Gray { 29458556204SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 29558556204SWilliam Breathitt Gray struct idio_24_gpio *idio24gpio; 29658556204SWilliam Breathitt Gray int err; 29710a2f11dSArnaud de Turckheim const size_t pci_plx_bar_index = 1; 29858556204SWilliam Breathitt Gray const size_t pci_bar_index = 2; 29958556204SWilliam Breathitt Gray const char *const name = pci_name(pdev); 300*1a200a39SWilliam Breathitt Gray struct gpio_regmap_config gpio_config = {}; 301*1a200a39SWilliam Breathitt Gray void __iomem *pex8311_regs; 302*1a200a39SWilliam Breathitt Gray void __iomem *idio_24_regs; 303*1a200a39SWilliam Breathitt Gray struct regmap *intcsr_map; 304*1a200a39SWilliam Breathitt Gray struct regmap_irq_chip *chip; 305*1a200a39SWilliam Breathitt Gray struct regmap_irq_chip_data *chip_data; 30658556204SWilliam Breathitt Gray 30758556204SWilliam Breathitt Gray err = pcim_enable_device(pdev); 30858556204SWilliam Breathitt Gray if (err) { 30958556204SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 31058556204SWilliam Breathitt Gray return err; 31158556204SWilliam Breathitt Gray } 31258556204SWilliam Breathitt Gray 31310a2f11dSArnaud de Turckheim err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name); 31458556204SWilliam Breathitt Gray if (err) { 31558556204SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 31658556204SWilliam Breathitt Gray return err; 31758556204SWilliam Breathitt Gray } 31858556204SWilliam Breathitt Gray 319*1a200a39SWilliam Breathitt Gray pex8311_regs = pcim_iomap_table(pdev)[pci_plx_bar_index]; 320*1a200a39SWilliam Breathitt Gray idio_24_regs = pcim_iomap_table(pdev)[pci_bar_index]; 32158556204SWilliam Breathitt Gray 322*1a200a39SWilliam Breathitt Gray intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config); 323*1a200a39SWilliam Breathitt Gray if (IS_ERR(intcsr_map)) 324*1a200a39SWilliam Breathitt Gray return dev_err_probe(dev, PTR_ERR(intcsr_map), 325*1a200a39SWilliam Breathitt Gray "Unable to initialize PEX8311 register map\n"); 32658556204SWilliam Breathitt Gray 327*1a200a39SWilliam Breathitt Gray idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); 328*1a200a39SWilliam Breathitt Gray if (!idio24gpio) 329*1a200a39SWilliam Breathitt Gray return -ENOMEM; 330*1a200a39SWilliam Breathitt Gray 331*1a200a39SWilliam Breathitt Gray idio24gpio->map = devm_regmap_init_mmio(dev, idio_24_regs, &idio_24_regmap_config); 332*1a200a39SWilliam Breathitt Gray if (IS_ERR(idio24gpio->map)) 333*1a200a39SWilliam Breathitt Gray return dev_err_probe(dev, PTR_ERR(idio24gpio->map), 334*1a200a39SWilliam Breathitt Gray "Unable to initialize register map\n"); 335866e863eSLinus Walleij 33658556204SWilliam Breathitt Gray raw_spin_lock_init(&idio24gpio->lock); 33758556204SWilliam Breathitt Gray 338*1a200a39SWilliam Breathitt Gray /* Initialize all IRQ type configuration to IRQ_TYPE_EDGE_BOTH */ 339*1a200a39SWilliam Breathitt Gray idio24gpio->irq_type = GENMASK(7, 0); 340*1a200a39SWilliam Breathitt Gray 341*1a200a39SWilliam Breathitt Gray chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 342*1a200a39SWilliam Breathitt Gray if (!chip) 343*1a200a39SWilliam Breathitt Gray return -ENOMEM; 344*1a200a39SWilliam Breathitt Gray 345*1a200a39SWilliam Breathitt Gray chip->name = name; 346*1a200a39SWilliam Breathitt Gray chip->status_base = IDIO_24_COS_STATUS_BASE; 347*1a200a39SWilliam Breathitt Gray chip->mask_base = IDIO_24_COS_ENABLE; 348*1a200a39SWilliam Breathitt Gray chip->ack_base = IDIO_24_COS_STATUS_BASE; 349*1a200a39SWilliam Breathitt Gray chip->num_regs = 4; 350*1a200a39SWilliam Breathitt Gray chip->irqs = idio_24_regmap_irqs; 351*1a200a39SWilliam Breathitt Gray chip->num_irqs = ARRAY_SIZE(idio_24_regmap_irqs); 352*1a200a39SWilliam Breathitt Gray chip->handle_mask_sync = idio_24_handle_mask_sync; 353*1a200a39SWilliam Breathitt Gray chip->set_type_config = idio_24_set_type_config; 354*1a200a39SWilliam Breathitt Gray chip->irq_drv_data = idio24gpio; 355*1a200a39SWilliam Breathitt Gray 35658556204SWilliam Breathitt Gray /* Software board reset */ 357*1a200a39SWilliam Breathitt Gray err = regmap_write(idio24gpio->map, IDIO_24_SOFT_RESET, 0); 358*1a200a39SWilliam Breathitt Gray if (err) 359*1a200a39SWilliam Breathitt Gray return err; 36010a2f11dSArnaud de Turckheim /* 36110a2f11dSArnaud de Turckheim * enable PLX PEX8311 internal PCI wire interrupt and local interrupt 36210a2f11dSArnaud de Turckheim * input 36310a2f11dSArnaud de Turckheim */ 364*1a200a39SWilliam Breathitt Gray err = regmap_update_bits(intcsr_map, 0x0, IDIO_24_ENABLE_IRQ, IDIO_24_ENABLE_IRQ); 365*1a200a39SWilliam Breathitt Gray if (err) 36658556204SWilliam Breathitt Gray return err; 36758556204SWilliam Breathitt Gray 368*1a200a39SWilliam Breathitt Gray err = devm_regmap_add_irq_chip(dev, idio24gpio->map, pdev->irq, 0, 0, chip, &chip_data); 369*1a200a39SWilliam Breathitt Gray if (err) 370*1a200a39SWilliam Breathitt Gray return dev_err_probe(dev, err, "IRQ registration failed\n"); 37158556204SWilliam Breathitt Gray 372*1a200a39SWilliam Breathitt Gray gpio_config.parent = dev; 373*1a200a39SWilliam Breathitt Gray gpio_config.regmap = idio24gpio->map; 374*1a200a39SWilliam Breathitt Gray gpio_config.ngpio = IDIO_24_NGPIO; 375*1a200a39SWilliam Breathitt Gray gpio_config.names = idio_24_names; 376*1a200a39SWilliam Breathitt Gray gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE); 377*1a200a39SWilliam Breathitt Gray gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE); 378*1a200a39SWilliam Breathitt Gray gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(IDIO_24_CONTROL_REG); 379*1a200a39SWilliam Breathitt Gray gpio_config.ngpio_per_reg = IDIO_24_NGPIO_PER_REG; 380*1a200a39SWilliam Breathitt Gray gpio_config.irq_domain = regmap_irq_get_domain(chip_data); 381*1a200a39SWilliam Breathitt Gray gpio_config.reg_mask_xlate = idio_24_reg_mask_xlate; 382*1a200a39SWilliam Breathitt Gray gpio_config.drvdata = idio24gpio->map; 383*1a200a39SWilliam Breathitt Gray 384*1a200a39SWilliam Breathitt Gray return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); 38558556204SWilliam Breathitt Gray } 38658556204SWilliam Breathitt Gray 38758556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = { 38858556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, 38958556204SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, 39058556204SWilliam Breathitt Gray { 0 } 39158556204SWilliam Breathitt Gray }; 39258556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); 39358556204SWilliam Breathitt Gray 39458556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = { 39558556204SWilliam Breathitt Gray .name = "pcie-idio-24", 39658556204SWilliam Breathitt Gray .id_table = idio_24_pci_dev_id, 39758556204SWilliam Breathitt Gray .probe = idio_24_probe 39858556204SWilliam Breathitt Gray }; 39958556204SWilliam Breathitt Gray 40058556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver); 40158556204SWilliam Breathitt Gray 40258556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 40358556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); 40458556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 405