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
78static 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
87static 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};
91static const struct regmap_range idio_24_rd_ranges[] = {
92	regmap_reg_range(0x0, 0xC), regmap_reg_range(0xE, 0xF),
93};
94static const struct regmap_range idio_24_volatile_ranges[] = {
95	regmap_reg_range(0x4, 0xB), regmap_reg_range(0xF, 0xF),
96};
97static 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};
101static 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};
105static 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
110static 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
132static 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 */
152struct idio_24_gpio {
153	struct regmap *map;
154	raw_spinlock_t lock;
155	u8 irq_type;
156};
157
158static 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
178static 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
222exit_unlock:
223	raw_spin_unlock(&idio24gpio->lock);
224
225	return ret;
226}
227
228static 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
282static 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
292static 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		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
310		return err;
311	}
312
313	err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name);
314	if (err) {
315		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
316		return err;
317	}
318
319	pex8311_regs = pcim_iomap_table(pdev)[pci_plx_bar_index];
320	idio_24_regs = pcim_iomap_table(pdev)[pci_bar_index];
321
322	intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config);
323	if (IS_ERR(intcsr_map))
324		return dev_err_probe(dev, PTR_ERR(intcsr_map),
325				     "Unable to initialize PEX8311 register map\n");
326
327	idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
328	if (!idio24gpio)
329		return -ENOMEM;
330
331	idio24gpio->map = devm_regmap_init_mmio(dev, idio_24_regs, &idio_24_regmap_config);
332	if (IS_ERR(idio24gpio->map))
333		return dev_err_probe(dev, PTR_ERR(idio24gpio->map),
334				     "Unable to initialize register map\n");
335
336	raw_spin_lock_init(&idio24gpio->lock);
337
338	/* Initialize all IRQ type configuration to IRQ_TYPE_EDGE_BOTH */
339	idio24gpio->irq_type = GENMASK(7, 0);
340
341	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
342	if (!chip)
343		return -ENOMEM;
344
345	chip->name = name;
346	chip->status_base = IDIO_24_COS_STATUS_BASE;
347	chip->mask_base = IDIO_24_COS_ENABLE;
348	chip->ack_base = IDIO_24_COS_STATUS_BASE;
349	chip->num_regs = 4;
350	chip->irqs = idio_24_regmap_irqs;
351	chip->num_irqs = ARRAY_SIZE(idio_24_regmap_irqs);
352	chip->handle_mask_sync = idio_24_handle_mask_sync;
353	chip->set_type_config = idio_24_set_type_config;
354	chip->irq_drv_data = idio24gpio;
355
356	/* Software board reset */
357	err = regmap_write(idio24gpio->map, IDIO_24_SOFT_RESET, 0);
358	if (err)
359		return err;
360	/*
361	 * enable PLX PEX8311 internal PCI wire interrupt and local interrupt
362	 * input
363	 */
364	err = regmap_update_bits(intcsr_map, 0x0, IDIO_24_ENABLE_IRQ, IDIO_24_ENABLE_IRQ);
365	if (err)
366		return err;
367
368	err = devm_regmap_add_irq_chip(dev, idio24gpio->map, pdev->irq, 0, 0, chip, &chip_data);
369	if (err)
370		return dev_err_probe(dev, err, "IRQ registration failed\n");
371
372	gpio_config.parent = dev;
373	gpio_config.regmap = idio24gpio->map;
374	gpio_config.ngpio = IDIO_24_NGPIO;
375	gpio_config.names = idio_24_names;
376	gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
377	gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
378	gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(IDIO_24_CONTROL_REG);
379	gpio_config.ngpio_per_reg = IDIO_24_NGPIO_PER_REG;
380	gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
381	gpio_config.reg_mask_xlate = idio_24_reg_mask_xlate;
382	gpio_config.drvdata = idio24gpio->map;
383
384	return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
385}
386
387static const struct pci_device_id idio_24_pci_dev_id[] = {
388	{ PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
389	{ PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
390	{ 0 }
391};
392MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
393
394static struct pci_driver idio_24_driver = {
395	.name = "pcie-idio-24",
396	.id_table = idio_24_pci_dev_id,
397	.probe = idio_24_probe
398};
399
400module_pci_driver(idio_24_driver);
401
402MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
403MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
404MODULE_LICENSE("GPL v2");
405