11ceacea2SWilliam Breathitt Gray /* 21ceacea2SWilliam Breathitt Gray * GPIO driver for the ACCES 104-IDIO-16 family 31ceacea2SWilliam Breathitt Gray * Copyright (C) 2015 William Breathitt Gray 41ceacea2SWilliam Breathitt Gray * 51ceacea2SWilliam Breathitt Gray * This program is free software; you can redistribute it and/or modify 61ceacea2SWilliam Breathitt Gray * it under the terms of the GNU General Public License, version 2, as 71ceacea2SWilliam Breathitt Gray * published by the Free Software Foundation. 81ceacea2SWilliam Breathitt Gray * 91ceacea2SWilliam Breathitt Gray * This program is distributed in the hope that it will be useful, but 101ceacea2SWilliam Breathitt Gray * WITHOUT ANY WARRANTY; without even the implied warranty of 111ceacea2SWilliam Breathitt Gray * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 121ceacea2SWilliam Breathitt Gray * General Public License for more details. 1386ea8a95SWilliam Breathitt Gray * 1486ea8a95SWilliam Breathitt Gray * This driver supports the following ACCES devices: 104-IDIO-16, 1586ea8a95SWilliam Breathitt Gray * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8. 161ceacea2SWilliam Breathitt Gray */ 17a1184147SWilliam Breathitt Gray #include <linux/bitops.h> 181ceacea2SWilliam Breathitt Gray #include <linux/device.h> 191ceacea2SWilliam Breathitt Gray #include <linux/errno.h> 201ceacea2SWilliam Breathitt Gray #include <linux/gpio/driver.h> 211ceacea2SWilliam Breathitt Gray #include <linux/io.h> 221ceacea2SWilliam Breathitt Gray #include <linux/ioport.h> 23a1184147SWilliam Breathitt Gray #include <linux/interrupt.h> 24a1184147SWilliam Breathitt Gray #include <linux/irqdesc.h> 2586ea8a95SWilliam Breathitt Gray #include <linux/isa.h> 261ceacea2SWilliam Breathitt Gray #include <linux/kernel.h> 271ceacea2SWilliam Breathitt Gray #include <linux/module.h> 281ceacea2SWilliam Breathitt Gray #include <linux/moduleparam.h> 291ceacea2SWilliam Breathitt Gray #include <linux/spinlock.h> 301ceacea2SWilliam Breathitt Gray 3186ea8a95SWilliam Breathitt Gray #define IDIO_16_EXTENT 8 3286ea8a95SWilliam Breathitt Gray #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT) 3386ea8a95SWilliam Breathitt Gray 3486ea8a95SWilliam Breathitt Gray static unsigned int base[MAX_NUM_IDIO_16]; 3586ea8a95SWilliam Breathitt Gray static unsigned int num_idio_16; 36d759f906SDavid Howells module_param_hw_array(base, uint, ioport, &num_idio_16, 0); 3786ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses"); 3886ea8a95SWilliam Breathitt Gray 3986ea8a95SWilliam Breathitt Gray static unsigned int irq[MAX_NUM_IDIO_16]; 40d759f906SDavid Howells module_param_hw_array(irq, uint, irq, NULL, 0); 4186ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers"); 421ceacea2SWilliam Breathitt Gray 431ceacea2SWilliam Breathitt Gray /** 441ceacea2SWilliam Breathitt Gray * struct idio_16_gpio - GPIO device private data structure 451ceacea2SWilliam Breathitt Gray * @chip: instance of the gpio_chip 46a1184147SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 47a1184147SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 481ceacea2SWilliam Breathitt Gray * @base: base port address of the GPIO device 491ceacea2SWilliam Breathitt Gray * @out_state: output bits state 501ceacea2SWilliam Breathitt Gray */ 511ceacea2SWilliam Breathitt Gray struct idio_16_gpio { 521ceacea2SWilliam Breathitt Gray struct gpio_chip chip; 531ceacea2SWilliam Breathitt Gray spinlock_t lock; 54a1184147SWilliam Breathitt Gray unsigned long irq_mask; 551ceacea2SWilliam Breathitt Gray unsigned base; 561ceacea2SWilliam Breathitt Gray unsigned out_state; 571ceacea2SWilliam Breathitt Gray }; 581ceacea2SWilliam Breathitt Gray 591ceacea2SWilliam Breathitt Gray static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 601ceacea2SWilliam Breathitt Gray { 611ceacea2SWilliam Breathitt Gray if (offset > 15) 621ceacea2SWilliam Breathitt Gray return 1; 631ceacea2SWilliam Breathitt Gray 641ceacea2SWilliam Breathitt Gray return 0; 651ceacea2SWilliam Breathitt Gray } 661ceacea2SWilliam Breathitt Gray 671ceacea2SWilliam Breathitt Gray static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 681ceacea2SWilliam Breathitt Gray { 691ceacea2SWilliam Breathitt Gray return 0; 701ceacea2SWilliam Breathitt Gray } 711ceacea2SWilliam Breathitt Gray 721ceacea2SWilliam Breathitt Gray static int idio_16_gpio_direction_output(struct gpio_chip *chip, 731ceacea2SWilliam Breathitt Gray unsigned offset, int value) 741ceacea2SWilliam Breathitt Gray { 751ceacea2SWilliam Breathitt Gray chip->set(chip, offset, value); 761ceacea2SWilliam Breathitt Gray return 0; 771ceacea2SWilliam Breathitt Gray } 781ceacea2SWilliam Breathitt Gray 791ceacea2SWilliam Breathitt Gray static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset) 801ceacea2SWilliam Breathitt Gray { 81d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 826e0171b4SWilliam Breathitt Gray const unsigned mask = BIT(offset-16); 831ceacea2SWilliam Breathitt Gray 841ceacea2SWilliam Breathitt Gray if (offset < 16) 851ceacea2SWilliam Breathitt Gray return -EINVAL; 861ceacea2SWilliam Breathitt Gray 871ceacea2SWilliam Breathitt Gray if (offset < 24) 886e0171b4SWilliam Breathitt Gray return !!(inb(idio16gpio->base + 1) & mask); 891ceacea2SWilliam Breathitt Gray 906e0171b4SWilliam Breathitt Gray return !!(inb(idio16gpio->base + 5) & (mask>>8)); 911ceacea2SWilliam Breathitt Gray } 921ceacea2SWilliam Breathitt Gray 931ceacea2SWilliam Breathitt Gray static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 941ceacea2SWilliam Breathitt Gray { 95d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 966e0171b4SWilliam Breathitt Gray const unsigned mask = BIT(offset); 971ceacea2SWilliam Breathitt Gray unsigned long flags; 981ceacea2SWilliam Breathitt Gray 991ceacea2SWilliam Breathitt Gray if (offset > 15) 1001ceacea2SWilliam Breathitt Gray return; 1011ceacea2SWilliam Breathitt Gray 1021ceacea2SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 1031ceacea2SWilliam Breathitt Gray 1041ceacea2SWilliam Breathitt Gray if (value) 1056e0171b4SWilliam Breathitt Gray idio16gpio->out_state |= mask; 1061ceacea2SWilliam Breathitt Gray else 1076e0171b4SWilliam Breathitt Gray idio16gpio->out_state &= ~mask; 1081ceacea2SWilliam Breathitt Gray 1091ceacea2SWilliam Breathitt Gray if (offset > 7) 1101ceacea2SWilliam Breathitt Gray outb(idio16gpio->out_state >> 8, idio16gpio->base + 4); 1111ceacea2SWilliam Breathitt Gray else 1121ceacea2SWilliam Breathitt Gray outb(idio16gpio->out_state, idio16gpio->base); 1131ceacea2SWilliam Breathitt Gray 1141ceacea2SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 1151ceacea2SWilliam Breathitt Gray } 1161ceacea2SWilliam Breathitt Gray 1179d7ae812SWilliam Breathitt Gray static void idio_16_gpio_set_multiple(struct gpio_chip *chip, 1189d7ae812SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 1199d7ae812SWilliam Breathitt Gray { 1209d7ae812SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 1219d7ae812SWilliam Breathitt Gray unsigned long flags; 1229d7ae812SWilliam Breathitt Gray 1239d7ae812SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 1249d7ae812SWilliam Breathitt Gray 1259d7ae812SWilliam Breathitt Gray idio16gpio->out_state &= ~*mask; 1269d7ae812SWilliam Breathitt Gray idio16gpio->out_state |= *mask & *bits; 1279d7ae812SWilliam Breathitt Gray 1289d7ae812SWilliam Breathitt Gray if (*mask & 0xFF) 1299d7ae812SWilliam Breathitt Gray outb(idio16gpio->out_state, idio16gpio->base); 1309d7ae812SWilliam Breathitt Gray if ((*mask >> 8) & 0xFF) 1319d7ae812SWilliam Breathitt Gray outb(idio16gpio->out_state >> 8, idio16gpio->base + 4); 1329d7ae812SWilliam Breathitt Gray 1339d7ae812SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 1349d7ae812SWilliam Breathitt Gray } 1359d7ae812SWilliam Breathitt Gray 136a1184147SWilliam Breathitt Gray static void idio_16_irq_ack(struct irq_data *data) 137a1184147SWilliam Breathitt Gray { 138a1184147SWilliam Breathitt Gray } 139a1184147SWilliam Breathitt Gray 140a1184147SWilliam Breathitt Gray static void idio_16_irq_mask(struct irq_data *data) 141a1184147SWilliam Breathitt Gray { 142a1184147SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 143d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 144a1184147SWilliam Breathitt Gray const unsigned long mask = BIT(irqd_to_hwirq(data)); 145a1184147SWilliam Breathitt Gray unsigned long flags; 146a1184147SWilliam Breathitt Gray 147a1184147SWilliam Breathitt Gray idio16gpio->irq_mask &= ~mask; 148a1184147SWilliam Breathitt Gray 149a1184147SWilliam Breathitt Gray if (!idio16gpio->irq_mask) { 150a1184147SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 151a1184147SWilliam Breathitt Gray 152a1184147SWilliam Breathitt Gray outb(0, idio16gpio->base + 2); 153a1184147SWilliam Breathitt Gray 154a1184147SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 155a1184147SWilliam Breathitt Gray } 156a1184147SWilliam Breathitt Gray } 157a1184147SWilliam Breathitt Gray 158a1184147SWilliam Breathitt Gray static void idio_16_irq_unmask(struct irq_data *data) 159a1184147SWilliam Breathitt Gray { 160a1184147SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 161d602ae90SLinus Walleij struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 162a1184147SWilliam Breathitt Gray const unsigned long mask = BIT(irqd_to_hwirq(data)); 163a1184147SWilliam Breathitt Gray const unsigned long prev_irq_mask = idio16gpio->irq_mask; 164a1184147SWilliam Breathitt Gray unsigned long flags; 165a1184147SWilliam Breathitt Gray 166a1184147SWilliam Breathitt Gray idio16gpio->irq_mask |= mask; 167a1184147SWilliam Breathitt Gray 168a1184147SWilliam Breathitt Gray if (!prev_irq_mask) { 169a1184147SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 170a1184147SWilliam Breathitt Gray 171a1184147SWilliam Breathitt Gray inb(idio16gpio->base + 2); 172a1184147SWilliam Breathitt Gray 173a1184147SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 174a1184147SWilliam Breathitt Gray } 175a1184147SWilliam Breathitt Gray } 176a1184147SWilliam Breathitt Gray 177a1184147SWilliam Breathitt Gray static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type) 178a1184147SWilliam Breathitt Gray { 179a1184147SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 180a1184147SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 181a1184147SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 182a1184147SWilliam Breathitt Gray return -EINVAL; 183a1184147SWilliam Breathitt Gray 184a1184147SWilliam Breathitt Gray return 0; 185a1184147SWilliam Breathitt Gray } 186a1184147SWilliam Breathitt Gray 187a1184147SWilliam Breathitt Gray static struct irq_chip idio_16_irqchip = { 188a1184147SWilliam Breathitt Gray .name = "104-idio-16", 189a1184147SWilliam Breathitt Gray .irq_ack = idio_16_irq_ack, 190a1184147SWilliam Breathitt Gray .irq_mask = idio_16_irq_mask, 191a1184147SWilliam Breathitt Gray .irq_unmask = idio_16_irq_unmask, 192a1184147SWilliam Breathitt Gray .irq_set_type = idio_16_irq_set_type 193a1184147SWilliam Breathitt Gray }; 194a1184147SWilliam Breathitt Gray 195a1184147SWilliam Breathitt Gray static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) 196a1184147SWilliam Breathitt Gray { 197a1184147SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = dev_id; 198a1184147SWilliam Breathitt Gray struct gpio_chip *const chip = &idio16gpio->chip; 199a1184147SWilliam Breathitt Gray int gpio; 200a1184147SWilliam Breathitt Gray 201a1184147SWilliam Breathitt Gray for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) 202a1184147SWilliam Breathitt Gray generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio)); 203a1184147SWilliam Breathitt Gray 20412b61c9dSWilliam Breathitt Gray spin_lock(&idio16gpio->lock); 20512b61c9dSWilliam Breathitt Gray 20612b61c9dSWilliam Breathitt Gray outb(0, idio16gpio->base + 1); 20712b61c9dSWilliam Breathitt Gray 20812b61c9dSWilliam Breathitt Gray spin_unlock(&idio16gpio->lock); 20912b61c9dSWilliam Breathitt Gray 210a1184147SWilliam Breathitt Gray return IRQ_HANDLED; 211a1184147SWilliam Breathitt Gray } 212a1184147SWilliam Breathitt Gray 213e0af4b5eSWilliam Breathitt Gray #define IDIO_16_NGPIO 32 214e0af4b5eSWilliam Breathitt Gray static const char *idio_16_names[IDIO_16_NGPIO] = { 215e0af4b5eSWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 216e0af4b5eSWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 217e0af4b5eSWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 218e0af4b5eSWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" 219e0af4b5eSWilliam Breathitt Gray }; 220e0af4b5eSWilliam Breathitt Gray 22186ea8a95SWilliam Breathitt Gray static int idio_16_probe(struct device *dev, unsigned int id) 2221ceacea2SWilliam Breathitt Gray { 2231ceacea2SWilliam Breathitt Gray struct idio_16_gpio *idio16gpio; 2246e0171b4SWilliam Breathitt Gray const char *const name = dev_name(dev); 2251ceacea2SWilliam Breathitt Gray int err; 2261ceacea2SWilliam Breathitt Gray 2271ceacea2SWilliam Breathitt Gray idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); 2281ceacea2SWilliam Breathitt Gray if (!idio16gpio) 2291ceacea2SWilliam Breathitt Gray return -ENOMEM; 2301ceacea2SWilliam Breathitt Gray 23186ea8a95SWilliam Breathitt Gray if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) { 232cb32389cSWilliam Breathitt Gray dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 23386ea8a95SWilliam Breathitt Gray base[id], base[id] + IDIO_16_EXTENT); 234cb32389cSWilliam Breathitt Gray return -EBUSY; 2351ceacea2SWilliam Breathitt Gray } 2361ceacea2SWilliam Breathitt Gray 2376e0171b4SWilliam Breathitt Gray idio16gpio->chip.label = name; 23858383c78SLinus Walleij idio16gpio->chip.parent = dev; 2391ceacea2SWilliam Breathitt Gray idio16gpio->chip.owner = THIS_MODULE; 2401ceacea2SWilliam Breathitt Gray idio16gpio->chip.base = -1; 241e0af4b5eSWilliam Breathitt Gray idio16gpio->chip.ngpio = IDIO_16_NGPIO; 242e0af4b5eSWilliam Breathitt Gray idio16gpio->chip.names = idio_16_names; 2431ceacea2SWilliam Breathitt Gray idio16gpio->chip.get_direction = idio_16_gpio_get_direction; 2441ceacea2SWilliam Breathitt Gray idio16gpio->chip.direction_input = idio_16_gpio_direction_input; 2451ceacea2SWilliam Breathitt Gray idio16gpio->chip.direction_output = idio_16_gpio_direction_output; 2461ceacea2SWilliam Breathitt Gray idio16gpio->chip.get = idio_16_gpio_get; 2471ceacea2SWilliam Breathitt Gray idio16gpio->chip.set = idio_16_gpio_set; 2489d7ae812SWilliam Breathitt Gray idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; 24986ea8a95SWilliam Breathitt Gray idio16gpio->base = base[id]; 2501ceacea2SWilliam Breathitt Gray idio16gpio->out_state = 0xFFFF; 2511ceacea2SWilliam Breathitt Gray 2521ceacea2SWilliam Breathitt Gray spin_lock_init(&idio16gpio->lock); 2531ceacea2SWilliam Breathitt Gray 254837143d3SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); 2551ceacea2SWilliam Breathitt Gray if (err) { 2561ceacea2SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 257cb32389cSWilliam Breathitt Gray return err; 2581ceacea2SWilliam Breathitt Gray } 2591ceacea2SWilliam Breathitt Gray 260fb50cdfeSWilliam Breathitt Gray /* Disable IRQ by default */ 26186ea8a95SWilliam Breathitt Gray outb(0, base[id] + 2); 26286ea8a95SWilliam Breathitt Gray outb(0, base[id] + 1); 263fb50cdfeSWilliam Breathitt Gray 264a1184147SWilliam Breathitt Gray err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0, 265a1184147SWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 266a1184147SWilliam Breathitt Gray if (err) { 267a1184147SWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 2681ceacea2SWilliam Breathitt Gray return err; 2691ceacea2SWilliam Breathitt Gray } 2701ceacea2SWilliam Breathitt Gray 271837143d3SWilliam Breathitt Gray err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name, 272837143d3SWilliam Breathitt Gray idio16gpio); 273837143d3SWilliam Breathitt Gray if (err) { 274837143d3SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 275837143d3SWilliam Breathitt Gray return err; 276837143d3SWilliam Breathitt Gray } 2771ceacea2SWilliam Breathitt Gray 2781ceacea2SWilliam Breathitt Gray return 0; 2791ceacea2SWilliam Breathitt Gray } 2801ceacea2SWilliam Breathitt Gray 28186ea8a95SWilliam Breathitt Gray static struct isa_driver idio_16_driver = { 28286ea8a95SWilliam Breathitt Gray .probe = idio_16_probe, 2831ceacea2SWilliam Breathitt Gray .driver = { 2841ceacea2SWilliam Breathitt Gray .name = "104-idio-16" 2851ceacea2SWilliam Breathitt Gray }, 2861ceacea2SWilliam Breathitt Gray }; 2871ceacea2SWilliam Breathitt Gray 28886ea8a95SWilliam Breathitt Gray module_isa_driver(idio_16_driver, num_idio_16); 2891ceacea2SWilliam Breathitt Gray 2901ceacea2SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 2911ceacea2SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); 29222aeddb5SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 293