[PATCH 10/12] gpio: add SiFive GPIO controller support

Ahmad Fatoum a.fatoum at pengutronix.de
Tue Apr 27 21:23:07 BST 2021


The SiFive GPIO controller is a straight forward generic gpio-mmio
controller. Only difference is that the number of GPIOs is described by
the number of interrupts in the device tree. Import the Linux v5.12
driver to support it.

Tested with gpio-restart on qemu-system-riscv64 -M sifive_u.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/gpio/Kconfig       |  7 +++
 drivers/gpio/Makefile      |  1 +
 drivers/gpio/gpio-sifive.c | 87 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+)
 create mode 100644 drivers/gpio/gpio-sifive.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 261b6e666257..a8ee9e58b84e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -164,6 +164,13 @@ config GPIO_SX150X
 	  Say Y here to build support for the Semtec Sx150x I2C GPIO
 	  expander chip.
 
+config GPIO_SIFIVE
+	bool "SiFive GPIO support"
+	depends on OF_GPIO
+	select GPIO_GENERIC
+	help
+	  Say yes here to support the GPIO device on SiFive SoCs.
+
 config GPIO_LIBFTDI1
 	bool "libftdi1 driver"
 	depends on SANDBOX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 77dcf58f640d..25e12105d83d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_GPIO_DESIGNWARE)	+= gpio-dw.o
 obj-$(CONFIG_GPIO_SX150X)	+= gpio-sx150x.o
 obj-$(CONFIG_GPIO_VF610)	+= gpio-vf610.o
 obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
+obj-$(CONFIG_GPIO_SIFIVE)	+= gpio-sifive.o
diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
new file mode 100644
index 000000000000..63f2c097e446
--- /dev/null
+++ b/drivers/gpio/gpio-sifive.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 SiFive
+ */
+
+#include <linux/basic_mmio_gpio.h>
+#include <printk.h>
+#include <driver.h>
+#include <errno.h>
+
+#define SIFIVE_GPIO_INPUT_VAL	0x00
+#define SIFIVE_GPIO_INPUT_EN	0x04
+#define SIFIVE_GPIO_OUTPUT_EN	0x08
+#define SIFIVE_GPIO_OUTPUT_VAL	0x0C
+#define SIFIVE_GPIO_RISE_IE	0x18
+#define SIFIVE_GPIO_FALL_IE	0x20
+#define SIFIVE_GPIO_HIGH_IE	0x28
+#define SIFIVE_GPIO_LOW_IE	0x30
+
+#define SIFIVE_GPIO_MAX		32
+
+static int __of_irq_count(struct device_node *np)
+{
+	unsigned npins = 0;
+
+	of_get_property(np, "interrupts", &npins);
+
+	return npins / sizeof(__be32);
+}
+
+static int sifive_gpio_probe(struct device_d *dev)
+{
+	struct bgpio_chip *bgc;
+	struct resource *res;
+	void __iomem *base;
+	int ret, ngpio;
+
+	bgc = xzalloc(sizeof(*bgc));
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res)) {
+		dev_err(dev, "failed to request device memory\n");
+		return PTR_ERR(res);
+	}
+	base = IOMEM(res->start);
+
+	ngpio = __of_irq_count(dev->device_node);
+	if (ngpio > SIFIVE_GPIO_MAX) {
+		dev_err(dev, "Too many GPIO interrupts (max=%d)\n",
+			SIFIVE_GPIO_MAX);
+		return -ENXIO;
+	}
+
+	ret = bgpio_init(bgc, dev, 4,
+			 base + SIFIVE_GPIO_INPUT_VAL,
+			 base + SIFIVE_GPIO_OUTPUT_VAL,
+			 NULL,
+			 base + SIFIVE_GPIO_OUTPUT_EN,
+			 base + SIFIVE_GPIO_INPUT_EN,
+			 0);
+	if (ret) {
+		dev_err(dev, "unable to init generic GPIO\n");
+		return ret;
+	}
+
+	/* Disable all GPIO interrupts */
+	writel(0, base + SIFIVE_GPIO_RISE_IE);
+	writel(0, base + SIFIVE_GPIO_FALL_IE);
+	writel(0, base + SIFIVE_GPIO_HIGH_IE);
+	writel(0, base + SIFIVE_GPIO_LOW_IE);
+
+	bgc->gc.ngpio = ngpio;
+	return gpiochip_add(&bgc->gc);
+}
+
+static const struct of_device_id sifive_gpio_match[] = {
+	{ .compatible = "sifive,gpio0" },
+	{ .compatible = "sifive,fu540-c000-gpio" },
+	{ },
+};
+
+static struct driver_d sifive_gpio_driver = {
+	.name		= "sifive_gpio",
+	.of_compatible	= sifive_gpio_match,
+	.probe		= sifive_gpio_probe,
+};
+postcore_platform_driver(sifive_gpio_driver);
-- 
2.29.2




More information about the barebox mailing list