1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * GPIO driver for the ACCES PCIe-IDIO-24 family 4 * Copyright (C) 2018 William Breathitt Gray 5 * 6 * This driver supports the following ACCES devices: PCIe-IDIO-24, 7 * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. 8 */ 9 #include <linux/bits.h> 10 #include <linux/device.h> 11 #include <linux/err.h> 12 #include <linux/gpio/regmap.h> 13 #include <linux/irq.h> 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/pci.h> 17 #include <linux/regmap.h> 18 #include <linux/spinlock.h> 19 #include <linux/types.h> 20 21 /* 22 * PLX PEX8311 PCI LCS_INTCSR Interrupt Control/Status 23 * 24 * Bit: Description 25 * 0: Enable Interrupt Sources (Bit 0) 26 * 1: Enable Interrupt Sources (Bit 1) 27 * 2: Generate Internal PCI Bus Internal SERR# Interrupt 28 * 3: Mailbox Interrupt Enable 29 * 4: Power Management Interrupt Enable 30 * 5: Power Management Interrupt 31 * 6: Slave Read Local Data Parity Check Error Enable 32 * 7: Slave Read Local Data Parity Check Error Status 33 * 8: Internal PCI Wire Interrupt Enable 34 * 9: PCI Express Doorbell Interrupt Enable 35 * 10: PCI Abort Interrupt Enable 36 * 11: Local Interrupt Input Enable 37 * 12: Retry Abort Enable 38 * 13: PCI Express Doorbell Interrupt Active 39 * 14: PCI Abort Interrupt Active 40 * 15: Local Interrupt Input Active 41 * 16: Local Interrupt Output Enable 42 * 17: Local Doorbell Interrupt Enable 43 * 18: DMA Channel 0 Interrupt Enable 44 * 19: DMA Channel 1 Interrupt Enable 45 * 20: Local Doorbell Interrupt Active 46 * 21: DMA Channel 0 Interrupt Active 47 * 22: DMA Channel 1 Interrupt Active 48 * 23: Built-In Self-Test (BIST) Interrupt Active 49 * 24: Direct Master was the Bus Master during a Master or Target Abort 50 * 25: DMA Channel 0 was the Bus Master during a Master or Target Abort 51 * 26: DMA Channel 1 was the Bus Master during a Master or Target Abort 52 * 27: Target Abort after internal 256 consecutive Master Retrys 53 * 28: PCI Bus wrote data to LCS_MBOX0 54 * 29: PCI Bus wrote data to LCS_MBOX1 55 * 30: PCI Bus wrote data to LCS_MBOX2 56 * 31: PCI Bus wrote data to LCS_MBOX3 57 */ 58 #define PLX_PEX8311_PCI_LCS_INTCSR 0x68 59 #define INTCSR_INTERNAL_PCI_WIRE BIT(8) 60 #define INTCSR_LOCAL_INPUT BIT(11) 61 #define IDIO_24_ENABLE_IRQ (INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT) 62 63 #define IDIO_24_OUT_BASE 0x0 64 #define IDIO_24_TTLCMOS_OUT_REG 0x3 65 #define IDIO_24_IN_BASE 0x4 66 #define IDIO_24_TTLCMOS_IN_REG 0x7 67 #define IDIO_24_COS_STATUS_BASE 0x8 68 #define IDIO_24_CONTROL_REG 0xC 69 #define IDIO_24_COS_ENABLE 0xE 70 #define IDIO_24_SOFT_RESET 0xF 71 72 #define CONTROL_REG_OUT_MODE BIT(1) 73 74 #define COS_ENABLE_RISING BIT(1) 75 #define COS_ENABLE_FALLING BIT(4) 76 #define COS_ENABLE_BOTH (COS_ENABLE_RISING | COS_ENABLE_FALLING) 77 78 static const struct regmap_config pex8311_intcsr_regmap_config = { 79 .name = "pex8311_intcsr", 80 .reg_bits = 32, 81 .reg_stride = 1, 82 .reg_base = PLX_PEX8311_PCI_LCS_INTCSR, 83 .val_bits = 32, 84 .io_port = true, 85 }; 86 87 static const struct regmap_range idio_24_wr_ranges[] = { 88 regmap_reg_range(0x0, 0x3), regmap_reg_range(0x8, 0xC), 89 regmap_reg_range(0xE, 0xF), 90 }; 91 static const struct regmap_range idio_24_rd_ranges[] = { 92 regmap_reg_range(0x0, 0xC), regmap_reg_range(0xE, 0xF), 93 }; 94 static const struct regmap_range idio_24_volatile_ranges[] = { 95 regmap_reg_range(0x4, 0xB), regmap_reg_range(0xF, 0xF), 96 }; 97 static const struct regmap_access_table idio_24_wr_table = { 98 .yes_ranges = idio_24_wr_ranges, 99 .n_yes_ranges = ARRAY_SIZE(idio_24_wr_ranges), 100 }; 101 static const struct regmap_access_table idio_24_rd_table = { 102 .yes_ranges = idio_24_rd_ranges, 103 .n_yes_ranges = ARRAY_SIZE(idio_24_rd_ranges), 104 }; 105 static const struct regmap_access_table idio_24_volatile_table = { 106 .yes_ranges = idio_24_volatile_ranges, 107 .n_yes_ranges = ARRAY_SIZE(idio_24_volatile_ranges), 108 }; 109 110 static const struct regmap_config idio_24_regmap_config = { 111 .reg_bits = 8, 112 .reg_stride = 1, 113 .val_bits = 8, 114 .io_port = true, 115 .wr_table = &idio_24_wr_table, 116 .rd_table = &idio_24_rd_table, 117 .volatile_table = &idio_24_volatile_table, 118 .cache_type = REGCACHE_FLAT, 119 .use_raw_spinlock = true, 120 }; 121 122 #define IDIO_24_NGPIO_PER_REG 8 123 #define IDIO_24_REGMAP_IRQ(_id) \ 124 [24 + _id] = { \ 125 .reg_offset = (_id) / IDIO_24_NGPIO_PER_REG, \ 126 .mask = BIT((_id) % IDIO_24_NGPIO_PER_REG), \ 127 .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \ 128 } 129 #define IDIO_24_IIN_IRQ(_id) IDIO_24_REGMAP_IRQ(_id) 130 #define IDIO_24_TTL_IRQ(_id) IDIO_24_REGMAP_IRQ(24 + _id) 131 132 static const struct regmap_irq idio_24_regmap_irqs[] = { 133 IDIO_24_IIN_IRQ(0), IDIO_24_IIN_IRQ(1), IDIO_24_IIN_IRQ(2), /* IIN 0-2 */ 134 IDIO_24_IIN_IRQ(3), IDIO_24_IIN_IRQ(4), IDIO_24_IIN_IRQ(5), /* IIN 3-5 */ 135 IDIO_24_IIN_IRQ(6), IDIO_24_IIN_IRQ(7), IDIO_24_IIN_IRQ(8), /* IIN 6-8 */ 136 IDIO_24_IIN_IRQ(9), IDIO_24_IIN_IRQ(10), IDIO_24_IIN_IRQ(11), /* IIN 9-11 */ 137 IDIO_24_IIN_IRQ(12), IDIO_24_IIN_IRQ(13), IDIO_24_IIN_IRQ(14), /* IIN 12-14 */ 138 IDIO_24_IIN_IRQ(15), IDIO_24_IIN_IRQ(16), IDIO_24_IIN_IRQ(17), /* IIN 15-17 */ 139 IDIO_24_IIN_IRQ(18), IDIO_24_IIN_IRQ(19), IDIO_24_IIN_IRQ(20), /* IIN 18-20 */ 140 IDIO_24_IIN_IRQ(21), IDIO_24_IIN_IRQ(22), IDIO_24_IIN_IRQ(23), /* IIN 21-23 */ 141 IDIO_24_TTL_IRQ(0), IDIO_24_TTL_IRQ(1), IDIO_24_TTL_IRQ(2), /* TTL 0-2 */ 142 IDIO_24_TTL_IRQ(3), IDIO_24_TTL_IRQ(4), IDIO_24_TTL_IRQ(5), /* TTL 3-5 */ 143 IDIO_24_TTL_IRQ(6), IDIO_24_TTL_IRQ(7), /* TTL 6-7 */ 144 }; 145 146 /** 147 * struct idio_24_gpio - GPIO device private data structure 148 * @map: regmap for the device 149 * @lock: synchronization lock to prevent I/O race conditions 150 * @irq_type: type configuration for IRQs 151 */ 152 struct idio_24_gpio { 153 struct regmap *map; 154 raw_spinlock_t lock; 155 u8 irq_type; 156 }; 157 158 static int idio_24_handle_mask_sync(const int index, const unsigned int mask_buf_def, 159 const unsigned int mask_buf, void *const irq_drv_data) 160 { 161 const unsigned int type_mask = COS_ENABLE_BOTH << index; 162 struct idio_24_gpio *const idio24gpio = irq_drv_data; 163 u8 type; 164 int ret; 165 166 raw_spin_lock(&idio24gpio->lock); 167 168 /* if all are masked, then disable interrupts, else set to type */ 169 type = (mask_buf == mask_buf_def) ? ~type_mask : idio24gpio->irq_type; 170 171 ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, type_mask, type); 172 173 raw_spin_unlock(&idio24gpio->lock); 174 175 return ret; 176 } 177 178 static int idio_24_set_type_config(unsigned int **const buf, const unsigned int type, 179 const struct regmap_irq *const irq_data, const int idx, 180 void *const irq_drv_data) 181 { 182 const unsigned int offset = irq_data->reg_offset; 183 const unsigned int rising = COS_ENABLE_RISING << offset; 184 const unsigned int falling = COS_ENABLE_FALLING << offset; 185 const unsigned int mask = COS_ENABLE_BOTH << offset; 186 struct idio_24_gpio *const idio24gpio = irq_drv_data; 187 unsigned int new; 188 unsigned int cos_enable; 189 int ret; 190 191 switch (type) { 192 case IRQ_TYPE_EDGE_RISING: 193 new = rising; 194 break; 195 case IRQ_TYPE_EDGE_FALLING: 196 new = falling; 197 break; 198 case IRQ_TYPE_EDGE_BOTH: 199 new = mask; 200 break; 201 default: 202 return -EINVAL; 203 } 204 205 raw_spin_lock(&idio24gpio->lock); 206 207 /* replace old bitmap with new bitmap */ 208 idio24gpio->irq_type = (idio24gpio->irq_type & ~mask) | (new & mask); 209 210 ret = regmap_read(idio24gpio->map, IDIO_24_COS_ENABLE, &cos_enable); 211 if (ret) 212 goto exit_unlock; 213 214 /* if COS is currently enabled then update the edge type */ 215 if (cos_enable & mask) { 216 ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, mask, 217 idio24gpio->irq_type); 218 if (ret) 219 goto exit_unlock; 220 } 221 222 exit_unlock: 223 raw_spin_unlock(&idio24gpio->lock); 224 225 return ret; 226 } 227 228 static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base, 229 const unsigned int offset, unsigned int *const reg, 230 unsigned int *const mask) 231 { 232 const unsigned int out_stride = offset / IDIO_24_NGPIO_PER_REG; 233 const unsigned int in_stride = (offset - 24) / IDIO_24_NGPIO_PER_REG; 234 struct regmap *const map = gpio_regmap_get_drvdata(gpio); 235 int err; 236 unsigned int ctrl_reg; 237 238 switch (base) { 239 case IDIO_24_OUT_BASE: 240 *mask = BIT(offset % IDIO_24_NGPIO_PER_REG); 241 242 /* FET Outputs */ 243 if (offset < 24) { 244 *reg = IDIO_24_OUT_BASE + out_stride; 245 return 0; 246 } 247 248 /* Isolated Inputs */ 249 if (offset < 48) { 250 *reg = IDIO_24_IN_BASE + in_stride; 251 return 0; 252 } 253 254 err = regmap_read(map, IDIO_24_CONTROL_REG, &ctrl_reg); 255 if (err) 256 return err; 257 258 /* TTL/CMOS Outputs */ 259 if (ctrl_reg & CONTROL_REG_OUT_MODE) { 260 *reg = IDIO_24_TTLCMOS_OUT_REG; 261 return 0; 262 } 263 264 /* TTL/CMOS Inputs */ 265 *reg = IDIO_24_TTLCMOS_IN_REG; 266 return 0; 267 case IDIO_24_CONTROL_REG: 268 /* We can only set direction for TTL/CMOS lines */ 269 if (offset < 48) 270 return -ENOTSUPP; 271 272 *reg = IDIO_24_CONTROL_REG; 273 *mask = CONTROL_REG_OUT_MODE; 274 return 0; 275 default: 276 /* Should never reach this path */ 277 return -EINVAL; 278 } 279 } 280 281 #define IDIO_24_NGPIO 56 282 static const char *idio_24_names[IDIO_24_NGPIO] = { 283 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 284 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 285 "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", 286 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 287 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", 288 "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", 289 "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" 290 }; 291 292 static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) 293 { 294 struct device *const dev = &pdev->dev; 295 struct idio_24_gpio *idio24gpio; 296 int err; 297 const size_t pci_plx_bar_index = 1; 298 const size_t pci_bar_index = 2; 299 const char *const name = pci_name(pdev); 300 struct gpio_regmap_config gpio_config = {}; 301 void __iomem *pex8311_regs; 302 void __iomem *idio_24_regs; 303 struct regmap *intcsr_map; 304 struct regmap_irq_chip *chip; 305 struct regmap_irq_chip_data *chip_data; 306 307 err = pcim_enable_device(pdev); 308 if (err) 309 return dev_err_probe(dev, err, "Failed to enable PCI device\n"); 310 311 pex8311_regs = pcim_iomap_region(pdev, pci_plx_bar_index, "pex8311"); 312 if (IS_ERR(pex8311_regs)) 313 return dev_err_probe(dev, PTR_ERR(pex8311_regs), "Unable to map PEX 8311 I/O addresses\n"); 314 315 idio_24_regs = pcim_iomap_region(pdev, pci_bar_index, name); 316 if (IS_ERR(idio_24_regs)) 317 return dev_err_probe(dev, PTR_ERR(idio_24_regs), "Unable to map PCIe-IDIO-24 I/O addresses\n"); 318 319 intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config); 320 if (IS_ERR(intcsr_map)) 321 return dev_err_probe(dev, PTR_ERR(intcsr_map), 322 "Unable to initialize PEX8311 register map\n"); 323 324 idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); 325 if (!idio24gpio) 326 return -ENOMEM; 327 328 idio24gpio->map = devm_regmap_init_mmio(dev, idio_24_regs, &idio_24_regmap_config); 329 if (IS_ERR(idio24gpio->map)) 330 return dev_err_probe(dev, PTR_ERR(idio24gpio->map), 331 "Unable to initialize register map\n"); 332 333 raw_spin_lock_init(&idio24gpio->lock); 334 335 /* Initialize all IRQ type configuration to IRQ_TYPE_EDGE_BOTH */ 336 idio24gpio->irq_type = GENMASK(7, 0); 337 338 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 339 if (!chip) 340 return -ENOMEM; 341 342 chip->name = name; 343 chip->status_base = IDIO_24_COS_STATUS_BASE; 344 chip->mask_base = IDIO_24_COS_ENABLE; 345 chip->ack_base = IDIO_24_COS_STATUS_BASE; 346 chip->num_regs = 4; 347 chip->irqs = idio_24_regmap_irqs; 348 chip->num_irqs = ARRAY_SIZE(idio_24_regmap_irqs); 349 chip->handle_mask_sync = idio_24_handle_mask_sync; 350 chip->set_type_config = idio_24_set_type_config; 351 chip->irq_drv_data = idio24gpio; 352 353 /* Software board reset */ 354 err = regmap_write(idio24gpio->map, IDIO_24_SOFT_RESET, 0); 355 if (err) 356 return err; 357 /* 358 * enable PLX PEX8311 internal PCI wire interrupt and local interrupt 359 * input 360 */ 361 err = regmap_update_bits(intcsr_map, 0x0, IDIO_24_ENABLE_IRQ, IDIO_24_ENABLE_IRQ); 362 if (err) 363 return err; 364 365 err = devm_regmap_add_irq_chip(dev, idio24gpio->map, pdev->irq, 0, 0, chip, &chip_data); 366 if (err) 367 return dev_err_probe(dev, err, "IRQ registration failed\n"); 368 369 gpio_config.parent = dev; 370 gpio_config.regmap = idio24gpio->map; 371 gpio_config.ngpio = IDIO_24_NGPIO; 372 gpio_config.names = idio_24_names; 373 gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE); 374 gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE); 375 gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(IDIO_24_CONTROL_REG); 376 gpio_config.ngpio_per_reg = IDIO_24_NGPIO_PER_REG; 377 gpio_config.irq_domain = regmap_irq_get_domain(chip_data); 378 gpio_config.reg_mask_xlate = idio_24_reg_mask_xlate; 379 gpio_config.drvdata = idio24gpio->map; 380 381 return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); 382 } 383 384 static const struct pci_device_id idio_24_pci_dev_id[] = { 385 { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, 386 { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, 387 { 0 } 388 }; 389 MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); 390 391 static struct pci_driver idio_24_driver = { 392 .name = "pcie-idio-24", 393 .id_table = idio_24_pci_dev_id, 394 .probe = idio_24_probe 395 }; 396 397 module_pci_driver(idio_24_driver); 398 399 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 400 MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); 401 MODULE_LICENSE("GPL v2"); 402