linux/drivers/gpio/gpio-104-idio-16.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * GPIO driver for the ACCES 104-IDIO-16 family
   4 * Copyright (C) 2015 William Breathitt Gray
   5 *
   6 * This driver supports the following ACCES devices: 104-IDIO-16,
   7 * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
   8 */
   9#include <linux/bitops.h>
  10#include <linux/device.h>
  11#include <linux/errno.h>
  12#include <linux/gpio/driver.h>
  13#include <linux/io.h>
  14#include <linux/ioport.h>
  15#include <linux/interrupt.h>
  16#include <linux/irqdesc.h>
  17#include <linux/isa.h>
  18#include <linux/kernel.h>
  19#include <linux/module.h>
  20#include <linux/moduleparam.h>
  21#include <linux/spinlock.h>
  22
  23#define IDIO_16_EXTENT 8
  24#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
  25
  26static unsigned int base[MAX_NUM_IDIO_16];
  27static unsigned int num_idio_16;
  28module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
  29MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
  30
  31static unsigned int irq[MAX_NUM_IDIO_16];
  32module_param_hw_array(irq, uint, irq, NULL, 0);
  33MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
  34
  35/**
  36 * struct idio_16_gpio - GPIO device private data structure
  37 * @chip:       instance of the gpio_chip
  38 * @lock:       synchronization lock to prevent I/O race conditions
  39 * @irq_mask:   I/O bits affected by interrupts
  40 * @base:       base port address of the GPIO device
  41 * @out_state:  output bits state
  42 */
  43struct idio_16_gpio {
  44        struct gpio_chip chip;
  45        raw_spinlock_t lock;
  46        unsigned long irq_mask;
  47        unsigned base;
  48        unsigned out_state;
  49};
  50
  51static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
  52{
  53        if (offset > 15)
  54                return 1;
  55
  56        return 0;
  57}
  58
  59static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  60{
  61        return 0;
  62}
  63
  64static int idio_16_gpio_direction_output(struct gpio_chip *chip,
  65        unsigned offset, int value)
  66{
  67        chip->set(chip, offset, value);
  68        return 0;
  69}
  70
  71static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
  72{
  73        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
  74        const unsigned mask = BIT(offset-16);
  75
  76        if (offset < 16)
  77                return -EINVAL;
  78
  79        if (offset < 24)
  80                return !!(inb(idio16gpio->base + 1) & mask);
  81
  82        return !!(inb(idio16gpio->base + 5) & (mask>>8));
  83}
  84
  85static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
  86        unsigned long *mask, unsigned long *bits)
  87{
  88        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
  89
  90        *bits = 0;
  91        if (*mask & GENMASK(23, 16))
  92                *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
  93        if (*mask & GENMASK(31, 24))
  94                *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
  95
  96        return 0;
  97}
  98
  99static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 100{
 101        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 102        const unsigned mask = BIT(offset);
 103        unsigned long flags;
 104
 105        if (offset > 15)
 106                return;
 107
 108        raw_spin_lock_irqsave(&idio16gpio->lock, flags);
 109
 110        if (value)
 111                idio16gpio->out_state |= mask;
 112        else
 113                idio16gpio->out_state &= ~mask;
 114
 115        if (offset > 7)
 116                outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
 117        else
 118                outb(idio16gpio->out_state, idio16gpio->base);
 119
 120        raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
 121}
 122
 123static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
 124        unsigned long *mask, unsigned long *bits)
 125{
 126        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 127        unsigned long flags;
 128
 129        raw_spin_lock_irqsave(&idio16gpio->lock, flags);
 130
 131        idio16gpio->out_state &= ~*mask;
 132        idio16gpio->out_state |= *mask & *bits;
 133
 134        if (*mask & 0xFF)
 135                outb(idio16gpio->out_state, idio16gpio->base);
 136        if ((*mask >> 8) & 0xFF)
 137                outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
 138
 139        raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
 140}
 141
 142static void idio_16_irq_ack(struct irq_data *data)
 143{
 144}
 145
 146static void idio_16_irq_mask(struct irq_data *data)
 147{
 148        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
 149        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 150        const unsigned long mask = BIT(irqd_to_hwirq(data));
 151        unsigned long flags;
 152
 153        idio16gpio->irq_mask &= ~mask;
 154
 155        if (!idio16gpio->irq_mask) {
 156                raw_spin_lock_irqsave(&idio16gpio->lock, flags);
 157
 158                outb(0, idio16gpio->base + 2);
 159
 160                raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
 161        }
 162}
 163
 164static void idio_16_irq_unmask(struct irq_data *data)
 165{
 166        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
 167        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 168        const unsigned long mask = BIT(irqd_to_hwirq(data));
 169        const unsigned long prev_irq_mask = idio16gpio->irq_mask;
 170        unsigned long flags;
 171
 172        idio16gpio->irq_mask |= mask;
 173
 174        if (!prev_irq_mask) {
 175                raw_spin_lock_irqsave(&idio16gpio->lock, flags);
 176
 177                inb(idio16gpio->base + 2);
 178
 179                raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
 180        }
 181}
 182
 183static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
 184{
 185        /* The only valid irq types are none and both-edges */
 186        if (flow_type != IRQ_TYPE_NONE &&
 187                (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
 188                return -EINVAL;
 189
 190        return 0;
 191}
 192
 193static struct irq_chip idio_16_irqchip = {
 194        .name = "104-idio-16",
 195        .irq_ack = idio_16_irq_ack,
 196        .irq_mask = idio_16_irq_mask,
 197        .irq_unmask = idio_16_irq_unmask,
 198        .irq_set_type = idio_16_irq_set_type
 199};
 200
 201static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
 202{
 203        struct idio_16_gpio *const idio16gpio = dev_id;
 204        struct gpio_chip *const chip = &idio16gpio->chip;
 205        int gpio;
 206
 207        for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
 208                generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
 209
 210        raw_spin_lock(&idio16gpio->lock);
 211
 212        outb(0, idio16gpio->base + 1);
 213
 214        raw_spin_unlock(&idio16gpio->lock);
 215
 216        return IRQ_HANDLED;
 217}
 218
 219#define IDIO_16_NGPIO 32
 220static const char *idio_16_names[IDIO_16_NGPIO] = {
 221        "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
 222        "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
 223        "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
 224        "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
 225};
 226
 227static int idio_16_probe(struct device *dev, unsigned int id)
 228{
 229        struct idio_16_gpio *idio16gpio;
 230        const char *const name = dev_name(dev);
 231        int err;
 232
 233        idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
 234        if (!idio16gpio)
 235                return -ENOMEM;
 236
 237        if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
 238                dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
 239                        base[id], base[id] + IDIO_16_EXTENT);
 240                return -EBUSY;
 241        }
 242
 243        idio16gpio->chip.label = name;
 244        idio16gpio->chip.parent = dev;
 245        idio16gpio->chip.owner = THIS_MODULE;
 246        idio16gpio->chip.base = -1;
 247        idio16gpio->chip.ngpio = IDIO_16_NGPIO;
 248        idio16gpio->chip.names = idio_16_names;
 249        idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
 250        idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
 251        idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
 252        idio16gpio->chip.get = idio_16_gpio_get;
 253        idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
 254        idio16gpio->chip.set = idio_16_gpio_set;
 255        idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
 256        idio16gpio->base = base[id];
 257        idio16gpio->out_state = 0xFFFF;
 258
 259        raw_spin_lock_init(&idio16gpio->lock);
 260
 261        err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
 262        if (err) {
 263                dev_err(dev, "GPIO registering failed (%d)\n", err);
 264                return err;
 265        }
 266
 267        /* Disable IRQ by default */
 268        outb(0, base[id] + 2);
 269        outb(0, base[id] + 1);
 270
 271        err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
 272                handle_edge_irq, IRQ_TYPE_NONE);
 273        if (err) {
 274                dev_err(dev, "Could not add irqchip (%d)\n", err);
 275                return err;
 276        }
 277
 278        err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
 279                idio16gpio);
 280        if (err) {
 281                dev_err(dev, "IRQ handler registering failed (%d)\n", err);
 282                return err;
 283        }
 284
 285        return 0;
 286}
 287
 288static struct isa_driver idio_16_driver = {
 289        .probe = idio_16_probe,
 290        .driver = {
 291                .name = "104-idio-16"
 292        },
 293};
 294
 295module_isa_driver(idio_16_driver, num_idio_16);
 296
 297MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
 298MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
 299MODULE_LICENSE("GPL v2");
 300