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/device.h> 15 #include <linux/errno.h> 16 #include <linux/gpio/driver.h> 17 #include <linux/io.h> 18 #include <linux/ioport.h> 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/moduleparam.h> 22 #include <linux/platform_device.h> 23 #include <linux/spinlock.h> 24 25 static unsigned idio_16_base; 26 module_param(idio_16_base, uint, 0); 27 MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address"); 28 29 /** 30 * struct idio_16_gpio - GPIO device private data structure 31 * @chip: instance of the gpio_chip 32 * @lock: synchronization lock to prevent gpio_set race conditions 33 * @base: base port address of the GPIO device 34 * @extent: extent of port address region of the GPIO device 35 * @out_state: output bits state 36 */ 37 struct idio_16_gpio { 38 struct gpio_chip chip; 39 spinlock_t lock; 40 unsigned base; 41 unsigned extent; 42 unsigned out_state; 43 }; 44 45 static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 46 { 47 if (offset > 15) 48 return 1; 49 50 return 0; 51 } 52 53 static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 54 { 55 return 0; 56 } 57 58 static int idio_16_gpio_direction_output(struct gpio_chip *chip, 59 unsigned offset, int value) 60 { 61 chip->set(chip, offset, value); 62 return 0; 63 } 64 65 static struct idio_16_gpio *to_idio16gpio(struct gpio_chip *gc) 66 { 67 return container_of(gc, struct idio_16_gpio, chip); 68 } 69 70 static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset) 71 { 72 struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip); 73 const unsigned BIT_MASK = 1U << (offset-16); 74 75 if (offset < 16) 76 return -EINVAL; 77 78 if (offset < 24) 79 return !!(inb(idio16gpio->base + 1) & BIT_MASK); 80 81 return !!(inb(idio16gpio->base + 5) & (BIT_MASK>>8)); 82 } 83 84 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 85 { 86 struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip); 87 const unsigned BIT_MASK = 1U << offset; 88 unsigned long flags; 89 90 if (offset > 15) 91 return; 92 93 spin_lock_irqsave(&idio16gpio->lock, flags); 94 95 if (value) 96 idio16gpio->out_state |= BIT_MASK; 97 else 98 idio16gpio->out_state &= ~BIT_MASK; 99 100 if (offset > 7) 101 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4); 102 else 103 outb(idio16gpio->out_state, idio16gpio->base); 104 105 spin_unlock_irqrestore(&idio16gpio->lock, flags); 106 } 107 108 static int __init idio_16_probe(struct platform_device *pdev) 109 { 110 struct device *dev = &pdev->dev; 111 struct idio_16_gpio *idio16gpio; 112 int err; 113 114 const unsigned BASE = idio_16_base; 115 const unsigned EXTENT = 8; 116 const char *const NAME = dev_name(dev); 117 118 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); 119 if (!idio16gpio) 120 return -ENOMEM; 121 122 if (!request_region(BASE, EXTENT, NAME)) { 123 dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n", 124 NAME, BASE, BASE + EXTENT); 125 err = -EBUSY; 126 goto err_lock_io_port; 127 } 128 129 idio16gpio->chip.label = NAME; 130 idio16gpio->chip.dev = dev; 131 idio16gpio->chip.owner = THIS_MODULE; 132 idio16gpio->chip.base = -1; 133 idio16gpio->chip.ngpio = 32; 134 idio16gpio->chip.get_direction = idio_16_gpio_get_direction; 135 idio16gpio->chip.direction_input = idio_16_gpio_direction_input; 136 idio16gpio->chip.direction_output = idio_16_gpio_direction_output; 137 idio16gpio->chip.get = idio_16_gpio_get; 138 idio16gpio->chip.set = idio_16_gpio_set; 139 idio16gpio->base = BASE; 140 idio16gpio->extent = EXTENT; 141 idio16gpio->out_state = 0xFFFF; 142 143 spin_lock_init(&idio16gpio->lock); 144 145 dev_set_drvdata(dev, idio16gpio); 146 147 err = gpiochip_add(&idio16gpio->chip); 148 if (err) { 149 dev_err(dev, "GPIO registering failed (%d)\n", err); 150 goto err_gpio_register; 151 } 152 153 return 0; 154 155 err_gpio_register: 156 release_region(BASE, EXTENT); 157 err_lock_io_port: 158 return err; 159 } 160 161 static int idio_16_remove(struct platform_device *pdev) 162 { 163 struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev); 164 165 gpiochip_remove(&idio16gpio->chip); 166 release_region(idio16gpio->base, idio16gpio->extent); 167 168 return 0; 169 } 170 171 static struct platform_device *idio_16_device; 172 173 static struct platform_driver idio_16_driver = { 174 .driver = { 175 .name = "104-idio-16" 176 }, 177 .remove = idio_16_remove 178 }; 179 180 static void __exit idio_16_exit(void) 181 { 182 platform_device_unregister(idio_16_device); 183 platform_driver_unregister(&idio_16_driver); 184 } 185 186 static int __init idio_16_init(void) 187 { 188 int err; 189 190 idio_16_device = platform_device_alloc(idio_16_driver.driver.name, -1); 191 if (!idio_16_device) 192 return -ENOMEM; 193 194 err = platform_device_add(idio_16_device); 195 if (err) 196 goto err_platform_device; 197 198 err = platform_driver_probe(&idio_16_driver, idio_16_probe); 199 if (err) 200 goto err_platform_driver; 201 202 return 0; 203 204 err_platform_driver: 205 platform_device_del(idio_16_device); 206 err_platform_device: 207 platform_device_put(idio_16_device); 208 return err; 209 } 210 211 module_init(idio_16_init); 212 module_exit(idio_16_exit); 213 214 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 215 MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); 216 MODULE_LICENSE("GPL"); 217