MAINTAINERS | 6 ++ drivers/gpio/Kconfig | 10 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-vortex86.c | 161 +++++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+) create mode 100644 drivers/gpio/gpio-vortex86.c
Add a new simple GPIO device driver for Vortex86 lines of SoCs,
implemented according to their programming reference manual [1].
This is required for detecting the status of the poweroff button and
performing the poweroff sequence on ICOP eBox computers.
IRQs are not implemented as they are available for less than half the
GPIO pins, and they are not the ones required for the poweroff stuff, so
polling will be required anyway.
[1]: http://www.dmp.com.tw/tech/DMP_Vortex86_Series_Software_Programming_Reference_091216.pdf
Signed-off-by: Marcos Del Sol Vives <marcos@orca.pet>
---
MAINTAINERS | 6 ++
drivers/gpio/Kconfig | 10 +++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-vortex86.c | 161 +++++++++++++++++++++++++++++++++++
4 files changed, 178 insertions(+)
create mode 100644 drivers/gpio/gpio-vortex86.c
diff --git a/MAINTAINERS b/MAINTAINERS
index fad6cb025a19..3e0ef902d003 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26574,6 +26574,12 @@ VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
R: Matti Vaittinen <mazziesaccount@gmail.com>
F: drivers/regulator/irq_helpers.c
+VORTEX86 GPIO DRIVER
+R: Marcos Del Sol Vives <marcos@orca.pet>
+L: linux-gpio@vger.kernel.org
+S: Maintained
+F: drivers/gpio/gpio-vortex86.c
+
VRF
M: David Ahern <dsahern@kernel.org>
L: netdev@vger.kernel.org
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 44f922e10db2..b51aa06bb11b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1066,6 +1066,16 @@ config GPIO_TS5500
blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
LCD port.
+config GPIO_VORTEX86
+ tristate "Vortex86 GPIO support"
+ depends on CPU_SUP_VORTEX_32 || COMPILE_TEST
+ help
+ Driver to access the five 8-bit bidirectional GPIO ports present on
+ all DM&P Vortex86 SoCs.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gpio-vortex86.
+
config GPIO_WINBOND
tristate "Winbond Super I/O GPIO support"
select ISA_BUS_API
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 88dedd298256..9d9ce589cc78 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -196,6 +196,7 @@ obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
+obj-$(CONFIG_GPIO_VORTEX86) += gpio-vortex86.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
diff --git a/drivers/gpio/gpio-vortex86.c b/drivers/gpio/gpio-vortex86.c
new file mode 100644
index 000000000000..6f79db392baa
--- /dev/null
+++ b/drivers/gpio/gpio-vortex86.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * GPIO driver for Vortex86 SoCs
+ *
+ * Author: Marcos Del Sol Vives <marcos@orca.pet>
+ *
+ * Based on the it87xx GPIO driver by Diego Elio Pettenò
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/gpio/driver.h>
+#include <linux/spinlock.h>
+
+#define GPIO_PORTS 5
+#define GPIO_PER_PORT 8
+#define GPIO_COUNT (GPIO_PORTS * GPIO_PER_PORT)
+
+#define GPIO_DATA_BASE 0x78
+#define GPIO_DIRECTION_BASE 0x98
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+static int vortex86_gpio_get(struct gpio_chip *chip, unsigned int gpio_num)
+{
+ uint8_t port = gpio_num / GPIO_PER_PORT;
+ uint8_t bit = gpio_num % GPIO_PER_PORT;
+ uint8_t val;
+
+ val = inb(GPIO_DATA_BASE + port);
+ return !!(val & (1 << bit));
+}
+
+static int vortex86_gpio_direction_in(struct gpio_chip *chip, unsigned int gpio_num)
+{
+ uint8_t port = gpio_num / GPIO_PER_PORT;
+ uint8_t bit = gpio_num % GPIO_PER_PORT;
+ unsigned long flags;
+ uint8_t dir;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ dir = inb(GPIO_DIRECTION_BASE + port);
+ dir &= ~(1 << bit); /* 0 = input */
+ outb(dir, GPIO_DIRECTION_BASE + port);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return 0;
+}
+
+static void vortex86_gpio_set(struct gpio_chip *chip, unsigned int gpio_num, int value)
+{
+ uint8_t port = gpio_num / GPIO_PER_PORT;
+ uint8_t bit = gpio_num % GPIO_PER_PORT;
+ unsigned long flags;
+ uint8_t dat;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ dat = inb(GPIO_DATA_BASE + port);
+ if (value)
+ dat |= (1 << bit);
+ else
+ dat &= ~(1 << bit);
+ outb(dat, GPIO_DATA_BASE + port);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+static int vortex86_gpio_direction_out(struct gpio_chip *chip, unsigned int gpio_num, int value)
+{
+ uint8_t port = gpio_num / GPIO_PER_PORT;
+ uint8_t bit = gpio_num % GPIO_PER_PORT;
+ unsigned long flags;
+ uint8_t dir, dat;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ /* Have to set direction first. Else writes to data are ignored. */
+ dir = inb(GPIO_DIRECTION_BASE + port);
+ dir |= (1 << bit); /* 1 = output */
+ outb(dir, GPIO_DIRECTION_BASE + port);
+
+ dat = inb(GPIO_DATA_BASE + port);
+ if (value)
+ dat |= (1 << bit);
+ else
+ dat &= ~(1 << bit);
+ outb(dat, GPIO_DATA_BASE + port);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return 0;
+}
+
+static char labels[GPIO_COUNT][sizeof("vortex86_gpXY")];
+static char *labels_table[GPIO_COUNT];
+
+static struct gpio_chip gpio_chip = {
+ .label = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .get = vortex86_gpio_get,
+ .direction_input = vortex86_gpio_direction_in,
+ .set = vortex86_gpio_set,
+ .direction_output = vortex86_gpio_direction_out,
+ .base = -1,
+ .ngpio = GPIO_COUNT,
+ .names = (const char * const *)labels_table,
+};
+
+static int __init vortex86_gpio_init(void)
+{
+ int rc = 0, i;
+
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_VORTEX) {
+ pr_err("Not a Vortex86 CPU, refusing to load\n");
+ return -ENODEV;
+ }
+
+ /* Request I/O regions for data and direction registers */
+ if (!request_region(GPIO_DATA_BASE, GPIO_PORTS, KBUILD_MODNAME))
+ return -EBUSY;
+ if (!request_region(GPIO_DIRECTION_BASE, GPIO_PORTS, KBUILD_MODNAME)) {
+ release_region(GPIO_DATA_BASE, GPIO_PORTS);
+ return -EBUSY;
+ }
+
+ /* Set up GPIO labels */
+ for (i = 0; i < GPIO_COUNT; i++) {
+ sprintf(labels[i], "vortex86_gp%u%u", i / 8, i % 8);
+ labels_table[i] = &labels[i][0];
+ }
+
+ rc = gpiochip_add_data(&gpio_chip, &gpio_chip);
+ if (rc) {
+ release_region(GPIO_DATA_BASE, GPIO_PORTS);
+ release_region(GPIO_DIRECTION_BASE, GPIO_PORTS);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void __exit vortex86_gpio_exit(void)
+{
+ gpiochip_remove(&gpio_chip);
+ release_region(GPIO_DATA_BASE, GPIO_PORTS);
+ release_region(GPIO_DIRECTION_BASE, GPIO_PORTS);
+}
+
+module_init(vortex86_gpio_init);
+module_exit(vortex86_gpio_exit);
+
+MODULE_AUTHOR("Marcos Del Sol Vives <marcos@orca.pet>");
+MODULE_DESCRIPTION("GPIO driver for Vortex86 SoCs");
+MODULE_LICENSE("GPL");
--
2.34.1
On Mon, Jul 7, 2025 at 3:22 PM Marcos Del Sol Vives <marcos@orca.pet> wrote: > > Add a new simple GPIO device driver for Vortex86 lines of SoCs, > implemented according to their programming reference manual [1]. > > This is required for detecting the status of the poweroff button and > performing the poweroff sequence on ICOP eBox computers. > > IRQs are not implemented as they are available for less than half the > GPIO pins, and they are not the ones required for the poweroff stuff, so > polling will be required anyway. > > [1]: http://www.dmp.com.tw/tech/DMP_Vortex86_Series_Software_Programming_Reference_091216.pdf > > Signed-off-by: Marcos Del Sol Vives <marcos@orca.pet> > --- Hi! This patch immediately rings alarm bells in my head because the chip is not registered with the driver model. It's not 2005 anymore so I'd need some more explanation. IMO there's nothing that makes it impossible to implement this as a platform device. Could you elaborate more on why you chose to implement it this way? Bart
El 07/07/2025 a las 16:10, Bartosz Golaszewski escribió: > Hi! > > This patch immediately rings alarm bells in my head because the chip > is not registered with the driver model. It's not 2005 anymore so I'd > need some more explanation. IMO there's nothing that makes it > impossible to implement this as a platform device. Could you elaborate > more on why you chose to implement it this way? > > Bart Hi Bart! This is my first time writing a driver in general, so the only reason is that the drivers I used as a reference (gpio-it87 and gpio-winbond) look more or less like this. I used those because they are fairly simple and also use fixed x86 ports for control. I see now on gpio-f7188x that it is possible to detect if the SoC matches using platform_driver and platform_device. I guess that is what you were referring to? Should I thus make a V2 patch using those facilities? Thanks, Marcos
© 2016 - 2025 Red Hat, Inc.