gpio-pcie-idio-24.c 13 KB

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