xref: /openbmc/linux/drivers/gpio/gpio-gpio-mm.c (revision 210b4bde)
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