1 /* 2 * GPIO driver for the Diamond Systems GPIO-MM 3 * Copyright (C) 2016 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 Diamond Systems devices: GPIO-MM and 15 * GPIO-MM-12. 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/isa.h> 24 #include <linux/kernel.h> 25 #include <linux/module.h> 26 #include <linux/moduleparam.h> 27 #include <linux/spinlock.h> 28 29 #define GPIOMM_EXTENT 8 30 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) 31 32 static unsigned int base[MAX_NUM_GPIOMM]; 33 static unsigned int num_gpiomm; 34 module_param_array(base, uint, &num_gpiomm, 0); 35 MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); 36 37 /** 38 * struct gpiomm_gpio - GPIO device private data structure 39 * @chip: instance of the gpio_chip 40 * @io_state: bit I/O state (whether bit is set to input or output) 41 * @out_state: output bits state 42 * @control: Control registers state 43 * @lock: synchronization lock to prevent I/O race conditions 44 * @base: base port address of the GPIO device 45 */ 46 struct gpiomm_gpio { 47 struct gpio_chip chip; 48 unsigned char io_state[6]; 49 unsigned char out_state[6]; 50 unsigned char control[2]; 51 spinlock_t lock; 52 unsigned int base; 53 }; 54 55 static int gpiomm_gpio_get_direction(struct gpio_chip *chip, 56 unsigned int offset) 57 { 58 struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 59 const unsigned int port = offset / 8; 60 const unsigned int mask = BIT(offset % 8); 61 62 return !!(gpiommgpio->io_state[port] & mask); 63 } 64 65 static int gpiomm_gpio_direction_input(struct gpio_chip *chip, 66 unsigned int offset) 67 { 68 struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 69 const unsigned int io_port = offset / 8; 70 const unsigned int control_port = io_port / 3; 71 const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4; 72 unsigned long flags; 73 unsigned int control; 74 75 spin_lock_irqsave(&gpiommgpio->lock, flags); 76 77 /* Check if configuring Port C */ 78 if (io_port == 2 || io_port == 5) { 79 /* Port C can be configured by nibble */ 80 if (offset % 8 > 3) { 81 gpiommgpio->io_state[io_port] |= 0xF0; 82 gpiommgpio->control[control_port] |= BIT(3); 83 } else { 84 gpiommgpio->io_state[io_port] |= 0x0F; 85 gpiommgpio->control[control_port] |= BIT(0); 86 } 87 } else { 88 gpiommgpio->io_state[io_port] |= 0xFF; 89 if (io_port == 0 || io_port == 3) 90 gpiommgpio->control[control_port] |= BIT(4); 91 else 92 gpiommgpio->control[control_port] |= BIT(1); 93 } 94 95 control = BIT(7) | gpiommgpio->control[control_port]; 96 outb(control, control_addr); 97 98 spin_unlock_irqrestore(&gpiommgpio->lock, flags); 99 100 return 0; 101 } 102 103 static int gpiomm_gpio_direction_output(struct gpio_chip *chip, 104 unsigned int offset, int value) 105 { 106 struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 107 const unsigned int io_port = offset / 8; 108 const unsigned int control_port = io_port / 3; 109 const unsigned int mask = BIT(offset % 8); 110 const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4; 111 const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port; 112 unsigned long flags; 113 unsigned int control; 114 115 spin_lock_irqsave(&gpiommgpio->lock, flags); 116 117 /* Check if configuring Port C */ 118 if (io_port == 2 || io_port == 5) { 119 /* Port C can be configured by nibble */ 120 if (offset % 8 > 3) { 121 gpiommgpio->io_state[io_port] &= 0x0F; 122 gpiommgpio->control[control_port] &= ~BIT(3); 123 } else { 124 gpiommgpio->io_state[io_port] &= 0xF0; 125 gpiommgpio->control[control_port] &= ~BIT(0); 126 } 127 } else { 128 gpiommgpio->io_state[io_port] &= 0x00; 129 if (io_port == 0 || io_port == 3) 130 gpiommgpio->control[control_port] &= ~BIT(4); 131 else 132 gpiommgpio->control[control_port] &= ~BIT(1); 133 } 134 135 if (value) 136 gpiommgpio->out_state[io_port] |= mask; 137 else 138 gpiommgpio->out_state[io_port] &= ~mask; 139 140 control = BIT(7) | gpiommgpio->control[control_port]; 141 outb(control, control_addr); 142 143 outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); 144 145 spin_unlock_irqrestore(&gpiommgpio->lock, flags); 146 147 return 0; 148 } 149 150 static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) 151 { 152 struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 153 const unsigned int port = offset / 8; 154 const unsigned int mask = BIT(offset % 8); 155 const unsigned int in_port = (port > 2) ? port + 1 : port; 156 unsigned long flags; 157 unsigned int port_state; 158 159 spin_lock_irqsave(&gpiommgpio->lock, flags); 160 161 /* ensure that GPIO is set for input */ 162 if (!(gpiommgpio->io_state[port] & mask)) { 163 spin_unlock_irqrestore(&gpiommgpio->lock, flags); 164 return -EINVAL; 165 } 166 167 port_state = inb(gpiommgpio->base + in_port); 168 169 spin_unlock_irqrestore(&gpiommgpio->lock, flags); 170 171 return !!(port_state & mask); 172 } 173 174 static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, 175 int value) 176 { 177 struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 178 const unsigned int port = offset / 8; 179 const unsigned int mask = BIT(offset % 8); 180 const unsigned int out_port = (port > 2) ? port + 1 : port; 181 unsigned long flags; 182 183 spin_lock_irqsave(&gpiommgpio->lock, flags); 184 185 if (value) 186 gpiommgpio->out_state[port] |= mask; 187 else 188 gpiommgpio->out_state[port] &= ~mask; 189 190 outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); 191 192 spin_unlock_irqrestore(&gpiommgpio->lock, flags); 193 } 194 195 static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, 196 unsigned long *mask, unsigned long *bits) 197 { 198 struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 199 unsigned int i; 200 const unsigned int gpio_reg_size = 8; 201 unsigned int port; 202 unsigned int out_port; 203 unsigned int bitmask; 204 unsigned long flags; 205 206 /* set bits are evaluated a gpio register size at a time */ 207 for (i = 0; i < chip->ngpio; i += gpio_reg_size) { 208 /* no more set bits in this mask word; skip to the next word */ 209 if (!mask[BIT_WORD(i)]) { 210 i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size; 211 continue; 212 } 213 214 port = i / gpio_reg_size; 215 out_port = (port > 2) ? port + 1 : port; 216 bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)]; 217 218 spin_lock_irqsave(&gpiommgpio->lock, flags); 219 220 /* update output state data and set device gpio register */ 221 gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)]; 222 gpiommgpio->out_state[port] |= bitmask; 223 outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); 224 225 spin_unlock_irqrestore(&gpiommgpio->lock, flags); 226 227 /* prepare for next gpio register set */ 228 mask[BIT_WORD(i)] >>= gpio_reg_size; 229 bits[BIT_WORD(i)] >>= gpio_reg_size; 230 } 231 } 232 233 static int gpiomm_probe(struct device *dev, unsigned int id) 234 { 235 struct gpiomm_gpio *gpiommgpio; 236 const char *const name = dev_name(dev); 237 int err; 238 239 gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL); 240 if (!gpiommgpio) 241 return -ENOMEM; 242 243 if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) { 244 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 245 base[id], base[id] + GPIOMM_EXTENT); 246 return -EBUSY; 247 } 248 249 gpiommgpio->chip.label = name; 250 gpiommgpio->chip.parent = dev; 251 gpiommgpio->chip.owner = THIS_MODULE; 252 gpiommgpio->chip.base = -1; 253 gpiommgpio->chip.ngpio = 48; 254 gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; 255 gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; 256 gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; 257 gpiommgpio->chip.get = gpiomm_gpio_get; 258 gpiommgpio->chip.set = gpiomm_gpio_set; 259 gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; 260 gpiommgpio->base = base[id]; 261 262 spin_lock_init(&gpiommgpio->lock); 263 264 err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); 265 if (err) { 266 dev_err(dev, "GPIO registering failed (%d)\n", err); 267 return err; 268 } 269 270 /* initialize all GPIO as output */ 271 outb(0x80, base[id] + 3); 272 outb(0x00, base[id]); 273 outb(0x00, base[id] + 1); 274 outb(0x00, base[id] + 2); 275 outb(0x80, base[id] + 7); 276 outb(0x00, base[id] + 4); 277 outb(0x00, base[id] + 5); 278 outb(0x00, base[id] + 6); 279 280 return 0; 281 } 282 283 static struct isa_driver gpiomm_driver = { 284 .probe = gpiomm_probe, 285 .driver = { 286 .name = "gpio-mm" 287 }, 288 }; 289 290 module_isa_driver(gpiomm_driver, num_gpiomm); 291 292 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 293 MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver"); 294 MODULE_LICENSE("GPL v2"); 295