lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250709091542.968968-1-marcos@orca.pet>
Date: Wed,  9 Jul 2025 11:15:40 +0200
From: Marcos Del Sol Vives <marcos@...a.pet>
To: linux-kernel@...r.kernel.org
Cc: marcos@...a.pet,
	Linus Walleij <linus.walleij@...aro.org>,
	Bartosz Golaszewski <brgl@...ev.pl>,
	linux-gpio@...r.kernel.org
Subject: [PATCH v2] gpio: vortex: add new GPIO device driver

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@...a.pet>
---
 MAINTAINERS                |   6 ++
 drivers/gpio/Kconfig       |  10 +++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/gpio-vortex.c | 169 +++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+)
 create mode 100644 drivers/gpio/gpio-vortex.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1ff244fe3e1a..0ad462e8cceb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26568,6 +26568,12 @@ VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
 R:	Matti Vaittinen <mazziesaccount@...il.com>
 F:	drivers/regulator/irq_helpers.c
 
+VORTEX GPIO DRIVER
+R:	Marcos Del Sol Vives <marcos@...a.pet>
+L:	linux-gpio@...r.kernel.org
+S:	Maintained
+F:	drivers/gpio/gpio-vortex.c
+
 VRF
 M:	David Ahern <dsahern@...nel.org>
 L:	netdev@...r.kernel.org
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 44f922e10db2..796fd6d43910 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_VORTEX
+	tristate "Vortex86 SoC 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-vortex.
+
 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..d226fc751686 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_VORTEX)		+= gpio-vortex.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-vortex.c b/drivers/gpio/gpio-vortex.c
new file mode 100644
index 000000000000..cf14d56d22d9
--- /dev/null
+++ b/drivers/gpio/gpio-vortex.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  GPIO driver for Vortex86 SoCs
+ *
+ *  Author: Marcos Del Sol Vives <marcos@...a.pet>
+ *
+ *  Based on the it87xx GPIO driver by Diego Elio Pettenò
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.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 struct platform_device *pdev;
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+static int vortex_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 vortex_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 int vortex_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);
+
+	return 0;
+}
+
+static int vortex_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("vortex_gpXY")];
+static char *labels_table[GPIO_COUNT];
+
+static struct gpio_chip gpio_chip = {
+	.label			= KBUILD_MODNAME,
+	.owner			= THIS_MODULE,
+	.get			= vortex_gpio_get,
+	.direction_input	= vortex_gpio_direction_in,
+	.set_rv			= vortex_gpio_set,
+	.direction_output	= vortex_gpio_direction_out,
+	.base			= -1,
+	.ngpio			= GPIO_COUNT,
+	.names			= (const char * const *)labels_table,
+};
+
+static int vortex_gpio_probe(struct platform_device *pdev)
+{
+	/* Set up GPIO labels */
+	for (int i = 0; i < GPIO_COUNT; i++) {
+		sprintf(labels[i], "vortex_gp%u%u", i / 8, i % 8);
+		labels_table[i] = &labels[i][0];
+	}
+
+	return devm_gpiochip_add_data(&pdev->dev, &gpio_chip, NULL);
+}
+
+static struct platform_driver vortex_gpio_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = vortex_gpio_probe,
+};
+
+static struct resource vortex_gpio_resources[] = {
+	DEFINE_RES_IO_NAMED(GPIO_DATA_BASE, GPIO_PORTS, KBUILD_MODNAME " data"),
+	DEFINE_RES_IO_NAMED(GPIO_DIRECTION_BASE, GPIO_PORTS, KBUILD_MODNAME " dir"),
+};
+
+static int __init vortex_gpio_init(void)
+{
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_VORTEX) {
+		pr_err("Not a Vortex86 CPU, refusing to load\n");
+		return -ENODEV;
+	}
+
+	pdev = platform_create_bundle(&vortex_gpio_driver, vortex_gpio_probe,
+			vortex_gpio_resources, ARRAY_SIZE(vortex_gpio_resources),
+			NULL, 0);
+	return PTR_ERR_OR_ZERO(pdev);
+}
+
+static void __exit vortex_gpio_exit(void)
+{
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&vortex_gpio_driver);
+}
+
+module_init(vortex_gpio_init);
+module_exit(vortex_gpio_exit);
+
+MODULE_AUTHOR("Marcos Del Sol Vives <marcos@...a.pet>");
+MODULE_DESCRIPTION("GPIO driver for Vortex86 SoCs");
+MODULE_LICENSE("GPL");
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ