linux/drivers/gpio/gpio-104-idi-48.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * GPIO driver for the ACCES 104-IDI-48 family
   4 * Copyright (C) 2015 William Breathitt Gray
   5 *
   6 * This driver supports the following ACCES devices: 104-IDI-48A,
   7 * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
   8 */
   9#include <linux/bitmap.h>
  10#include <linux/bitops.h>
  11#include <linux/device.h>
  12#include <linux/errno.h>
  13#include <linux/gpio/driver.h>
  14#include <linux/io.h>
  15#include <linux/ioport.h>
  16#include <linux/interrupt.h>
  17#include <linux/irqdesc.h>
  18#include <linux/isa.h>
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/moduleparam.h>
  22#include <linux/spinlock.h>
  23
  24#define IDI_48_EXTENT 8
  25#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
  26
  27static unsigned int base[MAX_NUM_IDI_48];
  28static unsigned int num_idi_48;
  29module_param_hw_array(base, uint, ioport, &num_idi_48, 0);
  30MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
  31
  32static unsigned int irq[MAX_NUM_IDI_48];
  33module_param_hw_array(irq, uint, irq, NULL, 0);
  34MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
  35
  36/**
  37 * struct idi_48_gpio - GPIO device private data structure
  38 * @chip:       instance of the gpio_chip
  39 * @lock:       synchronization lock to prevent I/O race conditions
  40 * @ack_lock:   synchronization lock to prevent IRQ handler race conditions
  41 * @irq_mask:   input bits affected by interrupts
  42 * @base:       base port address of the GPIO device
  43 * @cos_enb:    Change-Of-State IRQ enable boundaries mask
  44 */
  45struct idi_48_gpio {
  46        struct gpio_chip chip;
  47        raw_spinlock_t lock;
  48        spinlock_t ack_lock;
  49        unsigned char irq_mask[6];
  50        unsigned base;
  51        unsigned char cos_enb;
  52};
  53
  54static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
  55{
  56        return 1;
  57}
  58
  59static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  60{
  61        return 0;
  62}
  63
  64static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
  65{
  66        struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
  67        unsigned i;
  68        const unsigned register_offset[6] = { 0, 1, 2, 4, 5, 6 };
  69        unsigned base_offset;
  70        unsigned mask;
  71
  72        for (i = 0; i < 48; i += 8)
  73                if (offset < i + 8) {
  74                        base_offset = register_offset[i / 8];
  75                        mask = BIT(offset - i);
  76
  77                        return !!(inb(idi48gpio->base + base_offset) & mask);
  78                }
  79
  80        /* The following line should never execute since offset < 48 */
  81        return 0;
  82}
  83
  84static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
  85        unsigned long *bits)
  86{
  87        struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
  88        size_t i;
  89        static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
  90        const unsigned int gpio_reg_size = 8;
  91        unsigned int bits_offset;
  92        size_t word_index;
  93        unsigned int word_offset;
  94        unsigned long word_mask;
  95        const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
  96        unsigned long port_state;
  97
  98        /* clear bits array to a clean slate */
  99        bitmap_zero(bits, chip->ngpio);
 100
 101        /* get bits are evaluated a gpio port register at a time */
 102        for (i = 0; i < ARRAY_SIZE(ports); i++) {
 103                /* gpio offset in bits array */
 104                bits_offset = i * gpio_reg_size;
 105
 106                /* word index for bits array */
 107                word_index = BIT_WORD(bits_offset);
 108
 109                /* gpio offset within current word of bits array */
 110                word_offset = bits_offset % BITS_PER_LONG;
 111
 112                /* mask of get bits for current gpio within current word */
 113                word_mask = mask[word_index] & (port_mask << word_offset);
 114                if (!word_mask) {
 115                        /* no get bits in this port so skip to next one */
 116                        continue;
 117                }
 118
 119                /* read bits from current gpio port */
 120                port_state = inb(idi48gpio->base + ports[i]);
 121
 122                /* store acquired bits at respective bits array offset */
 123                bits[word_index] |= (port_state << word_offset) & word_mask;
 124        }
 125
 126        return 0;
 127}
 128
 129static void idi_48_irq_ack(struct irq_data *data)
 130{
 131}
 132
 133static void idi_48_irq_mask(struct irq_data *data)
 134{
 135        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
 136        struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
 137        const unsigned offset = irqd_to_hwirq(data);
 138        unsigned i;
 139        unsigned mask;
 140        unsigned boundary;
 141        unsigned long flags;
 142
 143        for (i = 0; i < 48; i += 8)
 144                if (offset < i + 8) {
 145                        mask = BIT(offset - i);
 146                        boundary = i / 8;
 147
 148                        idi48gpio->irq_mask[boundary] &= ~mask;
 149
 150                        if (!idi48gpio->irq_mask[boundary]) {
 151                                idi48gpio->cos_enb &= ~BIT(boundary);
 152
 153                                raw_spin_lock_irqsave(&idi48gpio->lock, flags);
 154
 155                                outb(idi48gpio->cos_enb, idi48gpio->base + 7);
 156
 157                                raw_spin_unlock_irqrestore(&idi48gpio->lock,
 158                                                           flags);
 159                        }
 160
 161                        return;
 162                }
 163}
 164
 165static void idi_48_irq_unmask(struct irq_data *data)
 166{
 167        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
 168        struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
 169        const unsigned offset = irqd_to_hwirq(data);
 170        unsigned i;
 171        unsigned mask;
 172        unsigned boundary;
 173        unsigned prev_irq_mask;
 174        unsigned long flags;
 175
 176        for (i = 0; i < 48; i += 8)
 177                if (offset < i + 8) {
 178                        mask = BIT(offset - i);
 179                        boundary = i / 8;
 180                        prev_irq_mask = idi48gpio->irq_mask[boundary];
 181
 182                        idi48gpio->irq_mask[boundary] |= mask;
 183
 184                        if (!prev_irq_mask) {
 185                                idi48gpio->cos_enb |= BIT(boundary);
 186
 187                                raw_spin_lock_irqsave(&idi48gpio->lock, flags);
 188
 189                                outb(idi48gpio->cos_enb, idi48gpio->base + 7);
 190
 191                                raw_spin_unlock_irqrestore(&idi48gpio->lock,
 192                                                           flags);
 193                        }
 194
 195                        return;
 196                }
 197}
 198
 199static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type)
 200{
 201        /* The only valid irq types are none and both-edges */
 202        if (flow_type != IRQ_TYPE_NONE &&
 203                (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
 204                return -EINVAL;
 205
 206        return 0;
 207}
 208
 209static struct irq_chip idi_48_irqchip = {
 210        .name = "104-idi-48",
 211        .irq_ack = idi_48_irq_ack,
 212        .irq_mask = idi_48_irq_mask,
 213        .irq_unmask = idi_48_irq_unmask,
 214        .irq_set_type = idi_48_irq_set_type
 215};
 216
 217static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
 218{
 219        struct idi_48_gpio *const idi48gpio = dev_id;
 220        unsigned long cos_status;
 221        unsigned long boundary;
 222        unsigned long irq_mask;
 223        unsigned long bit_num;
 224        unsigned long gpio;
 225        struct gpio_chip *const chip = &idi48gpio->chip;
 226
 227        spin_lock(&idi48gpio->ack_lock);
 228
 229        raw_spin_lock(&idi48gpio->lock);
 230
 231        cos_status = inb(idi48gpio->base + 7);
 232
 233        raw_spin_unlock(&idi48gpio->lock);
 234
 235        /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
 236        if (cos_status & BIT(6)) {
 237                spin_unlock(&idi48gpio->ack_lock);
 238                return IRQ_NONE;
 239        }
 240
 241        /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
 242        cos_status &= 0x3F;
 243
 244        for_each_set_bit(boundary, &cos_status, 6) {
 245                irq_mask = idi48gpio->irq_mask[boundary];
 246
 247                for_each_set_bit(bit_num, &irq_mask, 8) {
 248                        gpio = bit_num + boundary * 8;
 249
 250                        generic_handle_irq(irq_find_mapping(chip->irq.domain,
 251                                gpio));
 252                }
 253        }
 254
 255        spin_unlock(&idi48gpio->ack_lock);
 256
 257        return IRQ_HANDLED;
 258}
 259
 260#define IDI48_NGPIO 48
 261static const char *idi48_names[IDI48_NGPIO] = {
 262        "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
 263        "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
 264        "Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A", "Bit 16 A", "Bit 17 A",
 265        "Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A",
 266        "Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B",
 267        "Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B",
 268        "Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B", "Bit 16 B", "Bit 17 B",
 269        "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
 270};
 271
 272static int idi_48_probe(struct device *dev, unsigned int id)
 273{
 274        struct idi_48_gpio *idi48gpio;
 275        const char *const name = dev_name(dev);
 276        int err;
 277
 278        idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
 279        if (!idi48gpio)
 280                return -ENOMEM;
 281
 282        if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) {
 283                dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
 284                        base[id], base[id] + IDI_48_EXTENT);
 285                return -EBUSY;
 286        }
 287
 288        idi48gpio->chip.label = name;
 289        idi48gpio->chip.parent = dev;
 290        idi48gpio->chip.owner = THIS_MODULE;
 291        idi48gpio->chip.base = -1;
 292        idi48gpio->chip.ngpio = IDI48_NGPIO;
 293        idi48gpio->chip.names = idi48_names;
 294        idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
 295        idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
 296        idi48gpio->chip.get = idi_48_gpio_get;
 297        idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
 298        idi48gpio->base = base[id];
 299
 300        raw_spin_lock_init(&idi48gpio->lock);
 301        spin_lock_init(&idi48gpio->ack_lock);
 302
 303        err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
 304        if (err) {
 305                dev_err(dev, "GPIO registering failed (%d)\n", err);
 306                return err;
 307        }
 308
 309        /* Disable IRQ by default */
 310        outb(0, base[id] + 7);
 311        inb(base[id] + 7);
 312
 313        err = gpiochip_irqchip_add(&idi48gpio->chip, &idi_48_irqchip, 0,
 314                handle_edge_irq, IRQ_TYPE_NONE);
 315        if (err) {
 316                dev_err(dev, "Could not add irqchip (%d)\n", err);
 317                return err;
 318        }
 319
 320        err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
 321                name, idi48gpio);
 322        if (err) {
 323                dev_err(dev, "IRQ handler registering failed (%d)\n", err);
 324                return err;
 325        }
 326
 327        return 0;
 328}
 329
 330static struct isa_driver idi_48_driver = {
 331        .probe = idi_48_probe,
 332        .driver = {
 333                .name = "104-idi-48"
 334        },
 335};
 336module_isa_driver(idi_48_driver, num_idi_48);
 337
 338MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
 339MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
 340MODULE_LICENSE("GPL v2");
 341