Linux Audio

Check our new training course

Loading...
v6.8
  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 -EOPNOTSUPP;
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");
v5.4
  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 program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License, version 2, as
  8 * published by the Free Software Foundation.
  9 *
 10 * This program is distributed in the hope that it will be useful, but
 11 * WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13 * General Public License for more details.
 14 *
 15 * This driver supports the following ACCES devices: PCIe-IDIO-24,
 16 * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
 17 */
 18#include <linux/bitmap.h>
 19#include <linux/bitops.h>
 20#include <linux/device.h>
 21#include <linux/errno.h>
 22#include <linux/gpio/driver.h>
 23#include <linux/interrupt.h>
 24#include <linux/irqdesc.h>
 25#include <linux/kernel.h>
 26#include <linux/module.h>
 27#include <linux/pci.h>
 
 28#include <linux/spinlock.h>
 29#include <linux/types.h>
 30
 31/**
 32 * struct idio_24_gpio_reg - GPIO device registers structure
 33 * @out0_7:	Read: FET Outputs 0-7
 34 *		Write: FET Outputs 0-7
 35 * @out8_15:	Read: FET Outputs 8-15
 36 *		Write: FET Outputs 8-15
 37 * @out16_23:	Read: FET Outputs 16-23
 38 *		Write: FET Outputs 16-23
 39 * @ttl_out0_7:	Read: TTL/CMOS Outputs 0-7
 40 *		Write: TTL/CMOS Outputs 0-7
 41 * @in0_7:	Read: Isolated Inputs 0-7
 42 *		Write: Reserved
 43 * @in8_15:	Read: Isolated Inputs 8-15
 44 *		Write: Reserved
 45 * @in16_23:	Read: Isolated Inputs 16-23
 46 *		Write: Reserved
 47 * @ttl_in0_7:	Read: TTL/CMOS Inputs 0-7
 48 *		Write: Reserved
 49 * @cos0_7:	Read: COS Status Inputs 0-7
 50 *		Write: COS Clear Inputs 0-7
 51 * @cos8_15:	Read: COS Status Inputs 8-15
 52 *		Write: COS Clear Inputs 8-15
 53 * @cos16_23:	Read: COS Status Inputs 16-23
 54 *		Write: COS Clear Inputs 16-23
 55 * @cos_ttl0_7:	Read: COS Status TTL/CMOS 0-7
 56 *		Write: COS Clear TTL/CMOS 0-7
 57 * @ctl:	Read: Control Register
 58 *		Write: Control Register
 59 * @reserved:	Read: Reserved
 60 *		Write: Reserved
 61 * @cos_enable:	Read: COS Enable
 62 *		Write: COS Enable
 63 * @soft_reset:	Read: IRQ Output Pin Status
 64 *		Write: Software Board Reset
 
 
 65 */
 66struct idio_24_gpio_reg {
 67	u8 out0_7;
 68	u8 out8_15;
 69	u8 out16_23;
 70	u8 ttl_out0_7;
 71	u8 in0_7;
 72	u8 in8_15;
 73	u8 in16_23;
 74	u8 ttl_in0_7;
 75	u8 cos0_7;
 76	u8 cos8_15;
 77	u8 cos16_23;
 78	u8 cos_ttl0_7;
 79	u8 ctl;
 80	u8 reserved;
 81	u8 cos_enable;
 82	u8 soft_reset;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 83};
 84
 85/**
 86 * struct idio_24_gpio - GPIO device private data structure
 87 * @chip:	instance of the gpio_chip
 88 * @lock:	synchronization lock to prevent I/O race conditions
 89 * @reg:	I/O address offset for the GPIO device registers
 90 * @irq_mask:	I/O bits affected by interrupts
 91 */
 92struct idio_24_gpio {
 93	struct gpio_chip chip;
 94	raw_spinlock_t lock;
 95	struct idio_24_gpio_reg __iomem *reg;
 96	unsigned long irq_mask;
 97};
 98
 99static int idio_24_gpio_get_direction(struct gpio_chip *chip,
100	unsigned int offset)
101{
102	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
103	const unsigned long out_mode_mask = BIT(1);
 
 
104
105	/* FET Outputs */
106	if (offset < 24)
107		return 0;
108
109	/* Isolated Inputs */
110	if (offset < 48)
111		return 1;
112
113	/* TTL/CMOS I/O */
114	/* OUT MODE = 1 when TTL/CMOS Output Mode is set */
115	return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask);
116}
117
118static int idio_24_gpio_direction_input(struct gpio_chip *chip,
119	unsigned int offset)
120{
121	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
122	unsigned long flags;
123	unsigned int ctl_state;
124	const unsigned long out_mode_mask = BIT(1);
125
126	/* TTL/CMOS I/O */
127	if (offset > 47) {
128		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
129
130		/* Clear TTL/CMOS Output Mode */
131		ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
132		iowrite8(ctl_state, &idio24gpio->reg->ctl);
133
134		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
135	}
136
137	return 0;
138}
139
140static int idio_24_gpio_direction_output(struct gpio_chip *chip,
141	unsigned int offset, int value)
142{
143	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
144	unsigned long flags;
145	unsigned int ctl_state;
146	const unsigned long out_mode_mask = BIT(1);
147
148	/* TTL/CMOS I/O */
149	if (offset > 47) {
150		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
151
152		/* Set TTL/CMOS Output Mode */
153		ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
154		iowrite8(ctl_state, &idio24gpio->reg->ctl);
155
156		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 
 
 
 
 
 
 
 
157	}
158
159	chip->set(chip, offset, value);
160	return 0;
161}
162
163static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
164{
165	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
166	const unsigned long offset_mask = BIT(offset % 8);
167	const unsigned long out_mode_mask = BIT(1);
168
169	/* FET Outputs */
170	if (offset < 8)
171		return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
 
 
 
 
 
 
 
 
172
173	if (offset < 16)
174		return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
175
176	if (offset < 24)
177		return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
178
179	/* Isolated Inputs */
180	if (offset < 32)
181		return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
182
183	if (offset < 40)
184		return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
185
186	if (offset < 48)
187		return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
188
189	/* TTL/CMOS Outputs */
190	if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
191		return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
192
193	/* TTL/CMOS Inputs */
194	return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
195}
196
197static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
198	unsigned long *mask, unsigned long *bits)
 
199{
200	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
201	size_t i;
202	const unsigned int gpio_reg_size = 8;
203	unsigned int bits_offset;
204	size_t word_index;
205	unsigned int word_offset;
206	unsigned long word_mask;
207	const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
208	unsigned long port_state;
209	void __iomem *ports[] = {
210		&idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
211		&idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7,
212		&idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23,
213	};
214	const unsigned long out_mode_mask = BIT(1);
215
216	/* clear bits array to a clean slate */
217	bitmap_zero(bits, chip->ngpio);
218
219	/* get bits are evaluated a gpio port register at a time */
220	for (i = 0; i < ARRAY_SIZE(ports) + 1; i++) {
221		/* gpio offset in bits array */
222		bits_offset = i * gpio_reg_size;
223
224		/* word index for bits array */
225		word_index = BIT_WORD(bits_offset);
226
227		/* gpio offset within current word of bits array */
228		word_offset = bits_offset % BITS_PER_LONG;
229
230		/* mask of get bits for current gpio within current word */
231		word_mask = mask[word_index] & (port_mask << word_offset);
232		if (!word_mask) {
233			/* no get bits in this port so skip to next one */
234			continue;
235		}
236
237		/* read bits from current gpio port (port 6 is TTL GPIO) */
238		if (i < 6)
239			port_state = ioread8(ports[i]);
240		else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
241			port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
242		else
243			port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
244
245		/* store acquired bits at respective bits array offset */
246		bits[word_index] |= (port_state << word_offset) & word_mask;
247	}
248
249	return 0;
250}
251
252static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
253	int value)
254{
255	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
256	const unsigned long out_mode_mask = BIT(1);
257	void __iomem *base;
258	const unsigned int mask = BIT(offset % 8);
259	unsigned long flags;
260	unsigned int out_state;
261
262	/* Isolated Inputs */
263	if (offset > 23 && offset < 48)
264		return;
265
266	/* TTL/CMOS Inputs */
267	if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
268		return;
269
270	/* TTL/CMOS Outputs */
271	if (offset > 47)
272		base = &idio24gpio->reg->ttl_out0_7;
273	/* FET Outputs */
274	else if (offset > 15)
275		base = &idio24gpio->reg->out16_23;
276	else if (offset > 7)
277		base = &idio24gpio->reg->out8_15;
278	else
279		base = &idio24gpio->reg->out0_7;
280
281	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
282
283	if (value)
284		out_state = ioread8(base) | mask;
285	else
286		out_state = ioread8(base) & ~mask;
287
288	iowrite8(out_state, base);
289
290	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
291}
292
293static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
294	unsigned long *mask, unsigned long *bits)
295{
296	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
297	size_t i;
298	unsigned long bits_offset;
299	unsigned long gpio_mask;
300	const unsigned int gpio_reg_size = 8;
301	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
302	unsigned long flags;
303	unsigned int out_state;
304	void __iomem *ports[] = {
305		&idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
306		&idio24gpio->reg->out16_23
307	};
308	const unsigned long out_mode_mask = BIT(1);
309	const unsigned int ttl_offset = 48;
310	const size_t ttl_i = BIT_WORD(ttl_offset);
311	const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
312	const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
313	const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
314
315	/* set bits are processed a gpio port register at a time */
316	for (i = 0; i < ARRAY_SIZE(ports); i++) {
317		/* gpio offset in bits array */
318		bits_offset = i * gpio_reg_size;
319
320		/* check if any set bits for current port */
321		gpio_mask = (*mask >> bits_offset) & port_mask;
322		if (!gpio_mask) {
323			/* no set bits for this port so move on to next port */
324			continue;
325		}
326
327		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 
 
 
 
 
 
328
329		/* process output lines */
330		out_state = ioread8(ports[i]) & ~gpio_mask;
331		out_state |= (*bits >> bits_offset) & gpio_mask;
332		iowrite8(out_state, ports[i]);
333
334		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
335	}
336
337	/* check if setting TTL lines and if they are in output mode */
338	if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
339		return;
340
341	/* handle TTL output */
342	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
343
344	/* process output lines */
345	out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
346	out_state |= ttl_bits;
347	iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
348
349	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
350}
351
352static void idio_24_irq_ack(struct irq_data *data)
353{
354}
355
356static void idio_24_irq_mask(struct irq_data *data)
357{
358	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
359	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
360	unsigned long flags;
361	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
362	unsigned char new_irq_mask;
363	const unsigned long bank_offset = bit_offset/8 * 8;
364	unsigned char cos_enable_state;
365
366	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
367
368	idio24gpio->irq_mask &= BIT(bit_offset);
369	new_irq_mask = idio24gpio->irq_mask >> bank_offset;
370
371	if (!new_irq_mask) {
372		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
373
374		/* Disable Rising Edge detection */
375		cos_enable_state &= ~BIT(bank_offset);
376		/* Disable Falling Edge detection */
377		cos_enable_state &= ~BIT(bank_offset + 4);
378
379		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
380	}
381
382	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
383}
384
385static void idio_24_irq_unmask(struct irq_data *data)
386{
387	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
388	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
389	unsigned long flags;
390	unsigned char prev_irq_mask;
391	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
392	const unsigned long bank_offset = bit_offset/8 * 8;
393	unsigned char cos_enable_state;
394
395	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
396
397	prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
398	idio24gpio->irq_mask |= BIT(bit_offset);
399
400	if (!prev_irq_mask) {
401		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
402
403		/* Enable Rising Edge detection */
404		cos_enable_state |= BIT(bank_offset);
405		/* Enable Falling Edge detection */
406		cos_enable_state |= BIT(bank_offset + 4);
407
408		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
409	}
410
411	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
412}
413
414static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
415{
416	/* The only valid irq types are none and both-edges */
417	if (flow_type != IRQ_TYPE_NONE &&
418		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
419		return -EINVAL;
420
421	return 0;
422}
423
424static struct irq_chip idio_24_irqchip = {
425	.name = "pcie-idio-24",
426	.irq_ack = idio_24_irq_ack,
427	.irq_mask = idio_24_irq_mask,
428	.irq_unmask = idio_24_irq_unmask,
429	.irq_set_type = idio_24_irq_set_type
430};
431
432static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
433{
434	struct idio_24_gpio *const idio24gpio = dev_id;
435	unsigned long irq_status;
436	struct gpio_chip *const chip = &idio24gpio->chip;
437	unsigned long irq_mask;
438	int gpio;
439
440	raw_spin_lock(&idio24gpio->lock);
441
442	/* Read Change-Of-State status */
443	irq_status = ioread32(&idio24gpio->reg->cos0_7);
444
445	raw_spin_unlock(&idio24gpio->lock);
446
447	/* Make sure our device generated IRQ */
448	if (!irq_status)
449		return IRQ_NONE;
450
451	/* Handle only unmasked IRQ */
452	irq_mask = idio24gpio->irq_mask & irq_status;
453
454	for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
455		generic_handle_irq(irq_find_mapping(chip->irq.domain,
456			gpio + 24));
457
458	raw_spin_lock(&idio24gpio->lock);
459
460	/* Clear Change-Of-State status */
461	iowrite32(irq_status, &idio24gpio->reg->cos0_7);
462
463	raw_spin_unlock(&idio24gpio->lock);
464
465	return IRQ_HANDLED;
466}
467
468#define IDIO_24_NGPIO 56
469static const char *idio_24_names[IDIO_24_NGPIO] = {
470	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
471	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
472	"OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
473	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
474	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
475	"IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
476	"TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
477};
478
479static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
480{
481	struct device *const dev = &pdev->dev;
482	struct idio_24_gpio *idio24gpio;
483	int err;
 
484	const size_t pci_bar_index = 2;
485	const char *const name = pci_name(pdev);
486
487	idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
488	if (!idio24gpio)
489		return -ENOMEM;
 
 
490
491	err = pcim_enable_device(pdev);
492	if (err) {
493		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
494		return err;
495	}
496
497	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
498	if (err) {
499		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
500		return err;
501	}
502
503	idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
 
 
 
 
 
 
 
 
 
 
504
505	idio24gpio->chip.label = name;
506	idio24gpio->chip.parent = dev;
507	idio24gpio->chip.owner = THIS_MODULE;
508	idio24gpio->chip.base = -1;
509	idio24gpio->chip.ngpio = IDIO_24_NGPIO;
510	idio24gpio->chip.names = idio_24_names;
511	idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
512	idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
513	idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
514	idio24gpio->chip.get = idio_24_gpio_get;
515	idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
516	idio24gpio->chip.set = idio_24_gpio_set;
517	idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
518
519	raw_spin_lock_init(&idio24gpio->lock);
520
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
521	/* Software board reset */
522	iowrite8(0, &idio24gpio->reg->soft_reset);
523
524	err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
525	if (err) {
526		dev_err(dev, "GPIO registering failed (%d)\n", err);
527		return err;
528	}
529
530	err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0,
531		handle_edge_irq, IRQ_TYPE_NONE);
532	if (err) {
533		dev_err(dev, "Could not add irqchip (%d)\n", err);
534		return err;
535	}
536
537	err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
538		name, idio24gpio);
539	if (err) {
540		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
541		return err;
542	}
 
 
 
 
 
 
 
 
 
543
544	return 0;
545}
546
547static const struct pci_device_id idio_24_pci_dev_id[] = {
548	{ PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
549	{ PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
550	{ 0 }
551};
552MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
553
554static struct pci_driver idio_24_driver = {
555	.name = "pcie-idio-24",
556	.id_table = idio_24_pci_dev_id,
557	.probe = idio_24_probe
558};
559
560module_pci_driver(idio_24_driver);
561
562MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
563MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
564MODULE_LICENSE("GPL v2");