[PATCH v2 27/29] gpio: add support for StarFive GPIO controller
Ahmad Fatoum
a.fatoum at pengutronix.de
Fri Jun 18 21:50:53 PDT 2021
This imports support for the StarFive GPIO controller from the vendor's
kernel tree.
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
drivers/gpio/Kconfig | 8 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-starfive-vic.c | 177 +++++++++++++++++++++++++++++++
drivers/pinctrl/pinctrl-single.c | 4 +-
include/pinctrl.h | 6 ++
5 files changed, 194 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpio/gpio-starfive-vic.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index a8ee9e58b84e..98a44fbbb578 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -171,6 +171,14 @@ config GPIO_SIFIVE
help
Say yes here to support the GPIO device on SiFive SoCs.
+config GPIO_STARFIVE
+ bool "StarFive GPIO support"
+ depends on SOC_STARFIVE || CROSS_COMPILE
+ depends on OF_GPIO
+ select GPIO_GENERIC
+ help
+ Say yes here to support the GPIO device on StarFive SoCs.
+
config GPIO_LIBFTDI1
bool "libftdi1 driver"
depends on SANDBOX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 25e12105d83d..638cbb19a328 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -24,3 +24,4 @@ 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
+obj-$(CONFIG_GPIO_STARFIVE) += gpio-starfive-vic.o
diff --git a/drivers/gpio/gpio-starfive-vic.c b/drivers/gpio/gpio-starfive-vic.c
new file mode 100644
index 000000000000..baa4f584d5e8
--- /dev/null
+++ b/drivers/gpio/gpio-starfive-vic.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
+ */
+
+#include <linux/basic_mmio_gpio.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <printk.h>
+#include <driver.h>
+#include <errno.h>
+#include <pinctrl.h>
+
+#define GPIO_EN 0x0
+#define GPIO_IS_LOW 0x10
+#define GPIO_IS_HIGH 0x14
+#define GPIO_IBE_LOW 0x18
+#define GPIO_IBE_HIGH 0x1c
+#define GPIO_IEV_LOW 0x20
+#define GPIO_IEV_HIGH 0x24
+#define GPIO_IE_LOW 0x28
+#define GPIO_IE_HIGH 0x2c
+#define GPIO_IC_LOW 0x30
+#define GPIO_IC_HIGH 0x34
+//read only
+#define GPIO_RIS_LOW 0x38
+#define GPIO_RIS_HIGH 0x3c
+#define GPIO_MIS_LOW 0x40
+#define GPIO_MIS_HIGH 0x44
+#define GPIO_DIN_LOW 0x48
+#define GPIO_DIN_HIGH 0x4c
+
+#define GPIO_DOUT_X_REG 0x50
+#define GPIO_DOEN_X_REG 0x54
+
+#define MAX_GPIO 64
+
+struct starfive_gpio {
+ void __iomem *base;
+ struct gpio_chip gc;
+};
+
+#define to_starfive_gpio(gc) container_of(gc, struct starfive_gpio, gc)
+
+static int starfive_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ writel(0x1, chip->base + GPIO_DOEN_X_REG + offset * 8);
+
+ return 0;
+}
+
+static int starfive_direction_output(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+ writel(0x0, chip->base + GPIO_DOEN_X_REG + offset * 8);
+ writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8);
+
+ return 0;
+}
+
+static int starfive_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ return readl(chip->base + GPIO_DOEN_X_REG + offset * 8) & 0x1;
+}
+
+static int starfive_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+ int value;
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ if(offset < 32){
+ value = readl(chip->base + GPIO_DIN_LOW);
+ return (value >> offset) & 0x1;
+ } else {
+ value = readl(chip->base + GPIO_DIN_HIGH);
+ return (value >> (offset - 32)) & 0x1;
+ }
+}
+
+static void starfive_set_value(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return;
+
+ writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8);
+}
+
+static struct gpio_ops starfive_gpio_ops = {
+ .direction_input = starfive_direction_input,
+ .direction_output = starfive_direction_output,
+ .get_direction = starfive_get_direction,
+ .get = starfive_get_value,
+ .set = starfive_set_value,
+};
+
+static int starfive_gpio_probe(struct device_d *dev)
+{
+ struct starfive_gpio *chip;
+ struct resource *res;
+ struct clk *clk;
+ int ret;
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ clk_enable(clk);
+
+ ret = device_reset(dev);
+ if (ret)
+ return ret;
+
+ ret = pinctrl_single_probe(dev);
+ if (ret)
+ return ret;
+
+ res = dev_get_resource(dev, IORESOURCE_MEM, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ chip = xzalloc(sizeof(*chip));
+ chip->base = IOMEM(res->start);
+
+ chip->gc.base = -1;
+ chip->gc.ngpio = MAX_GPIO;
+ chip->gc.dev = dev;
+ chip->gc.ops = &starfive_gpio_ops;
+
+ /* Disable all GPIO interrupts */
+ iowrite32(0, chip->base + GPIO_IE_HIGH);
+ iowrite32(0, chip->base + GPIO_IE_LOW);
+
+ ret = gpiochip_add(&chip->gc);
+ if (ret) {
+ dev_err(dev, "could not add gpiochip\n");
+ gpiochip_remove(&chip->gc);
+ return ret;
+ }
+
+ writel(1, chip->base + GPIO_EN);
+
+ return 0;
+}
+
+static const struct of_device_id starfive_gpio_match[] = {
+ { .compatible = "starfive,gpio0", },
+ { },
+};
+
+static struct driver_d starfive_gpio_driver = {
+ .probe = starfive_gpio_probe,
+ .name = "starfive_gpio",
+ .of_compatible = starfive_gpio_match,
+};
+postcore_platform_driver(starfive_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huan Feng <huan.feng at starfivetech.com>");
+MODULE_DESCRIPTION("Starfive VIC GPIO generator driver");
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index c77466023216..cf2f724d187d 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -128,7 +128,7 @@ static struct pinctrl_ops pcs_ops = {
.set_state = pcs_set_state,
};
-static int pcs_probe(struct device_d *dev)
+int pinctrl_single_probe(struct device_d *dev)
{
struct resource *iores;
struct pinctrl_single *pcs;
@@ -215,7 +215,7 @@ static __maybe_unused struct of_device_id pcs_dt_ids[] = {
static struct driver_d pcs_driver = {
.name = "pinctrl-single",
- .probe = pcs_probe,
+ .probe = pinctrl_single_probe,
.of_compatible = DRV_OF_COMPAT(pcs_dt_ids),
};
diff --git a/include/pinctrl.h b/include/pinctrl.h
index 0fd7f491189c..a628c3aac95b 100644
--- a/include/pinctrl.h
+++ b/include/pinctrl.h
@@ -29,6 +29,7 @@ int of_pinctrl_select_state_default(struct device_node *np);
int pinctrl_gpio_direction_input(unsigned pin);
int pinctrl_gpio_direction_output(unsigned int pin);
int pinctrl_gpio_get_direction(unsigned pin);
+int pinctrl_single_probe(struct device_d *dev);
#else
static inline int pinctrl_select_state(struct device_d *dev, const char *state)
{
@@ -64,6 +65,11 @@ static inline int pinctrl_gpio_get_direction(unsigned pin)
{
return -ENOTSUPP;
}
+
+static inline int pinctrl_single_probe(struct device_d *dev)
+{
+ return -ENOSYS;
+}
#endif
#endif /* PINCTRL_H */
--
2.29.2
More information about the barebox
mailing list