18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * GPIO driver for the ACCES PCI-IDIO-16 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 William Breathitt Gray 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 78c2ecf20Sopenharmony_ci#include <linux/bitops.h> 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/irqdesc.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/** 208c2ecf20Sopenharmony_ci * struct idio_16_gpio_reg - GPIO device registers structure 218c2ecf20Sopenharmony_ci * @out0_7: Read: FET Drive Outputs 0-7 228c2ecf20Sopenharmony_ci * Write: FET Drive Outputs 0-7 238c2ecf20Sopenharmony_ci * @in0_7: Read: Isolated Inputs 0-7 248c2ecf20Sopenharmony_ci * Write: Clear Interrupt 258c2ecf20Sopenharmony_ci * @irq_ctl: Read: Enable IRQ 268c2ecf20Sopenharmony_ci * Write: Disable IRQ 278c2ecf20Sopenharmony_ci * @filter_ctl: Read: Activate Input Filters 0-15 288c2ecf20Sopenharmony_ci * Write: Deactivate Input Filters 0-15 298c2ecf20Sopenharmony_ci * @out8_15: Read: FET Drive Outputs 8-15 308c2ecf20Sopenharmony_ci * Write: FET Drive Outputs 8-15 318c2ecf20Sopenharmony_ci * @in8_15: Read: Isolated Inputs 8-15 328c2ecf20Sopenharmony_ci * Write: Unused 338c2ecf20Sopenharmony_ci * @irq_status: Read: Interrupt status 348c2ecf20Sopenharmony_ci * Write: Unused 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistruct idio_16_gpio_reg { 378c2ecf20Sopenharmony_ci u8 out0_7; 388c2ecf20Sopenharmony_ci u8 in0_7; 398c2ecf20Sopenharmony_ci u8 irq_ctl; 408c2ecf20Sopenharmony_ci u8 filter_ctl; 418c2ecf20Sopenharmony_ci u8 out8_15; 428c2ecf20Sopenharmony_ci u8 in8_15; 438c2ecf20Sopenharmony_ci u8 irq_status; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/** 478c2ecf20Sopenharmony_ci * struct idio_16_gpio - GPIO device private data structure 488c2ecf20Sopenharmony_ci * @chip: instance of the gpio_chip 498c2ecf20Sopenharmony_ci * @lock: synchronization lock to prevent I/O race conditions 508c2ecf20Sopenharmony_ci * @reg: I/O address offset for the GPIO device registers 518c2ecf20Sopenharmony_ci * @irq_mask: I/O bits affected by interrupts 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistruct idio_16_gpio { 548c2ecf20Sopenharmony_ci struct gpio_chip chip; 558c2ecf20Sopenharmony_ci raw_spinlock_t lock; 568c2ecf20Sopenharmony_ci struct idio_16_gpio_reg __iomem *reg; 578c2ecf20Sopenharmony_ci unsigned long irq_mask; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int idio_16_gpio_get_direction(struct gpio_chip *chip, 618c2ecf20Sopenharmony_ci unsigned int offset) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci if (offset > 15) 648c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int idio_16_gpio_direction_input(struct gpio_chip *chip, 708c2ecf20Sopenharmony_ci unsigned int offset) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int idio_16_gpio_direction_output(struct gpio_chip *chip, 768c2ecf20Sopenharmony_ci unsigned int offset, int value) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci chip->set(chip, offset, value); 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 858c2ecf20Sopenharmony_ci unsigned long mask = BIT(offset); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (offset < 8) 888c2ecf20Sopenharmony_ci return !!(ioread8(&idio16gpio->reg->out0_7) & mask); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (offset < 16) 918c2ecf20Sopenharmony_ci return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8)); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (offset < 24) 948c2ecf20Sopenharmony_ci return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16)); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24)); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int idio_16_gpio_get_multiple(struct gpio_chip *chip, 1008c2ecf20Sopenharmony_ci unsigned long *mask, unsigned long *bits) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 1038c2ecf20Sopenharmony_ci unsigned long offset; 1048c2ecf20Sopenharmony_ci unsigned long gpio_mask; 1058c2ecf20Sopenharmony_ci void __iomem *ports[] = { 1068c2ecf20Sopenharmony_ci &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15, 1078c2ecf20Sopenharmony_ci &idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15, 1088c2ecf20Sopenharmony_ci }; 1098c2ecf20Sopenharmony_ci void __iomem *port_addr; 1108c2ecf20Sopenharmony_ci unsigned long port_state; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* clear bits array to a clean slate */ 1138c2ecf20Sopenharmony_ci bitmap_zero(bits, chip->ngpio); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { 1168c2ecf20Sopenharmony_ci port_addr = ports[offset / 8]; 1178c2ecf20Sopenharmony_ci port_state = ioread8(port_addr) & gpio_mask; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci bitmap_set_value8(bits, port_state, offset); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, 1268c2ecf20Sopenharmony_ci int value) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 1298c2ecf20Sopenharmony_ci unsigned int mask = BIT(offset); 1308c2ecf20Sopenharmony_ci void __iomem *base; 1318c2ecf20Sopenharmony_ci unsigned long flags; 1328c2ecf20Sopenharmony_ci unsigned int out_state; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (offset > 15) 1358c2ecf20Sopenharmony_ci return; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (offset > 7) { 1388c2ecf20Sopenharmony_ci mask >>= 8; 1398c2ecf20Sopenharmony_ci base = &idio16gpio->reg->out8_15; 1408c2ecf20Sopenharmony_ci } else 1418c2ecf20Sopenharmony_ci base = &idio16gpio->reg->out0_7; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&idio16gpio->lock, flags); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (value) 1468c2ecf20Sopenharmony_ci out_state = ioread8(base) | mask; 1478c2ecf20Sopenharmony_ci else 1488c2ecf20Sopenharmony_ci out_state = ioread8(base) & ~mask; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci iowrite8(out_state, base); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void idio_16_gpio_set_multiple(struct gpio_chip *chip, 1568c2ecf20Sopenharmony_ci unsigned long *mask, unsigned long *bits) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 1598c2ecf20Sopenharmony_ci unsigned long offset; 1608c2ecf20Sopenharmony_ci unsigned long gpio_mask; 1618c2ecf20Sopenharmony_ci void __iomem *ports[] = { 1628c2ecf20Sopenharmony_ci &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15, 1638c2ecf20Sopenharmony_ci }; 1648c2ecf20Sopenharmony_ci size_t index; 1658c2ecf20Sopenharmony_ci void __iomem *port_addr; 1668c2ecf20Sopenharmony_ci unsigned long bitmask; 1678c2ecf20Sopenharmony_ci unsigned long flags; 1688c2ecf20Sopenharmony_ci unsigned long out_state; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { 1718c2ecf20Sopenharmony_ci index = offset / 8; 1728c2ecf20Sopenharmony_ci port_addr = ports[index]; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci bitmask = bitmap_get_value8(bits, offset) & gpio_mask; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&idio16gpio->lock, flags); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci out_state = ioread8(port_addr) & ~gpio_mask; 1798c2ecf20Sopenharmony_ci out_state |= bitmask; 1808c2ecf20Sopenharmony_ci iowrite8(out_state, port_addr); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void idio_16_irq_ack(struct irq_data *data) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void idio_16_irq_mask(struct irq_data *data) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 1938c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 1948c2ecf20Sopenharmony_ci const unsigned long mask = BIT(irqd_to_hwirq(data)); 1958c2ecf20Sopenharmony_ci unsigned long flags; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci idio16gpio->irq_mask &= ~mask; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!idio16gpio->irq_mask) { 2008c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&idio16gpio->lock, flags); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci iowrite8(0, &idio16gpio->reg->irq_ctl); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void idio_16_irq_unmask(struct irq_data *data) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 2118c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 2128c2ecf20Sopenharmony_ci const unsigned long mask = BIT(irqd_to_hwirq(data)); 2138c2ecf20Sopenharmony_ci const unsigned long prev_irq_mask = idio16gpio->irq_mask; 2148c2ecf20Sopenharmony_ci unsigned long flags; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci idio16gpio->irq_mask |= mask; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (!prev_irq_mask) { 2198c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&idio16gpio->lock, flags); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ioread8(&idio16gpio->reg->irq_ctl); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci /* The only valid irq types are none and both-edges */ 2308c2ecf20Sopenharmony_ci if (flow_type != IRQ_TYPE_NONE && 2318c2ecf20Sopenharmony_ci (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 2328c2ecf20Sopenharmony_ci return -EINVAL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic struct irq_chip idio_16_irqchip = { 2388c2ecf20Sopenharmony_ci .name = "pci-idio-16", 2398c2ecf20Sopenharmony_ci .irq_ack = idio_16_irq_ack, 2408c2ecf20Sopenharmony_ci .irq_mask = idio_16_irq_mask, 2418c2ecf20Sopenharmony_ci .irq_unmask = idio_16_irq_unmask, 2428c2ecf20Sopenharmony_ci .irq_set_type = idio_16_irq_set_type 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic irqreturn_t idio_16_irq_handler(int irq, void *dev_id) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = dev_id; 2488c2ecf20Sopenharmony_ci unsigned int irq_status; 2498c2ecf20Sopenharmony_ci struct gpio_chip *const chip = &idio16gpio->chip; 2508c2ecf20Sopenharmony_ci int gpio; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci raw_spin_lock(&idio16gpio->lock); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci irq_status = ioread8(&idio16gpio->reg->irq_status); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci raw_spin_unlock(&idio16gpio->lock); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Make sure our device generated IRQ */ 2598c2ecf20Sopenharmony_ci if (!(irq_status & 0x3) || !(irq_status & 0x4)) 2608c2ecf20Sopenharmony_ci return IRQ_NONE; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) 2638c2ecf20Sopenharmony_ci generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio)); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci raw_spin_lock(&idio16gpio->lock); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Clear interrupt */ 2688c2ecf20Sopenharmony_ci iowrite8(0, &idio16gpio->reg->in0_7); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci raw_spin_unlock(&idio16gpio->lock); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci#define IDIO_16_NGPIO 32 2768c2ecf20Sopenharmony_cistatic const char *idio_16_names[IDIO_16_NGPIO] = { 2778c2ecf20Sopenharmony_ci "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 2788c2ecf20Sopenharmony_ci "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 2798c2ecf20Sopenharmony_ci "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 2808c2ecf20Sopenharmony_ci "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int idio_16_irq_init_hw(struct gpio_chip *gc) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Disable IRQ by default and clear any pending interrupt */ 2888c2ecf20Sopenharmony_ci iowrite8(0, &idio16gpio->reg->irq_ctl); 2898c2ecf20Sopenharmony_ci iowrite8(0, &idio16gpio->reg->in0_7); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct device *const dev = &pdev->dev; 2978c2ecf20Sopenharmony_ci struct idio_16_gpio *idio16gpio; 2988c2ecf20Sopenharmony_ci int err; 2998c2ecf20Sopenharmony_ci const size_t pci_bar_index = 2; 3008c2ecf20Sopenharmony_ci const char *const name = pci_name(pdev); 3018c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); 3048c2ecf20Sopenharmony_ci if (!idio16gpio) 3058c2ecf20Sopenharmony_ci return -ENOMEM; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci err = pcim_enable_device(pdev); 3088c2ecf20Sopenharmony_ci if (err) { 3098c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable PCI device (%d)\n", err); 3108c2ecf20Sopenharmony_ci return err; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); 3148c2ecf20Sopenharmony_ci if (err) { 3158c2ecf20Sopenharmony_ci dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 3168c2ecf20Sopenharmony_ci return err; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Deactivate input filters */ 3228c2ecf20Sopenharmony_ci iowrite8(0, &idio16gpio->reg->filter_ctl); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci idio16gpio->chip.label = name; 3258c2ecf20Sopenharmony_ci idio16gpio->chip.parent = dev; 3268c2ecf20Sopenharmony_ci idio16gpio->chip.owner = THIS_MODULE; 3278c2ecf20Sopenharmony_ci idio16gpio->chip.base = -1; 3288c2ecf20Sopenharmony_ci idio16gpio->chip.ngpio = IDIO_16_NGPIO; 3298c2ecf20Sopenharmony_ci idio16gpio->chip.names = idio_16_names; 3308c2ecf20Sopenharmony_ci idio16gpio->chip.get_direction = idio_16_gpio_get_direction; 3318c2ecf20Sopenharmony_ci idio16gpio->chip.direction_input = idio_16_gpio_direction_input; 3328c2ecf20Sopenharmony_ci idio16gpio->chip.direction_output = idio_16_gpio_direction_output; 3338c2ecf20Sopenharmony_ci idio16gpio->chip.get = idio_16_gpio_get; 3348c2ecf20Sopenharmony_ci idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple; 3358c2ecf20Sopenharmony_ci idio16gpio->chip.set = idio_16_gpio_set; 3368c2ecf20Sopenharmony_ci idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci girq = &idio16gpio->chip.irq; 3398c2ecf20Sopenharmony_ci girq->chip = &idio_16_irqchip; 3408c2ecf20Sopenharmony_ci /* This will let us handle the parent IRQ in the driver */ 3418c2ecf20Sopenharmony_ci girq->parent_handler = NULL; 3428c2ecf20Sopenharmony_ci girq->num_parents = 0; 3438c2ecf20Sopenharmony_ci girq->parents = NULL; 3448c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 3458c2ecf20Sopenharmony_ci girq->handler = handle_edge_irq; 3468c2ecf20Sopenharmony_ci girq->init_hw = idio_16_irq_init_hw; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci raw_spin_lock_init(&idio16gpio->lock); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); 3518c2ecf20Sopenharmony_ci if (err) { 3528c2ecf20Sopenharmony_ci dev_err(dev, "GPIO registering failed (%d)\n", err); 3538c2ecf20Sopenharmony_ci return err; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED, 3578c2ecf20Sopenharmony_ci name, idio16gpio); 3588c2ecf20Sopenharmony_ci if (err) { 3598c2ecf20Sopenharmony_ci dev_err(dev, "IRQ handler registering failed (%d)\n", err); 3608c2ecf20Sopenharmony_ci return err; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const struct pci_device_id idio_16_pci_dev_id[] = { 3678c2ecf20Sopenharmony_ci { PCI_DEVICE(0x494F, 0x0DC8) }, { 0 } 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic struct pci_driver idio_16_driver = { 3728c2ecf20Sopenharmony_ci .name = "pci-idio-16", 3738c2ecf20Sopenharmony_ci .id_table = idio_16_pci_dev_id, 3748c2ecf20Sopenharmony_ci .probe = idio_16_probe 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cimodule_pci_driver(idio_16_driver); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ciMODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 3808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver"); 3818c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 382