Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * GPIO driver for the ACCES 104-IDI-48 family
0004  * Copyright (C) 2015 William Breathitt Gray
0005  *
0006  * This driver supports the following ACCES devices: 104-IDI-48A,
0007  * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
0008  */
0009 #include <linux/bits.h>
0010 #include <linux/device.h>
0011 #include <linux/errno.h>
0012 #include <linux/gpio/driver.h>
0013 #include <linux/io.h>
0014 #include <linux/ioport.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/irqdesc.h>
0017 #include <linux/isa.h>
0018 #include <linux/kernel.h>
0019 #include <linux/module.h>
0020 #include <linux/moduleparam.h>
0021 #include <linux/spinlock.h>
0022 #include <linux/types.h>
0023 
0024 #include "gpio-i8255.h"
0025 
0026 MODULE_IMPORT_NS(I8255);
0027 
0028 #define IDI_48_EXTENT 8
0029 #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
0030 
0031 static unsigned int base[MAX_NUM_IDI_48];
0032 static unsigned int num_idi_48;
0033 module_param_hw_array(base, uint, ioport, &num_idi_48, 0);
0034 MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
0035 
0036 static unsigned int irq[MAX_NUM_IDI_48];
0037 module_param_hw_array(irq, uint, irq, NULL, 0);
0038 MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
0039 
0040 /**
0041  * struct idi_48_reg - device register structure
0042  * @port0:  Port 0 Inputs
0043  * @unused: Unused
0044  * @port1:  Port 1 Inputs
0045  * @irq:    Read: IRQ Status Register/IRQ Clear
0046  *      Write: IRQ Enable/Disable
0047  */
0048 struct idi_48_reg {
0049     u8 port0[3];
0050     u8 unused;
0051     u8 port1[3];
0052     u8 irq;
0053 };
0054 
0055 /**
0056  * struct idi_48_gpio - GPIO device private data structure
0057  * @chip:   instance of the gpio_chip
0058  * @lock:   synchronization lock to prevent I/O race conditions
0059  * @irq_mask:   input bits affected by interrupts
0060  * @reg:    I/O address offset for the device registers
0061  * @cos_enb:    Change-Of-State IRQ enable boundaries mask
0062  */
0063 struct idi_48_gpio {
0064     struct gpio_chip chip;
0065     spinlock_t lock;
0066     unsigned char irq_mask[6];
0067     struct idi_48_reg __iomem *reg;
0068     unsigned char cos_enb;
0069 };
0070 
0071 static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
0072 {
0073     return GPIO_LINE_DIRECTION_IN;
0074 }
0075 
0076 static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
0077 {
0078     return 0;
0079 }
0080 
0081 static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset)
0082 {
0083     struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
0084     void __iomem *const ppi = idi48gpio->reg;
0085 
0086     return i8255_get(ppi, offset);
0087 }
0088 
0089 static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
0090     unsigned long *bits)
0091 {
0092     struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
0093     void __iomem *const ppi = idi48gpio->reg;
0094 
0095     i8255_get_multiple(ppi, mask, bits, chip->ngpio);
0096 
0097     return 0;
0098 }
0099 
0100 static void idi_48_irq_ack(struct irq_data *data)
0101 {
0102 }
0103 
0104 static void idi_48_irq_mask(struct irq_data *data)
0105 {
0106     struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
0107     struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
0108     const unsigned int offset = irqd_to_hwirq(data);
0109     const unsigned long boundary = offset / 8;
0110     const unsigned long mask = BIT(offset % 8);
0111     unsigned long flags;
0112 
0113     spin_lock_irqsave(&idi48gpio->lock, flags);
0114 
0115     idi48gpio->irq_mask[boundary] &= ~mask;
0116     gpiochip_disable_irq(chip, offset);
0117 
0118     /* Exit early if there are still input lines with IRQ unmasked */
0119     if (idi48gpio->irq_mask[boundary])
0120         goto exit;
0121 
0122     idi48gpio->cos_enb &= ~BIT(boundary);
0123 
0124     iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
0125 
0126 exit:
0127     spin_unlock_irqrestore(&idi48gpio->lock, flags);
0128 }
0129 
0130 static void idi_48_irq_unmask(struct irq_data *data)
0131 {
0132     struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
0133     struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
0134     const unsigned int offset = irqd_to_hwirq(data);
0135     const unsigned long boundary = offset / 8;
0136     const unsigned long mask = BIT(offset % 8);
0137     unsigned int prev_irq_mask;
0138     unsigned long flags;
0139 
0140     spin_lock_irqsave(&idi48gpio->lock, flags);
0141 
0142     prev_irq_mask = idi48gpio->irq_mask[boundary];
0143 
0144     gpiochip_enable_irq(chip, offset);
0145     idi48gpio->irq_mask[boundary] |= mask;
0146 
0147     /* Exit early if IRQ was already unmasked for this boundary */
0148     if (prev_irq_mask)
0149         goto exit;
0150 
0151     idi48gpio->cos_enb |= BIT(boundary);
0152 
0153     iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
0154 
0155 exit:
0156     spin_unlock_irqrestore(&idi48gpio->lock, flags);
0157 }
0158 
0159 static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type)
0160 {
0161     /* The only valid irq types are none and both-edges */
0162     if (flow_type != IRQ_TYPE_NONE &&
0163         (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
0164         return -EINVAL;
0165 
0166     return 0;
0167 }
0168 
0169 static const struct irq_chip idi_48_irqchip = {
0170     .name = "104-idi-48",
0171     .irq_ack = idi_48_irq_ack,
0172     .irq_mask = idi_48_irq_mask,
0173     .irq_unmask = idi_48_irq_unmask,
0174     .irq_set_type = idi_48_irq_set_type,
0175     .flags = IRQCHIP_IMMUTABLE,
0176     GPIOCHIP_IRQ_RESOURCE_HELPERS,
0177 };
0178 
0179 static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
0180 {
0181     struct idi_48_gpio *const idi48gpio = dev_id;
0182     unsigned long cos_status;
0183     unsigned long boundary;
0184     unsigned long irq_mask;
0185     unsigned long bit_num;
0186     unsigned long gpio;
0187     struct gpio_chip *const chip = &idi48gpio->chip;
0188 
0189     spin_lock(&idi48gpio->lock);
0190 
0191     cos_status = ioread8(&idi48gpio->reg->irq);
0192 
0193     /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
0194     if (cos_status & BIT(6)) {
0195         spin_unlock(&idi48gpio->lock);
0196         return IRQ_NONE;
0197     }
0198 
0199     /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
0200     cos_status &= 0x3F;
0201 
0202     for_each_set_bit(boundary, &cos_status, 6) {
0203         irq_mask = idi48gpio->irq_mask[boundary];
0204 
0205         for_each_set_bit(bit_num, &irq_mask, 8) {
0206             gpio = bit_num + boundary * 8;
0207 
0208             generic_handle_domain_irq(chip->irq.domain,
0209                           gpio);
0210         }
0211     }
0212 
0213     spin_unlock(&idi48gpio->lock);
0214 
0215     return IRQ_HANDLED;
0216 }
0217 
0218 #define IDI48_NGPIO 48
0219 static const char *idi48_names[IDI48_NGPIO] = {
0220     "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
0221     "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
0222     "Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A", "Bit 16 A", "Bit 17 A",
0223     "Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A",
0224     "Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B",
0225     "Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B",
0226     "Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B", "Bit 16 B", "Bit 17 B",
0227     "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
0228 };
0229 
0230 static int idi_48_irq_init_hw(struct gpio_chip *gc)
0231 {
0232     struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
0233 
0234     /* Disable IRQ by default */
0235     iowrite8(0, &idi48gpio->reg->irq);
0236     ioread8(&idi48gpio->reg->irq);
0237 
0238     return 0;
0239 }
0240 
0241 static int idi_48_probe(struct device *dev, unsigned int id)
0242 {
0243     struct idi_48_gpio *idi48gpio;
0244     const char *const name = dev_name(dev);
0245     struct gpio_irq_chip *girq;
0246     int err;
0247 
0248     idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
0249     if (!idi48gpio)
0250         return -ENOMEM;
0251 
0252     if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) {
0253         dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
0254             base[id], base[id] + IDI_48_EXTENT);
0255         return -EBUSY;
0256     }
0257 
0258     idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
0259     if (!idi48gpio->reg)
0260         return -ENOMEM;
0261 
0262     idi48gpio->chip.label = name;
0263     idi48gpio->chip.parent = dev;
0264     idi48gpio->chip.owner = THIS_MODULE;
0265     idi48gpio->chip.base = -1;
0266     idi48gpio->chip.ngpio = IDI48_NGPIO;
0267     idi48gpio->chip.names = idi48_names;
0268     idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
0269     idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
0270     idi48gpio->chip.get = idi_48_gpio_get;
0271     idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
0272 
0273     girq = &idi48gpio->chip.irq;
0274     gpio_irq_chip_set_chip(girq, &idi_48_irqchip);
0275     /* This will let us handle the parent IRQ in the driver */
0276     girq->parent_handler = NULL;
0277     girq->num_parents = 0;
0278     girq->parents = NULL;
0279     girq->default_type = IRQ_TYPE_NONE;
0280     girq->handler = handle_edge_irq;
0281     girq->init_hw = idi_48_irq_init_hw;
0282 
0283     spin_lock_init(&idi48gpio->lock);
0284 
0285     err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
0286     if (err) {
0287         dev_err(dev, "GPIO registering failed (%d)\n", err);
0288         return err;
0289     }
0290 
0291     err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
0292         name, idi48gpio);
0293     if (err) {
0294         dev_err(dev, "IRQ handler registering failed (%d)\n", err);
0295         return err;
0296     }
0297 
0298     return 0;
0299 }
0300 
0301 static struct isa_driver idi_48_driver = {
0302     .probe = idi_48_probe,
0303     .driver = {
0304         .name = "104-idi-48"
0305     },
0306 };
0307 module_isa_driver(idi_48_driver, num_idi_48);
0308 
0309 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
0310 MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
0311 MODULE_LICENSE("GPL v2");