xref: /openbmc/linux/drivers/gpio/gpio-gpio-mm.c (revision 1802d0be)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26ea5dcdfSWilliam Breathitt Gray /*
36ea5dcdfSWilliam Breathitt Gray  * GPIO driver for the Diamond Systems GPIO-MM
46ea5dcdfSWilliam Breathitt Gray  * Copyright (C) 2016 William Breathitt Gray
56ea5dcdfSWilliam Breathitt Gray  *
66ea5dcdfSWilliam Breathitt Gray  * This driver supports the following Diamond Systems devices: GPIO-MM and
76ea5dcdfSWilliam Breathitt Gray  * GPIO-MM-12.
86ea5dcdfSWilliam Breathitt Gray  */
941b25131SWilliam Breathitt Gray #include <linux/bitmap.h>
106ea5dcdfSWilliam Breathitt Gray #include <linux/bitops.h>
116ea5dcdfSWilliam Breathitt Gray #include <linux/device.h>
126ea5dcdfSWilliam Breathitt Gray #include <linux/errno.h>
136ea5dcdfSWilliam Breathitt Gray #include <linux/gpio/driver.h>
146ea5dcdfSWilliam Breathitt Gray #include <linux/io.h>
156ea5dcdfSWilliam Breathitt Gray #include <linux/ioport.h>
166ea5dcdfSWilliam Breathitt Gray #include <linux/isa.h>
176ea5dcdfSWilliam Breathitt Gray #include <linux/kernel.h>
186ea5dcdfSWilliam Breathitt Gray #include <linux/module.h>
196ea5dcdfSWilliam Breathitt Gray #include <linux/moduleparam.h>
206ea5dcdfSWilliam Breathitt Gray #include <linux/spinlock.h>
216ea5dcdfSWilliam Breathitt Gray 
226ea5dcdfSWilliam Breathitt Gray #define GPIOMM_EXTENT 8
236ea5dcdfSWilliam Breathitt Gray #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
246ea5dcdfSWilliam Breathitt Gray 
256ea5dcdfSWilliam Breathitt Gray static unsigned int base[MAX_NUM_GPIOMM];
266ea5dcdfSWilliam Breathitt Gray static unsigned int num_gpiomm;
27d759f906SDavid Howells module_param_hw_array(base, uint, ioport, &num_gpiomm, 0);
286ea5dcdfSWilliam Breathitt Gray MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
296ea5dcdfSWilliam Breathitt Gray 
306ea5dcdfSWilliam Breathitt Gray /**
316ea5dcdfSWilliam Breathitt Gray  * struct gpiomm_gpio - GPIO device private data structure
326ea5dcdfSWilliam Breathitt Gray  * @chip:	instance of the gpio_chip
336ea5dcdfSWilliam Breathitt Gray  * @io_state:	bit I/O state (whether bit is set to input or output)
346ea5dcdfSWilliam Breathitt Gray  * @out_state:	output bits state
356ea5dcdfSWilliam Breathitt Gray  * @control:	Control registers state
366ea5dcdfSWilliam Breathitt Gray  * @lock:	synchronization lock to prevent I/O race conditions
376ea5dcdfSWilliam Breathitt Gray  * @base:	base port address of the GPIO device
386ea5dcdfSWilliam Breathitt Gray  */
396ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio {
406ea5dcdfSWilliam Breathitt Gray 	struct gpio_chip chip;
416ea5dcdfSWilliam Breathitt Gray 	unsigned char io_state[6];
426ea5dcdfSWilliam Breathitt Gray 	unsigned char out_state[6];
436ea5dcdfSWilliam Breathitt Gray 	unsigned char control[2];
446ea5dcdfSWilliam Breathitt Gray 	spinlock_t lock;
456ea5dcdfSWilliam Breathitt Gray 	unsigned int base;
466ea5dcdfSWilliam Breathitt Gray };
476ea5dcdfSWilliam Breathitt Gray 
486ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
496ea5dcdfSWilliam Breathitt Gray 	unsigned int offset)
506ea5dcdfSWilliam Breathitt Gray {
516ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
526ea5dcdfSWilliam Breathitt Gray 	const unsigned int port = offset / 8;
536ea5dcdfSWilliam Breathitt Gray 	const unsigned int mask = BIT(offset % 8);
546ea5dcdfSWilliam Breathitt Gray 
556ea5dcdfSWilliam Breathitt Gray 	return !!(gpiommgpio->io_state[port] & mask);
566ea5dcdfSWilliam Breathitt Gray }
576ea5dcdfSWilliam Breathitt Gray 
586ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
596ea5dcdfSWilliam Breathitt Gray 	unsigned int offset)
606ea5dcdfSWilliam Breathitt Gray {
616ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
626ea5dcdfSWilliam Breathitt Gray 	const unsigned int io_port = offset / 8;
636ea5dcdfSWilliam Breathitt Gray 	const unsigned int control_port = io_port / 3;
646ea5dcdfSWilliam Breathitt Gray 	const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
656ea5dcdfSWilliam Breathitt Gray 	unsigned long flags;
666ea5dcdfSWilliam Breathitt Gray 	unsigned int control;
676ea5dcdfSWilliam Breathitt Gray 
686ea5dcdfSWilliam Breathitt Gray 	spin_lock_irqsave(&gpiommgpio->lock, flags);
696ea5dcdfSWilliam Breathitt Gray 
706ea5dcdfSWilliam Breathitt Gray 	/* Check if configuring Port C */
716ea5dcdfSWilliam Breathitt Gray 	if (io_port == 2 || io_port == 5) {
726ea5dcdfSWilliam Breathitt Gray 		/* Port C can be configured by nibble */
736ea5dcdfSWilliam Breathitt Gray 		if (offset % 8 > 3) {
746ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->io_state[io_port] |= 0xF0;
756ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] |= BIT(3);
766ea5dcdfSWilliam Breathitt Gray 		} else {
776ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->io_state[io_port] |= 0x0F;
786ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] |= BIT(0);
796ea5dcdfSWilliam Breathitt Gray 		}
806ea5dcdfSWilliam Breathitt Gray 	} else {
816ea5dcdfSWilliam Breathitt Gray 		gpiommgpio->io_state[io_port] |= 0xFF;
826ea5dcdfSWilliam Breathitt Gray 		if (io_port == 0 || io_port == 3)
836ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] |= BIT(4);
846ea5dcdfSWilliam Breathitt Gray 		else
856ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] |= BIT(1);
866ea5dcdfSWilliam Breathitt Gray 	}
876ea5dcdfSWilliam Breathitt Gray 
886ea5dcdfSWilliam Breathitt Gray 	control = BIT(7) | gpiommgpio->control[control_port];
896ea5dcdfSWilliam Breathitt Gray 	outb(control, control_addr);
906ea5dcdfSWilliam Breathitt Gray 
916ea5dcdfSWilliam Breathitt Gray 	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
926ea5dcdfSWilliam Breathitt Gray 
936ea5dcdfSWilliam Breathitt Gray 	return 0;
946ea5dcdfSWilliam Breathitt Gray }
956ea5dcdfSWilliam Breathitt Gray 
966ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
976ea5dcdfSWilliam Breathitt Gray 	unsigned int offset, int value)
986ea5dcdfSWilliam Breathitt Gray {
996ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
1006ea5dcdfSWilliam Breathitt Gray 	const unsigned int io_port = offset / 8;
1016ea5dcdfSWilliam Breathitt Gray 	const unsigned int control_port = io_port / 3;
1026ea5dcdfSWilliam Breathitt Gray 	const unsigned int mask = BIT(offset % 8);
1036ea5dcdfSWilliam Breathitt Gray 	const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
1046ea5dcdfSWilliam Breathitt Gray 	const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
1056ea5dcdfSWilliam Breathitt Gray 	unsigned long flags;
1066ea5dcdfSWilliam Breathitt Gray 	unsigned int control;
1076ea5dcdfSWilliam Breathitt Gray 
1086ea5dcdfSWilliam Breathitt Gray 	spin_lock_irqsave(&gpiommgpio->lock, flags);
1096ea5dcdfSWilliam Breathitt Gray 
1106ea5dcdfSWilliam Breathitt Gray 	/* Check if configuring Port C */
1116ea5dcdfSWilliam Breathitt Gray 	if (io_port == 2 || io_port == 5) {
1126ea5dcdfSWilliam Breathitt Gray 		/* Port C can be configured by nibble */
1136ea5dcdfSWilliam Breathitt Gray 		if (offset % 8 > 3) {
1146ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->io_state[io_port] &= 0x0F;
1156ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] &= ~BIT(3);
1166ea5dcdfSWilliam Breathitt Gray 		} else {
1176ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->io_state[io_port] &= 0xF0;
1186ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] &= ~BIT(0);
1196ea5dcdfSWilliam Breathitt Gray 		}
1206ea5dcdfSWilliam Breathitt Gray 	} else {
1216ea5dcdfSWilliam Breathitt Gray 		gpiommgpio->io_state[io_port] &= 0x00;
1226ea5dcdfSWilliam Breathitt Gray 		if (io_port == 0 || io_port == 3)
1236ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] &= ~BIT(4);
1246ea5dcdfSWilliam Breathitt Gray 		else
1256ea5dcdfSWilliam Breathitt Gray 			gpiommgpio->control[control_port] &= ~BIT(1);
1266ea5dcdfSWilliam Breathitt Gray 	}
1276ea5dcdfSWilliam Breathitt Gray 
1286ea5dcdfSWilliam Breathitt Gray 	if (value)
1296ea5dcdfSWilliam Breathitt Gray 		gpiommgpio->out_state[io_port] |= mask;
1306ea5dcdfSWilliam Breathitt Gray 	else
1316ea5dcdfSWilliam Breathitt Gray 		gpiommgpio->out_state[io_port] &= ~mask;
1326ea5dcdfSWilliam Breathitt Gray 
1336ea5dcdfSWilliam Breathitt Gray 	control = BIT(7) | gpiommgpio->control[control_port];
1346ea5dcdfSWilliam Breathitt Gray 	outb(control, control_addr);
1356ea5dcdfSWilliam Breathitt Gray 
1366ea5dcdfSWilliam Breathitt Gray 	outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
1376ea5dcdfSWilliam Breathitt Gray 
1386ea5dcdfSWilliam Breathitt Gray 	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
1396ea5dcdfSWilliam Breathitt Gray 
1406ea5dcdfSWilliam Breathitt Gray 	return 0;
1416ea5dcdfSWilliam Breathitt Gray }
1426ea5dcdfSWilliam Breathitt Gray 
1436ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
1446ea5dcdfSWilliam Breathitt Gray {
1456ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
1466ea5dcdfSWilliam Breathitt Gray 	const unsigned int port = offset / 8;
1476ea5dcdfSWilliam Breathitt Gray 	const unsigned int mask = BIT(offset % 8);
1486ea5dcdfSWilliam Breathitt Gray 	const unsigned int in_port = (port > 2) ? port + 1 : port;
1496ea5dcdfSWilliam Breathitt Gray 	unsigned long flags;
1506ea5dcdfSWilliam Breathitt Gray 	unsigned int port_state;
1516ea5dcdfSWilliam Breathitt Gray 
1526ea5dcdfSWilliam Breathitt Gray 	spin_lock_irqsave(&gpiommgpio->lock, flags);
1536ea5dcdfSWilliam Breathitt Gray 
1546ea5dcdfSWilliam Breathitt Gray 	/* ensure that GPIO is set for input */
1556ea5dcdfSWilliam Breathitt Gray 	if (!(gpiommgpio->io_state[port] & mask)) {
1566ea5dcdfSWilliam Breathitt Gray 		spin_unlock_irqrestore(&gpiommgpio->lock, flags);
1576ea5dcdfSWilliam Breathitt Gray 		return -EINVAL;
1586ea5dcdfSWilliam Breathitt Gray 	}
1596ea5dcdfSWilliam Breathitt Gray 
1606ea5dcdfSWilliam Breathitt Gray 	port_state = inb(gpiommgpio->base + in_port);
1616ea5dcdfSWilliam Breathitt Gray 
1626ea5dcdfSWilliam Breathitt Gray 	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
1636ea5dcdfSWilliam Breathitt Gray 
1646ea5dcdfSWilliam Breathitt Gray 	return !!(port_state & mask);
1656ea5dcdfSWilliam Breathitt Gray }
1666ea5dcdfSWilliam Breathitt Gray 
16741b25131SWilliam Breathitt Gray static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
16841b25131SWilliam Breathitt Gray 	unsigned long *bits)
16941b25131SWilliam Breathitt Gray {
17041b25131SWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
17141b25131SWilliam Breathitt Gray 	size_t i;
172413f9e99SColin Ian King 	static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
17341b25131SWilliam Breathitt Gray 	const unsigned int gpio_reg_size = 8;
17441b25131SWilliam Breathitt Gray 	unsigned int bits_offset;
17541b25131SWilliam Breathitt Gray 	size_t word_index;
17641b25131SWilliam Breathitt Gray 	unsigned int word_offset;
17741b25131SWilliam Breathitt Gray 	unsigned long word_mask;
17841b25131SWilliam Breathitt Gray 	const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
17941b25131SWilliam Breathitt Gray 	unsigned long port_state;
18041b25131SWilliam Breathitt Gray 
18141b25131SWilliam Breathitt Gray 	/* clear bits array to a clean slate */
18241b25131SWilliam Breathitt Gray 	bitmap_zero(bits, chip->ngpio);
18341b25131SWilliam Breathitt Gray 
18441b25131SWilliam Breathitt Gray 	/* get bits are evaluated a gpio port register at a time */
18541b25131SWilliam Breathitt Gray 	for (i = 0; i < ARRAY_SIZE(ports); i++) {
18641b25131SWilliam Breathitt Gray 		/* gpio offset in bits array */
18741b25131SWilliam Breathitt Gray 		bits_offset = i * gpio_reg_size;
18841b25131SWilliam Breathitt Gray 
18941b25131SWilliam Breathitt Gray 		/* word index for bits array */
19041b25131SWilliam Breathitt Gray 		word_index = BIT_WORD(bits_offset);
19141b25131SWilliam Breathitt Gray 
19241b25131SWilliam Breathitt Gray 		/* gpio offset within current word of bits array */
19341b25131SWilliam Breathitt Gray 		word_offset = bits_offset % BITS_PER_LONG;
19441b25131SWilliam Breathitt Gray 
19541b25131SWilliam Breathitt Gray 		/* mask of get bits for current gpio within current word */
19641b25131SWilliam Breathitt Gray 		word_mask = mask[word_index] & (port_mask << word_offset);
19741b25131SWilliam Breathitt Gray 		if (!word_mask) {
19841b25131SWilliam Breathitt Gray 			/* no get bits in this port so skip to next one */
19941b25131SWilliam Breathitt Gray 			continue;
20041b25131SWilliam Breathitt Gray 		}
20141b25131SWilliam Breathitt Gray 
20241b25131SWilliam Breathitt Gray 		/* read bits from current gpio port */
20341b25131SWilliam Breathitt Gray 		port_state = inb(gpiommgpio->base + ports[i]);
20441b25131SWilliam Breathitt Gray 
20541b25131SWilliam Breathitt Gray 		/* store acquired bits at respective bits array offset */
2063bfbc440SWilliam Breathitt Gray 		bits[word_index] |= (port_state << word_offset) & word_mask;
20741b25131SWilliam Breathitt Gray 	}
20841b25131SWilliam Breathitt Gray 
20941b25131SWilliam Breathitt Gray 	return 0;
21041b25131SWilliam Breathitt Gray }
21141b25131SWilliam Breathitt Gray 
2126ea5dcdfSWilliam Breathitt Gray static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
2136ea5dcdfSWilliam Breathitt Gray 	int value)
2146ea5dcdfSWilliam Breathitt Gray {
2156ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
2166ea5dcdfSWilliam Breathitt Gray 	const unsigned int port = offset / 8;
2176ea5dcdfSWilliam Breathitt Gray 	const unsigned int mask = BIT(offset % 8);
2186ea5dcdfSWilliam Breathitt Gray 	const unsigned int out_port = (port > 2) ? port + 1 : port;
2196ea5dcdfSWilliam Breathitt Gray 	unsigned long flags;
2206ea5dcdfSWilliam Breathitt Gray 
2216ea5dcdfSWilliam Breathitt Gray 	spin_lock_irqsave(&gpiommgpio->lock, flags);
2226ea5dcdfSWilliam Breathitt Gray 
2236ea5dcdfSWilliam Breathitt Gray 	if (value)
2246ea5dcdfSWilliam Breathitt Gray 		gpiommgpio->out_state[port] |= mask;
2256ea5dcdfSWilliam Breathitt Gray 	else
2266ea5dcdfSWilliam Breathitt Gray 		gpiommgpio->out_state[port] &= ~mask;
2276ea5dcdfSWilliam Breathitt Gray 
2286ea5dcdfSWilliam Breathitt Gray 	outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
2296ea5dcdfSWilliam Breathitt Gray 
2306ea5dcdfSWilliam Breathitt Gray 	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
2316ea5dcdfSWilliam Breathitt Gray }
2326ea5dcdfSWilliam Breathitt Gray 
23365502a12SWilliam Breathitt Gray static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
23465502a12SWilliam Breathitt Gray 	unsigned long *mask, unsigned long *bits)
23565502a12SWilliam Breathitt Gray {
23665502a12SWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
23765502a12SWilliam Breathitt Gray 	unsigned int i;
23865502a12SWilliam Breathitt Gray 	const unsigned int gpio_reg_size = 8;
23965502a12SWilliam Breathitt Gray 	unsigned int port;
24065502a12SWilliam Breathitt Gray 	unsigned int out_port;
24165502a12SWilliam Breathitt Gray 	unsigned int bitmask;
24265502a12SWilliam Breathitt Gray 	unsigned long flags;
24365502a12SWilliam Breathitt Gray 
24465502a12SWilliam Breathitt Gray 	/* set bits are evaluated a gpio register size at a time */
24565502a12SWilliam Breathitt Gray 	for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
24665502a12SWilliam Breathitt Gray 		/* no more set bits in this mask word; skip to the next word */
24765502a12SWilliam Breathitt Gray 		if (!mask[BIT_WORD(i)]) {
24865502a12SWilliam Breathitt Gray 			i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
24965502a12SWilliam Breathitt Gray 			continue;
25065502a12SWilliam Breathitt Gray 		}
25165502a12SWilliam Breathitt Gray 
25265502a12SWilliam Breathitt Gray 		port = i / gpio_reg_size;
25365502a12SWilliam Breathitt Gray 		out_port = (port > 2) ? port + 1 : port;
25465502a12SWilliam Breathitt Gray 		bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
25565502a12SWilliam Breathitt Gray 
25665502a12SWilliam Breathitt Gray 		spin_lock_irqsave(&gpiommgpio->lock, flags);
25765502a12SWilliam Breathitt Gray 
25865502a12SWilliam Breathitt Gray 		/* update output state data and set device gpio register */
25965502a12SWilliam Breathitt Gray 		gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)];
26065502a12SWilliam Breathitt Gray 		gpiommgpio->out_state[port] |= bitmask;
26165502a12SWilliam Breathitt Gray 		outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
26265502a12SWilliam Breathitt Gray 
26365502a12SWilliam Breathitt Gray 		spin_unlock_irqrestore(&gpiommgpio->lock, flags);
26465502a12SWilliam Breathitt Gray 
26565502a12SWilliam Breathitt Gray 		/* prepare for next gpio register set */
26665502a12SWilliam Breathitt Gray 		mask[BIT_WORD(i)] >>= gpio_reg_size;
26765502a12SWilliam Breathitt Gray 		bits[BIT_WORD(i)] >>= gpio_reg_size;
26865502a12SWilliam Breathitt Gray 	}
26965502a12SWilliam Breathitt Gray }
27065502a12SWilliam Breathitt Gray 
271210b4bdeSWilliam Breathitt Gray #define GPIOMM_NGPIO 48
272210b4bdeSWilliam Breathitt Gray static const char *gpiomm_names[GPIOMM_NGPIO] = {
273210b4bdeSWilliam Breathitt Gray 	"Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5",
274210b4bdeSWilliam Breathitt Gray 	"Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3",
275210b4bdeSWilliam Breathitt Gray 	"Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1",
276210b4bdeSWilliam Breathitt Gray 	"Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7",
277210b4bdeSWilliam Breathitt Gray 	"Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5",
278210b4bdeSWilliam Breathitt Gray 	"Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3",
279210b4bdeSWilliam Breathitt Gray 	"Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1",
280210b4bdeSWilliam Breathitt Gray 	"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
281210b4bdeSWilliam Breathitt Gray };
282210b4bdeSWilliam Breathitt Gray 
2836ea5dcdfSWilliam Breathitt Gray static int gpiomm_probe(struct device *dev, unsigned int id)
2846ea5dcdfSWilliam Breathitt Gray {
2856ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *gpiommgpio;
2866ea5dcdfSWilliam Breathitt Gray 	const char *const name = dev_name(dev);
2876ea5dcdfSWilliam Breathitt Gray 	int err;
2886ea5dcdfSWilliam Breathitt Gray 
2896ea5dcdfSWilliam Breathitt Gray 	gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
2906ea5dcdfSWilliam Breathitt Gray 	if (!gpiommgpio)
2916ea5dcdfSWilliam Breathitt Gray 		return -ENOMEM;
2926ea5dcdfSWilliam Breathitt Gray 
2936ea5dcdfSWilliam Breathitt Gray 	if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
2946ea5dcdfSWilliam Breathitt Gray 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
2956ea5dcdfSWilliam Breathitt Gray 			base[id], base[id] + GPIOMM_EXTENT);
2966ea5dcdfSWilliam Breathitt Gray 		return -EBUSY;
2976ea5dcdfSWilliam Breathitt Gray 	}
2986ea5dcdfSWilliam Breathitt Gray 
2996ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.label = name;
3006ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.parent = dev;
3016ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.owner = THIS_MODULE;
3026ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.base = -1;
303210b4bdeSWilliam Breathitt Gray 	gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
304210b4bdeSWilliam Breathitt Gray 	gpiommgpio->chip.names = gpiomm_names;
3056ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
3066ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
3076ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
3086ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.get = gpiomm_gpio_get;
30941b25131SWilliam Breathitt Gray 	gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
3106ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.set = gpiomm_gpio_set;
31165502a12SWilliam Breathitt Gray 	gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
3126ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->base = base[id];
3136ea5dcdfSWilliam Breathitt Gray 
3146ea5dcdfSWilliam Breathitt Gray 	spin_lock_init(&gpiommgpio->lock);
3156ea5dcdfSWilliam Breathitt Gray 
3162141b0a1SWilliam Breathitt Gray 	err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
3176ea5dcdfSWilliam Breathitt Gray 	if (err) {
3186ea5dcdfSWilliam Breathitt Gray 		dev_err(dev, "GPIO registering failed (%d)\n", err);
3196ea5dcdfSWilliam Breathitt Gray 		return err;
3206ea5dcdfSWilliam Breathitt Gray 	}
3216ea5dcdfSWilliam Breathitt Gray 
3226ea5dcdfSWilliam Breathitt Gray 	/* initialize all GPIO as output */
3236ea5dcdfSWilliam Breathitt Gray 	outb(0x80, base[id] + 3);
3246ea5dcdfSWilliam Breathitt Gray 	outb(0x00, base[id]);
3256ea5dcdfSWilliam Breathitt Gray 	outb(0x00, base[id] + 1);
3266ea5dcdfSWilliam Breathitt Gray 	outb(0x00, base[id] + 2);
3276ea5dcdfSWilliam Breathitt Gray 	outb(0x80, base[id] + 7);
3286ea5dcdfSWilliam Breathitt Gray 	outb(0x00, base[id] + 4);
3296ea5dcdfSWilliam Breathitt Gray 	outb(0x00, base[id] + 5);
3306ea5dcdfSWilliam Breathitt Gray 	outb(0x00, base[id] + 6);
3316ea5dcdfSWilliam Breathitt Gray 
3326ea5dcdfSWilliam Breathitt Gray 	return 0;
3336ea5dcdfSWilliam Breathitt Gray }
3346ea5dcdfSWilliam Breathitt Gray 
3356ea5dcdfSWilliam Breathitt Gray static struct isa_driver gpiomm_driver = {
3366ea5dcdfSWilliam Breathitt Gray 	.probe = gpiomm_probe,
3376ea5dcdfSWilliam Breathitt Gray 	.driver = {
3386ea5dcdfSWilliam Breathitt Gray 		.name = "gpio-mm"
3396ea5dcdfSWilliam Breathitt Gray 	},
3406ea5dcdfSWilliam Breathitt Gray };
3416ea5dcdfSWilliam Breathitt Gray 
3426ea5dcdfSWilliam Breathitt Gray module_isa_driver(gpiomm_driver, num_gpiomm);
3436ea5dcdfSWilliam Breathitt Gray 
3446ea5dcdfSWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
3456ea5dcdfSWilliam Breathitt Gray MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
3466ea5dcdfSWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
347