16ea5dcdfSWilliam Breathitt Gray /* 26ea5dcdfSWilliam Breathitt Gray * GPIO driver for the Diamond Systems GPIO-MM 36ea5dcdfSWilliam Breathitt Gray * Copyright (C) 2016 William Breathitt Gray 46ea5dcdfSWilliam Breathitt Gray * 56ea5dcdfSWilliam Breathitt Gray * This program is free software; you can redistribute it and/or modify 66ea5dcdfSWilliam Breathitt Gray * it under the terms of the GNU General Public License, version 2, as 76ea5dcdfSWilliam Breathitt Gray * published by the Free Software Foundation. 86ea5dcdfSWilliam Breathitt Gray * 96ea5dcdfSWilliam Breathitt Gray * This program is distributed in the hope that it will be useful, but 106ea5dcdfSWilliam Breathitt Gray * WITHOUT ANY WARRANTY; without even the implied warranty of 116ea5dcdfSWilliam Breathitt Gray * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 126ea5dcdfSWilliam Breathitt Gray * General Public License for more details. 136ea5dcdfSWilliam Breathitt Gray * 146ea5dcdfSWilliam Breathitt Gray * This driver supports the following Diamond Systems devices: GPIO-MM and 156ea5dcdfSWilliam Breathitt Gray * GPIO-MM-12. 166ea5dcdfSWilliam Breathitt Gray */ 176ea5dcdfSWilliam Breathitt Gray #include <linux/bitops.h> 186ea5dcdfSWilliam Breathitt Gray #include <linux/device.h> 196ea5dcdfSWilliam Breathitt Gray #include <linux/errno.h> 206ea5dcdfSWilliam Breathitt Gray #include <linux/gpio/driver.h> 216ea5dcdfSWilliam Breathitt Gray #include <linux/io.h> 226ea5dcdfSWilliam Breathitt Gray #include <linux/ioport.h> 236ea5dcdfSWilliam Breathitt Gray #include <linux/isa.h> 246ea5dcdfSWilliam Breathitt Gray #include <linux/kernel.h> 256ea5dcdfSWilliam Breathitt Gray #include <linux/module.h> 266ea5dcdfSWilliam Breathitt Gray #include <linux/moduleparam.h> 276ea5dcdfSWilliam Breathitt Gray #include <linux/spinlock.h> 286ea5dcdfSWilliam Breathitt Gray 296ea5dcdfSWilliam Breathitt Gray #define GPIOMM_EXTENT 8 306ea5dcdfSWilliam Breathitt Gray #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) 316ea5dcdfSWilliam Breathitt Gray 326ea5dcdfSWilliam Breathitt Gray static unsigned int base[MAX_NUM_GPIOMM]; 336ea5dcdfSWilliam Breathitt Gray static unsigned int num_gpiomm; 346ea5dcdfSWilliam Breathitt Gray module_param_array(base, uint, &num_gpiomm, 0); 356ea5dcdfSWilliam Breathitt Gray MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); 366ea5dcdfSWilliam Breathitt Gray 376ea5dcdfSWilliam Breathitt Gray /** 386ea5dcdfSWilliam Breathitt Gray * struct gpiomm_gpio - GPIO device private data structure 396ea5dcdfSWilliam Breathitt Gray * @chip: instance of the gpio_chip 406ea5dcdfSWilliam Breathitt Gray * @io_state: bit I/O state (whether bit is set to input or output) 416ea5dcdfSWilliam Breathitt Gray * @out_state: output bits state 426ea5dcdfSWilliam Breathitt Gray * @control: Control registers state 436ea5dcdfSWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 446ea5dcdfSWilliam Breathitt Gray * @base: base port address of the GPIO device 456ea5dcdfSWilliam Breathitt Gray */ 466ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio { 476ea5dcdfSWilliam Breathitt Gray struct gpio_chip chip; 486ea5dcdfSWilliam Breathitt Gray unsigned char io_state[6]; 496ea5dcdfSWilliam Breathitt Gray unsigned char out_state[6]; 506ea5dcdfSWilliam Breathitt Gray unsigned char control[2]; 516ea5dcdfSWilliam Breathitt Gray spinlock_t lock; 526ea5dcdfSWilliam Breathitt Gray unsigned int base; 536ea5dcdfSWilliam Breathitt Gray }; 546ea5dcdfSWilliam Breathitt Gray 556ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_get_direction(struct gpio_chip *chip, 566ea5dcdfSWilliam Breathitt Gray unsigned int offset) 576ea5dcdfSWilliam Breathitt Gray { 586ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 596ea5dcdfSWilliam Breathitt Gray const unsigned int port = offset / 8; 606ea5dcdfSWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 616ea5dcdfSWilliam Breathitt Gray 626ea5dcdfSWilliam Breathitt Gray return !!(gpiommgpio->io_state[port] & mask); 636ea5dcdfSWilliam Breathitt Gray } 646ea5dcdfSWilliam Breathitt Gray 656ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_direction_input(struct gpio_chip *chip, 666ea5dcdfSWilliam Breathitt Gray unsigned int offset) 676ea5dcdfSWilliam Breathitt Gray { 686ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 696ea5dcdfSWilliam Breathitt Gray const unsigned int io_port = offset / 8; 706ea5dcdfSWilliam Breathitt Gray const unsigned int control_port = io_port / 3; 716ea5dcdfSWilliam Breathitt Gray const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4; 726ea5dcdfSWilliam Breathitt Gray unsigned long flags; 736ea5dcdfSWilliam Breathitt Gray unsigned int control; 746ea5dcdfSWilliam Breathitt Gray 756ea5dcdfSWilliam Breathitt Gray spin_lock_irqsave(&gpiommgpio->lock, flags); 766ea5dcdfSWilliam Breathitt Gray 776ea5dcdfSWilliam Breathitt Gray /* Check if configuring Port C */ 786ea5dcdfSWilliam Breathitt Gray if (io_port == 2 || io_port == 5) { 796ea5dcdfSWilliam Breathitt Gray /* Port C can be configured by nibble */ 806ea5dcdfSWilliam Breathitt Gray if (offset % 8 > 3) { 816ea5dcdfSWilliam Breathitt Gray gpiommgpio->io_state[io_port] |= 0xF0; 826ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] |= BIT(3); 836ea5dcdfSWilliam Breathitt Gray } else { 846ea5dcdfSWilliam Breathitt Gray gpiommgpio->io_state[io_port] |= 0x0F; 856ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] |= BIT(0); 866ea5dcdfSWilliam Breathitt Gray } 876ea5dcdfSWilliam Breathitt Gray } else { 886ea5dcdfSWilliam Breathitt Gray gpiommgpio->io_state[io_port] |= 0xFF; 896ea5dcdfSWilliam Breathitt Gray if (io_port == 0 || io_port == 3) 906ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] |= BIT(4); 916ea5dcdfSWilliam Breathitt Gray else 926ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] |= BIT(1); 936ea5dcdfSWilliam Breathitt Gray } 946ea5dcdfSWilliam Breathitt Gray 956ea5dcdfSWilliam Breathitt Gray control = BIT(7) | gpiommgpio->control[control_port]; 966ea5dcdfSWilliam Breathitt Gray outb(control, control_addr); 976ea5dcdfSWilliam Breathitt Gray 986ea5dcdfSWilliam Breathitt Gray spin_unlock_irqrestore(&gpiommgpio->lock, flags); 996ea5dcdfSWilliam Breathitt Gray 1006ea5dcdfSWilliam Breathitt Gray return 0; 1016ea5dcdfSWilliam Breathitt Gray } 1026ea5dcdfSWilliam Breathitt Gray 1036ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_direction_output(struct gpio_chip *chip, 1046ea5dcdfSWilliam Breathitt Gray unsigned int offset, int value) 1056ea5dcdfSWilliam Breathitt Gray { 1066ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 1076ea5dcdfSWilliam Breathitt Gray const unsigned int io_port = offset / 8; 1086ea5dcdfSWilliam Breathitt Gray const unsigned int control_port = io_port / 3; 1096ea5dcdfSWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 1106ea5dcdfSWilliam Breathitt Gray const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4; 1116ea5dcdfSWilliam Breathitt Gray const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port; 1126ea5dcdfSWilliam Breathitt Gray unsigned long flags; 1136ea5dcdfSWilliam Breathitt Gray unsigned int control; 1146ea5dcdfSWilliam Breathitt Gray 1156ea5dcdfSWilliam Breathitt Gray spin_lock_irqsave(&gpiommgpio->lock, flags); 1166ea5dcdfSWilliam Breathitt Gray 1176ea5dcdfSWilliam Breathitt Gray /* Check if configuring Port C */ 1186ea5dcdfSWilliam Breathitt Gray if (io_port == 2 || io_port == 5) { 1196ea5dcdfSWilliam Breathitt Gray /* Port C can be configured by nibble */ 1206ea5dcdfSWilliam Breathitt Gray if (offset % 8 > 3) { 1216ea5dcdfSWilliam Breathitt Gray gpiommgpio->io_state[io_port] &= 0x0F; 1226ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] &= ~BIT(3); 1236ea5dcdfSWilliam Breathitt Gray } else { 1246ea5dcdfSWilliam Breathitt Gray gpiommgpio->io_state[io_port] &= 0xF0; 1256ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] &= ~BIT(0); 1266ea5dcdfSWilliam Breathitt Gray } 1276ea5dcdfSWilliam Breathitt Gray } else { 1286ea5dcdfSWilliam Breathitt Gray gpiommgpio->io_state[io_port] &= 0x00; 1296ea5dcdfSWilliam Breathitt Gray if (io_port == 0 || io_port == 3) 1306ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] &= ~BIT(4); 1316ea5dcdfSWilliam Breathitt Gray else 1326ea5dcdfSWilliam Breathitt Gray gpiommgpio->control[control_port] &= ~BIT(1); 1336ea5dcdfSWilliam Breathitt Gray } 1346ea5dcdfSWilliam Breathitt Gray 1356ea5dcdfSWilliam Breathitt Gray if (value) 1366ea5dcdfSWilliam Breathitt Gray gpiommgpio->out_state[io_port] |= mask; 1376ea5dcdfSWilliam Breathitt Gray else 1386ea5dcdfSWilliam Breathitt Gray gpiommgpio->out_state[io_port] &= ~mask; 1396ea5dcdfSWilliam Breathitt Gray 1406ea5dcdfSWilliam Breathitt Gray control = BIT(7) | gpiommgpio->control[control_port]; 1416ea5dcdfSWilliam Breathitt Gray outb(control, control_addr); 1426ea5dcdfSWilliam Breathitt Gray 1436ea5dcdfSWilliam Breathitt Gray outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); 1446ea5dcdfSWilliam Breathitt Gray 1456ea5dcdfSWilliam Breathitt Gray spin_unlock_irqrestore(&gpiommgpio->lock, flags); 1466ea5dcdfSWilliam Breathitt Gray 1476ea5dcdfSWilliam Breathitt Gray return 0; 1486ea5dcdfSWilliam Breathitt Gray } 1496ea5dcdfSWilliam Breathitt Gray 1506ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) 1516ea5dcdfSWilliam Breathitt Gray { 1526ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 1536ea5dcdfSWilliam Breathitt Gray const unsigned int port = offset / 8; 1546ea5dcdfSWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 1556ea5dcdfSWilliam Breathitt Gray const unsigned int in_port = (port > 2) ? port + 1 : port; 1566ea5dcdfSWilliam Breathitt Gray unsigned long flags; 1576ea5dcdfSWilliam Breathitt Gray unsigned int port_state; 1586ea5dcdfSWilliam Breathitt Gray 1596ea5dcdfSWilliam Breathitt Gray spin_lock_irqsave(&gpiommgpio->lock, flags); 1606ea5dcdfSWilliam Breathitt Gray 1616ea5dcdfSWilliam Breathitt Gray /* ensure that GPIO is set for input */ 1626ea5dcdfSWilliam Breathitt Gray if (!(gpiommgpio->io_state[port] & mask)) { 1636ea5dcdfSWilliam Breathitt Gray spin_unlock_irqrestore(&gpiommgpio->lock, flags); 1646ea5dcdfSWilliam Breathitt Gray return -EINVAL; 1656ea5dcdfSWilliam Breathitt Gray } 1666ea5dcdfSWilliam Breathitt Gray 1676ea5dcdfSWilliam Breathitt Gray port_state = inb(gpiommgpio->base + in_port); 1686ea5dcdfSWilliam Breathitt Gray 1696ea5dcdfSWilliam Breathitt Gray spin_unlock_irqrestore(&gpiommgpio->lock, flags); 1706ea5dcdfSWilliam Breathitt Gray 1716ea5dcdfSWilliam Breathitt Gray return !!(port_state & mask); 1726ea5dcdfSWilliam Breathitt Gray } 1736ea5dcdfSWilliam Breathitt Gray 1746ea5dcdfSWilliam Breathitt Gray static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, 1756ea5dcdfSWilliam Breathitt Gray int value) 1766ea5dcdfSWilliam Breathitt Gray { 1776ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 1786ea5dcdfSWilliam Breathitt Gray const unsigned int port = offset / 8; 1796ea5dcdfSWilliam Breathitt Gray const unsigned int mask = BIT(offset % 8); 1806ea5dcdfSWilliam Breathitt Gray const unsigned int out_port = (port > 2) ? port + 1 : port; 1816ea5dcdfSWilliam Breathitt Gray unsigned long flags; 1826ea5dcdfSWilliam Breathitt Gray 1836ea5dcdfSWilliam Breathitt Gray spin_lock_irqsave(&gpiommgpio->lock, flags); 1846ea5dcdfSWilliam Breathitt Gray 1856ea5dcdfSWilliam Breathitt Gray if (value) 1866ea5dcdfSWilliam Breathitt Gray gpiommgpio->out_state[port] |= mask; 1876ea5dcdfSWilliam Breathitt Gray else 1886ea5dcdfSWilliam Breathitt Gray gpiommgpio->out_state[port] &= ~mask; 1896ea5dcdfSWilliam Breathitt Gray 1906ea5dcdfSWilliam Breathitt Gray outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); 1916ea5dcdfSWilliam Breathitt Gray 1926ea5dcdfSWilliam Breathitt Gray spin_unlock_irqrestore(&gpiommgpio->lock, flags); 1936ea5dcdfSWilliam Breathitt Gray } 1946ea5dcdfSWilliam Breathitt Gray 19565502a12SWilliam Breathitt Gray static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, 19665502a12SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 19765502a12SWilliam Breathitt Gray { 19865502a12SWilliam Breathitt Gray struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); 19965502a12SWilliam Breathitt Gray unsigned int i; 20065502a12SWilliam Breathitt Gray const unsigned int gpio_reg_size = 8; 20165502a12SWilliam Breathitt Gray unsigned int port; 20265502a12SWilliam Breathitt Gray unsigned int out_port; 20365502a12SWilliam Breathitt Gray unsigned int bitmask; 20465502a12SWilliam Breathitt Gray unsigned long flags; 20565502a12SWilliam Breathitt Gray 20665502a12SWilliam Breathitt Gray /* set bits are evaluated a gpio register size at a time */ 20765502a12SWilliam Breathitt Gray for (i = 0; i < chip->ngpio; i += gpio_reg_size) { 20865502a12SWilliam Breathitt Gray /* no more set bits in this mask word; skip to the next word */ 20965502a12SWilliam Breathitt Gray if (!mask[BIT_WORD(i)]) { 21065502a12SWilliam Breathitt Gray i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size; 21165502a12SWilliam Breathitt Gray continue; 21265502a12SWilliam Breathitt Gray } 21365502a12SWilliam Breathitt Gray 21465502a12SWilliam Breathitt Gray port = i / gpio_reg_size; 21565502a12SWilliam Breathitt Gray out_port = (port > 2) ? port + 1 : port; 21665502a12SWilliam Breathitt Gray bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)]; 21765502a12SWilliam Breathitt Gray 21865502a12SWilliam Breathitt Gray spin_lock_irqsave(&gpiommgpio->lock, flags); 21965502a12SWilliam Breathitt Gray 22065502a12SWilliam Breathitt Gray /* update output state data and set device gpio register */ 22165502a12SWilliam Breathitt Gray gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)]; 22265502a12SWilliam Breathitt Gray gpiommgpio->out_state[port] |= bitmask; 22365502a12SWilliam Breathitt Gray outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); 22465502a12SWilliam Breathitt Gray 22565502a12SWilliam Breathitt Gray spin_unlock_irqrestore(&gpiommgpio->lock, flags); 22665502a12SWilliam Breathitt Gray 22765502a12SWilliam Breathitt Gray /* prepare for next gpio register set */ 22865502a12SWilliam Breathitt Gray mask[BIT_WORD(i)] >>= gpio_reg_size; 22965502a12SWilliam Breathitt Gray bits[BIT_WORD(i)] >>= gpio_reg_size; 23065502a12SWilliam Breathitt Gray } 23165502a12SWilliam Breathitt Gray } 23265502a12SWilliam Breathitt Gray 2336ea5dcdfSWilliam Breathitt Gray static int gpiomm_probe(struct device *dev, unsigned int id) 2346ea5dcdfSWilliam Breathitt Gray { 2356ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *gpiommgpio; 2366ea5dcdfSWilliam Breathitt Gray const char *const name = dev_name(dev); 2376ea5dcdfSWilliam Breathitt Gray int err; 2386ea5dcdfSWilliam Breathitt Gray 2396ea5dcdfSWilliam Breathitt Gray gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL); 2406ea5dcdfSWilliam Breathitt Gray if (!gpiommgpio) 2416ea5dcdfSWilliam Breathitt Gray return -ENOMEM; 2426ea5dcdfSWilliam Breathitt Gray 2436ea5dcdfSWilliam Breathitt Gray if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) { 2446ea5dcdfSWilliam Breathitt Gray dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 2456ea5dcdfSWilliam Breathitt Gray base[id], base[id] + GPIOMM_EXTENT); 2466ea5dcdfSWilliam Breathitt Gray return -EBUSY; 2476ea5dcdfSWilliam Breathitt Gray } 2486ea5dcdfSWilliam Breathitt Gray 2496ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.label = name; 2506ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.parent = dev; 2516ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.owner = THIS_MODULE; 2526ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.base = -1; 2536ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.ngpio = 48; 2546ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; 2556ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; 2566ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; 2576ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.get = gpiomm_gpio_get; 2586ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.set = gpiomm_gpio_set; 25965502a12SWilliam Breathitt Gray gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; 2606ea5dcdfSWilliam Breathitt Gray gpiommgpio->base = base[id]; 2616ea5dcdfSWilliam Breathitt Gray 2626ea5dcdfSWilliam Breathitt Gray spin_lock_init(&gpiommgpio->lock); 2636ea5dcdfSWilliam Breathitt Gray 2646ea5dcdfSWilliam Breathitt Gray dev_set_drvdata(dev, gpiommgpio); 2656ea5dcdfSWilliam Breathitt Gray 2666ea5dcdfSWilliam Breathitt Gray err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio); 2676ea5dcdfSWilliam Breathitt Gray if (err) { 2686ea5dcdfSWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 2696ea5dcdfSWilliam Breathitt Gray return err; 2706ea5dcdfSWilliam Breathitt Gray } 2716ea5dcdfSWilliam Breathitt Gray 2726ea5dcdfSWilliam Breathitt Gray /* initialize all GPIO as output */ 2736ea5dcdfSWilliam Breathitt Gray outb(0x80, base[id] + 3); 2746ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id]); 2756ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 1); 2766ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 2); 2776ea5dcdfSWilliam Breathitt Gray outb(0x80, base[id] + 7); 2786ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 4); 2796ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 5); 2806ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 6); 2816ea5dcdfSWilliam Breathitt Gray 2826ea5dcdfSWilliam Breathitt Gray return 0; 2836ea5dcdfSWilliam Breathitt Gray } 2846ea5dcdfSWilliam Breathitt Gray 2856ea5dcdfSWilliam Breathitt Gray static int gpiomm_remove(struct device *dev, unsigned int id) 2866ea5dcdfSWilliam Breathitt Gray { 2876ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev); 2886ea5dcdfSWilliam Breathitt Gray 2896ea5dcdfSWilliam Breathitt Gray gpiochip_remove(&gpiommgpio->chip); 2906ea5dcdfSWilliam Breathitt Gray 2916ea5dcdfSWilliam Breathitt Gray return 0; 2926ea5dcdfSWilliam Breathitt Gray } 2936ea5dcdfSWilliam Breathitt Gray 2946ea5dcdfSWilliam Breathitt Gray static struct isa_driver gpiomm_driver = { 2956ea5dcdfSWilliam Breathitt Gray .probe = gpiomm_probe, 2966ea5dcdfSWilliam Breathitt Gray .driver = { 2976ea5dcdfSWilliam Breathitt Gray .name = "gpio-mm" 2986ea5dcdfSWilliam Breathitt Gray }, 2996ea5dcdfSWilliam Breathitt Gray .remove = gpiomm_remove 3006ea5dcdfSWilliam Breathitt Gray }; 3016ea5dcdfSWilliam Breathitt Gray 3026ea5dcdfSWilliam Breathitt Gray module_isa_driver(gpiomm_driver, num_gpiomm); 3036ea5dcdfSWilliam Breathitt Gray 3046ea5dcdfSWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 3056ea5dcdfSWilliam Breathitt Gray MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver"); 3066ea5dcdfSWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 307