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