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 #include <linux/bitops.h> 15 #include <linux/device.h> 16 #include <linux/errno.h> 17 #include <linux/gpio/driver.h> 18 #include <linux/io.h> 19 #include <linux/ioport.h> 20 #include <linux/interrupt.h> 21 #include <linux/irqdesc.h> 22 #include <linux/kernel.h> 23 #include <linux/module.h> 24 #include <linux/moduleparam.h> 25 #include <linux/platform_device.h> 26 #include <linux/spinlock.h> 27 28 static unsigned idio_16_base; 29 module_param(idio_16_base, uint, 0); 30 MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address"); 31 static unsigned idio_16_irq; 32 module_param(idio_16_irq, uint, 0); 33 MODULE_PARM_DESC(idio_16_irq, "ACCES 104-IDIO-16 interrupt line number"); 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 * @irq: Interrupt line number 42 * @out_state: output bits state 43 */ 44 struct idio_16_gpio { 45 struct gpio_chip chip; 46 spinlock_t lock; 47 unsigned long irq_mask; 48 unsigned base; 49 unsigned irq; 50 unsigned out_state; 51 }; 52 53 static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 54 { 55 if (offset > 15) 56 return 1; 57 58 return 0; 59 } 60 61 static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 62 { 63 return 0; 64 } 65 66 static int idio_16_gpio_direction_output(struct gpio_chip *chip, 67 unsigned offset, int value) 68 { 69 chip->set(chip, offset, value); 70 return 0; 71 } 72 73 static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset) 74 { 75 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 76 const unsigned mask = BIT(offset-16); 77 78 if (offset < 16) 79 return -EINVAL; 80 81 if (offset < 24) 82 return !!(inb(idio16gpio->base + 1) & mask); 83 84 return !!(inb(idio16gpio->base + 5) & (mask>>8)); 85 } 86 87 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 88 { 89 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 90 const unsigned mask = BIT(offset); 91 unsigned long flags; 92 93 if (offset > 15) 94 return; 95 96 spin_lock_irqsave(&idio16gpio->lock, flags); 97 98 if (value) 99 idio16gpio->out_state |= mask; 100 else 101 idio16gpio->out_state &= ~mask; 102 103 if (offset > 7) 104 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4); 105 else 106 outb(idio16gpio->out_state, idio16gpio->base); 107 108 spin_unlock_irqrestore(&idio16gpio->lock, flags); 109 } 110 111 static void idio_16_irq_ack(struct irq_data *data) 112 { 113 } 114 115 static void idio_16_irq_mask(struct irq_data *data) 116 { 117 struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 118 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 119 const unsigned long mask = BIT(irqd_to_hwirq(data)); 120 unsigned long flags; 121 122 idio16gpio->irq_mask &= ~mask; 123 124 if (!idio16gpio->irq_mask) { 125 spin_lock_irqsave(&idio16gpio->lock, flags); 126 127 outb(0, idio16gpio->base + 2); 128 129 spin_unlock_irqrestore(&idio16gpio->lock, flags); 130 } 131 } 132 133 static void idio_16_irq_unmask(struct irq_data *data) 134 { 135 struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 136 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 137 const unsigned long mask = BIT(irqd_to_hwirq(data)); 138 const unsigned long prev_irq_mask = idio16gpio->irq_mask; 139 unsigned long flags; 140 141 idio16gpio->irq_mask |= mask; 142 143 if (!prev_irq_mask) { 144 spin_lock_irqsave(&idio16gpio->lock, flags); 145 146 inb(idio16gpio->base + 2); 147 148 spin_unlock_irqrestore(&idio16gpio->lock, flags); 149 } 150 } 151 152 static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type) 153 { 154 /* The only valid irq types are none and both-edges */ 155 if (flow_type != IRQ_TYPE_NONE && 156 (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 157 return -EINVAL; 158 159 return 0; 160 } 161 162 static struct irq_chip idio_16_irqchip = { 163 .name = "104-idio-16", 164 .irq_ack = idio_16_irq_ack, 165 .irq_mask = idio_16_irq_mask, 166 .irq_unmask = idio_16_irq_unmask, 167 .irq_set_type = idio_16_irq_set_type 168 }; 169 170 static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) 171 { 172 struct idio_16_gpio *const idio16gpio = dev_id; 173 struct gpio_chip *const chip = &idio16gpio->chip; 174 int gpio; 175 176 for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) 177 generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio)); 178 179 spin_lock(&idio16gpio->lock); 180 181 outb(0, idio16gpio->base + 1); 182 183 spin_unlock(&idio16gpio->lock); 184 185 return IRQ_HANDLED; 186 } 187 188 static int __init idio_16_probe(struct platform_device *pdev) 189 { 190 struct device *dev = &pdev->dev; 191 struct idio_16_gpio *idio16gpio; 192 const unsigned base = idio_16_base; 193 const unsigned extent = 8; 194 const char *const name = dev_name(dev); 195 int err; 196 const unsigned irq = idio_16_irq; 197 198 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); 199 if (!idio16gpio) 200 return -ENOMEM; 201 202 if (!devm_request_region(dev, base, extent, name)) { 203 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 204 base, base + extent); 205 return -EBUSY; 206 } 207 208 idio16gpio->chip.label = name; 209 idio16gpio->chip.parent = dev; 210 idio16gpio->chip.owner = THIS_MODULE; 211 idio16gpio->chip.base = -1; 212 idio16gpio->chip.ngpio = 32; 213 idio16gpio->chip.get_direction = idio_16_gpio_get_direction; 214 idio16gpio->chip.direction_input = idio_16_gpio_direction_input; 215 idio16gpio->chip.direction_output = idio_16_gpio_direction_output; 216 idio16gpio->chip.get = idio_16_gpio_get; 217 idio16gpio->chip.set = idio_16_gpio_set; 218 idio16gpio->base = base; 219 idio16gpio->irq = irq; 220 idio16gpio->out_state = 0xFFFF; 221 222 spin_lock_init(&idio16gpio->lock); 223 224 dev_set_drvdata(dev, idio16gpio); 225 226 err = gpiochip_add_data(&idio16gpio->chip, idio16gpio); 227 if (err) { 228 dev_err(dev, "GPIO registering failed (%d)\n", err); 229 return err; 230 } 231 232 /* Disable IRQ by default */ 233 outb(0, base + 2); 234 outb(0, base + 1); 235 236 err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0, 237 handle_edge_irq, IRQ_TYPE_NONE); 238 if (err) { 239 dev_err(dev, "Could not add irqchip (%d)\n", err); 240 goto err_gpiochip_remove; 241 } 242 243 err = request_irq(irq, idio_16_irq_handler, 0, name, idio16gpio); 244 if (err) { 245 dev_err(dev, "IRQ handler registering failed (%d)\n", err); 246 goto err_gpiochip_remove; 247 } 248 249 return 0; 250 251 err_gpiochip_remove: 252 gpiochip_remove(&idio16gpio->chip); 253 return err; 254 } 255 256 static int idio_16_remove(struct platform_device *pdev) 257 { 258 struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev); 259 260 free_irq(idio16gpio->irq, idio16gpio); 261 gpiochip_remove(&idio16gpio->chip); 262 263 return 0; 264 } 265 266 static struct platform_device *idio_16_device; 267 268 static struct platform_driver idio_16_driver = { 269 .driver = { 270 .name = "104-idio-16" 271 }, 272 .remove = idio_16_remove 273 }; 274 275 static void __exit idio_16_exit(void) 276 { 277 platform_device_unregister(idio_16_device); 278 platform_driver_unregister(&idio_16_driver); 279 } 280 281 static int __init idio_16_init(void) 282 { 283 int err; 284 285 idio_16_device = platform_device_alloc(idio_16_driver.driver.name, -1); 286 if (!idio_16_device) 287 return -ENOMEM; 288 289 err = platform_device_add(idio_16_device); 290 if (err) 291 goto err_platform_device; 292 293 err = platform_driver_probe(&idio_16_driver, idio_16_probe); 294 if (err) 295 goto err_platform_driver; 296 297 return 0; 298 299 err_platform_driver: 300 platform_device_del(idio_16_device); 301 err_platform_device: 302 platform_device_put(idio_16_device); 303 return err; 304 } 305 306 module_init(idio_16_init); 307 module_exit(idio_16_exit); 308 309 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 310 MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); 311 MODULE_LICENSE("GPL v2"); 312