summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2021-04-27 22:23:07 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-05-10 09:18:40 +0200
commit109a9487f5565e798129e69b6a8fc53b083be470 (patch)
tree952294d81f5da7cecd231199129946179eda05fd /drivers
parent8f9ef2d9ab22f4d9e1047661994bc608e98fd467 (diff)
downloadbarebox-109a9487f5565e798129e69b6a8fc53b083be470.tar.gz
barebox-109a9487f5565e798129e69b6a8fc53b083be470.tar.xz
gpio: add SiFive GPIO controller support
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@pengutronix.de> Link: https://lore.barebox.org/20210427202309.32077-10-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-sifive.c87
3 files changed, 95 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 261b6e6662..a8ee9e58b8 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 77dcf58f64..25e12105d8 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 0000000000..63f2c097e4
--- /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);