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 233210b4bdeSWilliam Breathitt Gray #define GPIOMM_NGPIO 48 234210b4bdeSWilliam Breathitt Gray static const char *gpiomm_names[GPIOMM_NGPIO] = { 235210b4bdeSWilliam Breathitt Gray "Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5", 236210b4bdeSWilliam Breathitt Gray "Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3", 237210b4bdeSWilliam Breathitt Gray "Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1", 238210b4bdeSWilliam Breathitt Gray "Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7", 239210b4bdeSWilliam Breathitt Gray "Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5", 240210b4bdeSWilliam Breathitt Gray "Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3", 241210b4bdeSWilliam Breathitt Gray "Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1", 242210b4bdeSWilliam Breathitt Gray "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7", 243210b4bdeSWilliam Breathitt Gray }; 244210b4bdeSWilliam Breathitt Gray 2456ea5dcdfSWilliam Breathitt Gray static int gpiomm_probe(struct device *dev, unsigned int id) 2466ea5dcdfSWilliam Breathitt Gray { 2476ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio *gpiommgpio; 2486ea5dcdfSWilliam Breathitt Gray const char *const name = dev_name(dev); 2496ea5dcdfSWilliam Breathitt Gray int err; 2506ea5dcdfSWilliam Breathitt Gray 2516ea5dcdfSWilliam Breathitt Gray gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL); 2526ea5dcdfSWilliam Breathitt Gray if (!gpiommgpio) 2536ea5dcdfSWilliam Breathitt Gray return -ENOMEM; 2546ea5dcdfSWilliam Breathitt Gray 2556ea5dcdfSWilliam Breathitt Gray if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) { 2566ea5dcdfSWilliam Breathitt Gray dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 2576ea5dcdfSWilliam Breathitt Gray base[id], base[id] + GPIOMM_EXTENT); 2586ea5dcdfSWilliam Breathitt Gray return -EBUSY; 2596ea5dcdfSWilliam Breathitt Gray } 2606ea5dcdfSWilliam Breathitt Gray 2616ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.label = name; 2626ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.parent = dev; 2636ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.owner = THIS_MODULE; 2646ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.base = -1; 265210b4bdeSWilliam Breathitt Gray gpiommgpio->chip.ngpio = GPIOMM_NGPIO; 266210b4bdeSWilliam Breathitt Gray gpiommgpio->chip.names = gpiomm_names; 2676ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; 2686ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; 2696ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; 2706ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.get = gpiomm_gpio_get; 2716ea5dcdfSWilliam Breathitt Gray gpiommgpio->chip.set = gpiomm_gpio_set; 27265502a12SWilliam Breathitt Gray gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; 2736ea5dcdfSWilliam Breathitt Gray gpiommgpio->base = base[id]; 2746ea5dcdfSWilliam Breathitt Gray 2756ea5dcdfSWilliam Breathitt Gray spin_lock_init(&gpiommgpio->lock); 2766ea5dcdfSWilliam Breathitt Gray 2772141b0a1SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); 2786ea5dcdfSWilliam Breathitt Gray if (err) { 2796ea5dcdfSWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 2806ea5dcdfSWilliam Breathitt Gray return err; 2816ea5dcdfSWilliam Breathitt Gray } 2826ea5dcdfSWilliam Breathitt Gray 2836ea5dcdfSWilliam Breathitt Gray /* initialize all GPIO as output */ 2846ea5dcdfSWilliam Breathitt Gray outb(0x80, base[id] + 3); 2856ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id]); 2866ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 1); 2876ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 2); 2886ea5dcdfSWilliam Breathitt Gray outb(0x80, base[id] + 7); 2896ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 4); 2906ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 5); 2916ea5dcdfSWilliam Breathitt Gray outb(0x00, base[id] + 6); 2926ea5dcdfSWilliam Breathitt Gray 2936ea5dcdfSWilliam Breathitt Gray return 0; 2946ea5dcdfSWilliam Breathitt Gray } 2956ea5dcdfSWilliam Breathitt Gray 2966ea5dcdfSWilliam Breathitt Gray static struct isa_driver gpiomm_driver = { 2976ea5dcdfSWilliam Breathitt Gray .probe = gpiomm_probe, 2986ea5dcdfSWilliam Breathitt Gray .driver = { 2996ea5dcdfSWilliam Breathitt Gray .name = "gpio-mm" 3006ea5dcdfSWilliam Breathitt Gray }, 3016ea5dcdfSWilliam Breathitt Gray }; 3026ea5dcdfSWilliam Breathitt Gray 3036ea5dcdfSWilliam Breathitt Gray module_isa_driver(gpiomm_driver, num_gpiomm); 3046ea5dcdfSWilliam Breathitt Gray 3056ea5dcdfSWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 3066ea5dcdfSWilliam Breathitt Gray MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver"); 3076ea5dcdfSWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 308