11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21ceacea2SWilliam Breathitt Gray /* 31ceacea2SWilliam Breathitt Gray * GPIO driver for the ACCES 104-IDIO-16 family 41ceacea2SWilliam Breathitt Gray * Copyright (C) 2015 William Breathitt Gray 51ceacea2SWilliam Breathitt Gray * 686ea8a95SWilliam Breathitt Gray * This driver supports the following ACCES devices: 104-IDIO-16, 786ea8a95SWilliam Breathitt Gray * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8. 81ceacea2SWilliam Breathitt Gray */ 9*c4ec384cSWilliam Breathitt Gray #include <linux/bitmap.h> 101ceacea2SWilliam Breathitt Gray #include <linux/device.h> 111ceacea2SWilliam Breathitt Gray #include <linux/errno.h> 121ceacea2SWilliam Breathitt Gray #include <linux/gpio/driver.h> 131ceacea2SWilliam Breathitt Gray #include <linux/io.h> 141ceacea2SWilliam Breathitt Gray #include <linux/ioport.h> 15a1184147SWilliam Breathitt Gray #include <linux/interrupt.h> 16a1184147SWilliam Breathitt Gray #include <linux/irqdesc.h> 1786ea8a95SWilliam Breathitt Gray #include <linux/isa.h> 181ceacea2SWilliam Breathitt Gray #include <linux/kernel.h> 191ceacea2SWilliam Breathitt Gray #include <linux/module.h> 201ceacea2SWilliam Breathitt Gray #include <linux/moduleparam.h> 211ceacea2SWilliam Breathitt Gray #include <linux/spinlock.h> 22cc442e4dSWilliam Breathitt Gray #include <linux/types.h> 231ceacea2SWilliam Breathitt Gray 24*c4ec384cSWilliam Breathitt Gray #include "gpio-idio-16.h" 25*c4ec384cSWilliam Breathitt Gray 2686ea8a95SWilliam Breathitt Gray #define IDIO_16_EXTENT 8 2786ea8a95SWilliam Breathitt Gray #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT) 2886ea8a95SWilliam Breathitt Gray 2986ea8a95SWilliam Breathitt Gray static unsigned int base[MAX_NUM_IDIO_16]; 3086ea8a95SWilliam Breathitt Gray static unsigned int num_idio_16; 31d759f906SDavid Howells module_param_hw_array(base, uint, ioport, &num_idio_16, 0); 3286ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses"); 3386ea8a95SWilliam Breathitt Gray 3486ea8a95SWilliam Breathitt Gray static unsigned int irq[MAX_NUM_IDIO_16]; 35c6074f3fSWilliam Breathitt Gray static unsigned int num_irq; 36c6074f3fSWilliam Breathitt Gray module_param_hw_array(irq, uint, irq, &num_irq, 0); 3786ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers"); 381ceacea2SWilliam Breathitt Gray 391ceacea2SWilliam Breathitt Gray /** 401ceacea2SWilliam Breathitt Gray * struct idio_16_gpio - GPIO device private data structure 411ceacea2SWilliam Breathitt Gray * @chip: instance of the gpio_chip 42a1184147SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 43a1184147SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 44cc442e4dSWilliam Breathitt Gray * @reg: I/O address offset for the device registers 45*c4ec384cSWilliam Breathitt Gray * @state: ACCES IDIO-16 device state 461ceacea2SWilliam Breathitt Gray */ 471ceacea2SWilliam Breathitt Gray struct idio_16_gpio { 481ceacea2SWilliam Breathitt Gray struct gpio_chip chip; 493906e808SJulia Cartwright raw_spinlock_t lock; 50a1184147SWilliam Breathitt Gray unsigned long irq_mask; 51*c4ec384cSWilliam Breathitt Gray struct idio_16 __iomem *reg; 52*c4ec384cSWilliam Breathitt Gray struct idio_16_state state; 531ceacea2SWilliam Breathitt Gray }; 541ceacea2SWilliam Breathitt Gray 55cc0f53d2SNavin Sankar Velliangiri static int idio_16_gpio_get_direction(struct gpio_chip *chip, 56cc0f53d2SNavin Sankar Velliangiri unsigned int offset) 571ceacea2SWilliam Breathitt Gray { 58*c4ec384cSWilliam Breathitt Gray if (idio_16_get_direction(offset)) 59e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 601ceacea2SWilliam Breathitt Gray 61e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 621ceacea2SWilliam Breathitt Gray } 631ceacea2SWilliam Breathitt Gray 64cc0f53d2SNavin Sankar Velliangiri static int idio_16_gpio_direction_input(struct gpio_chip *chip, 65cc0f53d2SNavin Sankar Velliangiri unsigned int offset) 661ceacea2SWilliam Breathitt Gray { 671ceacea2SWilliam Breathitt Gray return 0; 681ceacea2SWilliam Breathitt Gray } 691ceacea2SWilliam Breathitt Gray 701ceacea2SWilliam Breathitt Gray static int idio_16_gpio_direction_output(struct gpio_chip *chip, 71cc0f53d2SNavin Sankar Velliangiri unsigned int offset, int value) 721ceacea2SWilliam Breathitt Gray { 731ceacea2SWilliam Breathitt Gray chip->set(chip, offset, value); 741ceacea2SWilliam Breathitt Gray return 0; 751ceacea2SWilliam Breathitt Gray } 761ceacea2SWilliam Breathitt Gray 77cc0f53d2SNavin Sankar Velliangiri static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) 781ceacea2SWilliam Breathitt Gray { 79d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 801ceacea2SWilliam Breathitt Gray 81*c4ec384cSWilliam Breathitt Gray return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset); 821ceacea2SWilliam Breathitt Gray } 831ceacea2SWilliam Breathitt Gray 8415f59cffSWilliam Breathitt Gray static int idio_16_gpio_get_multiple(struct gpio_chip *chip, 8515f59cffSWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 8615f59cffSWilliam Breathitt Gray { 8715f59cffSWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 8815f59cffSWilliam Breathitt Gray 89*c4ec384cSWilliam Breathitt Gray idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits); 9015f59cffSWilliam Breathitt Gray 9115f59cffSWilliam Breathitt Gray return 0; 9215f59cffSWilliam Breathitt Gray } 9315f59cffSWilliam Breathitt Gray 94cc0f53d2SNavin Sankar Velliangiri static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, 95cc0f53d2SNavin Sankar Velliangiri int value) 961ceacea2SWilliam Breathitt Gray { 97d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 981ceacea2SWilliam Breathitt Gray 99*c4ec384cSWilliam Breathitt Gray idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value); 1001ceacea2SWilliam Breathitt Gray } 1011ceacea2SWilliam Breathitt Gray 1029d7ae812SWilliam Breathitt Gray static void idio_16_gpio_set_multiple(struct gpio_chip *chip, 1039d7ae812SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 1049d7ae812SWilliam Breathitt Gray { 1059d7ae812SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 1069d7ae812SWilliam Breathitt Gray 107*c4ec384cSWilliam Breathitt Gray idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits); 1089d7ae812SWilliam Breathitt Gray } 1099d7ae812SWilliam Breathitt Gray 110a1184147SWilliam Breathitt Gray static void idio_16_irq_ack(struct irq_data *data) 111a1184147SWilliam Breathitt Gray { 112a1184147SWilliam Breathitt Gray } 113a1184147SWilliam Breathitt Gray 114a1184147SWilliam Breathitt Gray static void idio_16_irq_mask(struct irq_data *data) 115a1184147SWilliam Breathitt Gray { 116a1184147SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 117d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 118410a5041SWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 119a1184147SWilliam Breathitt Gray unsigned long flags; 120a1184147SWilliam Breathitt Gray 121410a5041SWilliam Breathitt Gray idio16gpio->irq_mask &= ~BIT(offset); 122410a5041SWilliam Breathitt Gray gpiochip_disable_irq(chip, offset); 123a1184147SWilliam Breathitt Gray 124a1184147SWilliam Breathitt Gray if (!idio16gpio->irq_mask) { 1253906e808SJulia Cartwright raw_spin_lock_irqsave(&idio16gpio->lock, flags); 126a1184147SWilliam Breathitt Gray 127cc442e4dSWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->irq_ctl); 128a1184147SWilliam Breathitt Gray 1293906e808SJulia Cartwright raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 130a1184147SWilliam Breathitt Gray } 131a1184147SWilliam Breathitt Gray } 132a1184147SWilliam Breathitt Gray 133a1184147SWilliam Breathitt Gray static void idio_16_irq_unmask(struct irq_data *data) 134a1184147SWilliam Breathitt Gray { 135a1184147SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 136d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 137410a5041SWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 138a1184147SWilliam Breathitt Gray const unsigned long prev_irq_mask = idio16gpio->irq_mask; 139a1184147SWilliam Breathitt Gray unsigned long flags; 140a1184147SWilliam Breathitt Gray 141410a5041SWilliam Breathitt Gray gpiochip_enable_irq(chip, offset); 142410a5041SWilliam Breathitt Gray idio16gpio->irq_mask |= BIT(offset); 143a1184147SWilliam Breathitt Gray 144a1184147SWilliam Breathitt Gray if (!prev_irq_mask) { 1453906e808SJulia Cartwright raw_spin_lock_irqsave(&idio16gpio->lock, flags); 146a1184147SWilliam Breathitt Gray 147cc442e4dSWilliam Breathitt Gray ioread8(&idio16gpio->reg->irq_ctl); 148a1184147SWilliam Breathitt Gray 1493906e808SJulia Cartwright raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 150a1184147SWilliam Breathitt Gray } 151a1184147SWilliam Breathitt Gray } 152a1184147SWilliam Breathitt Gray 153cc0f53d2SNavin Sankar Velliangiri static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type) 154a1184147SWilliam Breathitt Gray { 155a1184147SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 156a1184147SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 157a1184147SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 158a1184147SWilliam Breathitt Gray return -EINVAL; 159a1184147SWilliam Breathitt Gray 160a1184147SWilliam Breathitt Gray return 0; 161a1184147SWilliam Breathitt Gray } 162a1184147SWilliam Breathitt Gray 163410a5041SWilliam Breathitt Gray static const struct irq_chip idio_16_irqchip = { 164a1184147SWilliam Breathitt Gray .name = "104-idio-16", 165a1184147SWilliam Breathitt Gray .irq_ack = idio_16_irq_ack, 166a1184147SWilliam Breathitt Gray .irq_mask = idio_16_irq_mask, 167a1184147SWilliam Breathitt Gray .irq_unmask = idio_16_irq_unmask, 168410a5041SWilliam Breathitt Gray .irq_set_type = idio_16_irq_set_type, 169410a5041SWilliam Breathitt Gray .flags = IRQCHIP_IMMUTABLE, 170410a5041SWilliam Breathitt Gray GPIOCHIP_IRQ_RESOURCE_HELPERS, 171a1184147SWilliam Breathitt Gray }; 172a1184147SWilliam Breathitt Gray 173a1184147SWilliam Breathitt Gray static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) 174a1184147SWilliam Breathitt Gray { 175a1184147SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = dev_id; 176a1184147SWilliam Breathitt Gray struct gpio_chip *const chip = &idio16gpio->chip; 177a1184147SWilliam Breathitt Gray int gpio; 178a1184147SWilliam Breathitt Gray 179a1184147SWilliam Breathitt Gray for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) 180dbd1c54fSMarc Zyngier generic_handle_domain_irq(chip->irq.domain, gpio); 181a1184147SWilliam Breathitt Gray 1823906e808SJulia Cartwright raw_spin_lock(&idio16gpio->lock); 18312b61c9dSWilliam Breathitt Gray 184cc442e4dSWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->in0_7); 18512b61c9dSWilliam Breathitt Gray 1863906e808SJulia Cartwright raw_spin_unlock(&idio16gpio->lock); 18712b61c9dSWilliam Breathitt Gray 188a1184147SWilliam Breathitt Gray return IRQ_HANDLED; 189a1184147SWilliam Breathitt Gray } 190a1184147SWilliam Breathitt Gray 191e0af4b5eSWilliam Breathitt Gray #define IDIO_16_NGPIO 32 192e0af4b5eSWilliam Breathitt Gray static const char *idio_16_names[IDIO_16_NGPIO] = { 193e0af4b5eSWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 194e0af4b5eSWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 195e0af4b5eSWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 196e0af4b5eSWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" 197e0af4b5eSWilliam Breathitt Gray }; 198e0af4b5eSWilliam Breathitt Gray 19982e4613dSLinus Walleij static int idio_16_irq_init_hw(struct gpio_chip *gc) 20082e4613dSLinus Walleij { 20182e4613dSLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc); 20282e4613dSLinus Walleij 20382e4613dSLinus Walleij /* Disable IRQ by default */ 204cc442e4dSWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->irq_ctl); 205cc442e4dSWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->in0_7); 20682e4613dSLinus Walleij 20782e4613dSLinus Walleij return 0; 20882e4613dSLinus Walleij } 20982e4613dSLinus Walleij 21086ea8a95SWilliam Breathitt Gray static int idio_16_probe(struct device *dev, unsigned int id) 2111ceacea2SWilliam Breathitt Gray { 2121ceacea2SWilliam Breathitt Gray struct idio_16_gpio *idio16gpio; 2136e0171b4SWilliam Breathitt Gray const char *const name = dev_name(dev); 21482e4613dSLinus Walleij struct gpio_irq_chip *girq; 2151ceacea2SWilliam Breathitt Gray int err; 2161ceacea2SWilliam Breathitt Gray 2171ceacea2SWilliam Breathitt Gray idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); 2181ceacea2SWilliam Breathitt Gray if (!idio16gpio) 2191ceacea2SWilliam Breathitt Gray return -ENOMEM; 2201ceacea2SWilliam Breathitt Gray 22186ea8a95SWilliam Breathitt Gray if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) { 222cb32389cSWilliam Breathitt Gray dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 22386ea8a95SWilliam Breathitt Gray base[id], base[id] + IDIO_16_EXTENT); 224cb32389cSWilliam Breathitt Gray return -EBUSY; 2251ceacea2SWilliam Breathitt Gray } 2261ceacea2SWilliam Breathitt Gray 227cc442e4dSWilliam Breathitt Gray idio16gpio->reg = devm_ioport_map(dev, base[id], IDIO_16_EXTENT); 228cc442e4dSWilliam Breathitt Gray if (!idio16gpio->reg) 229e0a574efSWilliam Breathitt Gray return -ENOMEM; 230e0a574efSWilliam Breathitt Gray 2316e0171b4SWilliam Breathitt Gray idio16gpio->chip.label = name; 23258383c78SLinus Walleij idio16gpio->chip.parent = dev; 2331ceacea2SWilliam Breathitt Gray idio16gpio->chip.owner = THIS_MODULE; 2341ceacea2SWilliam Breathitt Gray idio16gpio->chip.base = -1; 235e0af4b5eSWilliam Breathitt Gray idio16gpio->chip.ngpio = IDIO_16_NGPIO; 236e0af4b5eSWilliam Breathitt Gray idio16gpio->chip.names = idio_16_names; 2371ceacea2SWilliam Breathitt Gray idio16gpio->chip.get_direction = idio_16_gpio_get_direction; 2381ceacea2SWilliam Breathitt Gray idio16gpio->chip.direction_input = idio_16_gpio_direction_input; 2391ceacea2SWilliam Breathitt Gray idio16gpio->chip.direction_output = idio_16_gpio_direction_output; 2401ceacea2SWilliam Breathitt Gray idio16gpio->chip.get = idio_16_gpio_get; 24115f59cffSWilliam Breathitt Gray idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple; 2421ceacea2SWilliam Breathitt Gray idio16gpio->chip.set = idio_16_gpio_set; 2439d7ae812SWilliam Breathitt Gray idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; 244*c4ec384cSWilliam Breathitt Gray 245*c4ec384cSWilliam Breathitt Gray idio_16_state_init(&idio16gpio->state); 246*c4ec384cSWilliam Breathitt Gray /* FET off states are represented by bit values of "1" */ 247*c4ec384cSWilliam Breathitt Gray bitmap_fill(idio16gpio->state.out_state, IDIO_16_NOUT); 2481ceacea2SWilliam Breathitt Gray 24982e4613dSLinus Walleij girq = &idio16gpio->chip.irq; 250410a5041SWilliam Breathitt Gray gpio_irq_chip_set_chip(girq, &idio_16_irqchip); 25182e4613dSLinus Walleij /* This will let us handle the parent IRQ in the driver */ 25282e4613dSLinus Walleij girq->parent_handler = NULL; 25382e4613dSLinus Walleij girq->num_parents = 0; 25482e4613dSLinus Walleij girq->parents = NULL; 25582e4613dSLinus Walleij girq->default_type = IRQ_TYPE_NONE; 25682e4613dSLinus Walleij girq->handler = handle_edge_irq; 25782e4613dSLinus Walleij girq->init_hw = idio_16_irq_init_hw; 25882e4613dSLinus Walleij 2593906e808SJulia Cartwright raw_spin_lock_init(&idio16gpio->lock); 2601ceacea2SWilliam Breathitt Gray 261837143d3SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); 2621ceacea2SWilliam Breathitt Gray if (err) { 2631ceacea2SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 264cb32389cSWilliam Breathitt Gray return err; 2651ceacea2SWilliam Breathitt Gray } 2661ceacea2SWilliam Breathitt Gray 267837143d3SWilliam Breathitt Gray err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name, 268837143d3SWilliam Breathitt Gray idio16gpio); 269837143d3SWilliam Breathitt Gray if (err) { 270837143d3SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 271837143d3SWilliam Breathitt Gray return err; 272837143d3SWilliam Breathitt Gray } 2731ceacea2SWilliam Breathitt Gray 2741ceacea2SWilliam Breathitt Gray return 0; 2751ceacea2SWilliam Breathitt Gray } 2761ceacea2SWilliam Breathitt Gray 27786ea8a95SWilliam Breathitt Gray static struct isa_driver idio_16_driver = { 27886ea8a95SWilliam Breathitt Gray .probe = idio_16_probe, 2791ceacea2SWilliam Breathitt Gray .driver = { 2801ceacea2SWilliam Breathitt Gray .name = "104-idio-16" 2811ceacea2SWilliam Breathitt Gray }, 2821ceacea2SWilliam Breathitt Gray }; 2831ceacea2SWilliam Breathitt Gray 284c6074f3fSWilliam Breathitt Gray module_isa_driver_with_irq(idio_16_driver, num_idio_16, num_irq); 2851ceacea2SWilliam Breathitt Gray 2861ceacea2SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 2871ceacea2SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); 28822aeddb5SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 289*c4ec384cSWilliam Breathitt Gray MODULE_IMPORT_NS(GPIO_IDIO_16); 290