gpio: npcm: Add support for Nuvoton NPCM SoCs
authorStanley Chu <stanley.chuys@gmail.com>
Fri, 25 Feb 2022 02:14:50 +0000 (10:14 +0800)
committerTom Rini <trini@konsulko.com>
Thu, 5 May 2022 13:29:58 +0000 (09:29 -0400)
Add Nuvoton BMC NPCM7xx/NPCM8xx gpio driver

Signed-off-by: Stanley Chu <yschu@nuvoton.com>
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/npcm_gpio.c [new file with mode: 0644]

index 886cdbcdbaacf6146f0130f37115e895b417d860..149a62ffe611ed83a2858807b5a935b34a9ca6e6 100644 (file)
@@ -279,6 +279,13 @@ config MXS_GPIO
        help
          Support GPIO controllers on i.MX23 and i.MX28 platforms
 
+config NPCM_GPIO
+       bool "Nuvoton NPCM GPIO driver"
+       depends on DM_GPIO
+       help
+         Support GPIO controllers on Nuvovon NPCM SoCs.
+         NPCM7xx/NPCM8xx contain 8 GPIO banks, each bank contains 32 pins.
+
 config OMAP_GPIO
        bool "TI OMAP GPIO driver"
        depends on ARCH_OMAP2PLUS
index b39dde12abfe35db6becd50bb001a6b6306c9d64..d7552762d0655e238ecab33a3f2ff4137d737db6 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_MARVELL_GPIO)    += mvgpio.o
 obj-$(CONFIG_MCP230XX_GPIO)    += mcp230xx_gpio.o
 obj-$(CONFIG_MXC_GPIO) += mxc_gpio.o
 obj-$(CONFIG_MXS_GPIO) += mxs_gpio.o
+obj-$(CONFIG_NPCM_GPIO)        += npcm_gpio.o
 obj-$(CONFIG_PCA953X)          += pca953x.o
 obj-$(CONFIG_PCA9698)          += pca9698.o
 obj-$(CONFIG_ROCKCHIP_GPIO)    += rk_gpio.o
diff --git a/drivers/gpio/npcm_gpio.c b/drivers/gpio/npcm_gpio.c
new file mode 100644 (file)
index 0000000..8afd57f
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Nuvoton Technology Corp.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <linux/io.h>
+
+#define NPCM_GPIOS_PER_BANK    32
+
+/* Register offsets */
+#define GPIO_DIN               0x4     /* RO - Data In */
+#define GPIO_DOUT              0xC     /* RW - Data Out */
+#define GPIO_OE                        0x10    /* RW - Output Enable */
+#define GPIO_IEM               0x58    /* RW - Input Enable Mask */
+#define GPIO_OES               0x70    /* WO - Output Enable Register Set */
+#define GPIO_OEC               0x74    /* WO - Output Enable Register Clear */
+
+struct npcm_gpio_priv {
+       void __iomem *base;
+};
+
+static int npcm_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+       struct npcm_gpio_priv *priv = dev_get_priv(dev);
+
+       writel(BIT(offset), priv->base + GPIO_OEC);
+       setbits_le32(priv->base + GPIO_IEM, BIT(offset));
+
+       return 0;
+}
+
+static int npcm_gpio_direction_output(struct udevice *dev, unsigned int offset,
+                                     int value)
+{
+       struct npcm_gpio_priv *priv = dev_get_priv(dev);
+
+       clrbits_le32(priv->base + GPIO_IEM, BIT(offset));
+       writel(BIT(offset), priv->base + GPIO_OES);
+
+       if (value)
+               setbits_le32(priv->base + GPIO_DOUT, BIT(offset));
+       else
+               clrbits_le32(priv->base + GPIO_DOUT, BIT(offset));
+
+       return 0;
+}
+
+static int npcm_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+       struct npcm_gpio_priv *priv = dev_get_priv(dev);
+
+       if (readl(priv->base + GPIO_IEM) & BIT(offset))
+               return !!(readl(priv->base + GPIO_DIN) & BIT(offset));
+
+       if (readl(priv->base + GPIO_OE) & BIT(offset))
+               return !!(readl(priv->base + GPIO_DOUT) & BIT(offset));
+
+       return -EINVAL;
+}
+
+static int npcm_gpio_set_value(struct udevice *dev, unsigned int offset,
+                              int value)
+{
+       struct npcm_gpio_priv *priv = dev_get_priv(dev);
+
+       if (value)
+               setbits_le32(priv->base + GPIO_DOUT, BIT(offset));
+       else
+               clrbits_le32(priv->base + GPIO_DOUT, BIT(offset));
+
+       return 0;
+}
+
+static int npcm_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+       struct npcm_gpio_priv *priv = dev_get_priv(dev);
+
+       if (readl(priv->base + GPIO_IEM) & BIT(offset))
+               return GPIOF_INPUT;
+
+       if (readl(priv->base + GPIO_OE) & BIT(offset))
+               return GPIOF_OUTPUT;
+
+       return GPIOF_FUNC;
+}
+
+static const struct dm_gpio_ops npcm_gpio_ops = {
+       .direction_input        = npcm_gpio_direction_input,
+       .direction_output       = npcm_gpio_direction_output,
+       .get_value              = npcm_gpio_get_value,
+       .set_value              = npcm_gpio_set_value,
+       .get_function           = npcm_gpio_get_function,
+};
+
+static int npcm_gpio_probe(struct udevice *dev)
+{
+       struct npcm_gpio_priv *priv = dev_get_priv(dev);
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+       priv->base = dev_read_addr_ptr(dev);
+       uc_priv->gpio_count = NPCM_GPIOS_PER_BANK;
+       uc_priv->bank_name = dev->name;
+
+       return 0;
+}
+
+static const struct udevice_id npcm_gpio_match[] = {
+       { .compatible = "nuvoton,npcm845-gpio" },
+       { .compatible = "nuvoton,npcm750-gpio" },
+       { }
+};
+
+U_BOOT_DRIVER(npcm_gpio) = {
+       .name   = "npcm_gpio",
+       .id     = UCLASS_GPIO,
+       .of_match = npcm_gpio_match,
+       .probe  = npcm_gpio_probe,
+       .priv_auto = sizeof(struct npcm_gpio_priv),
+       .ops    = &npcm_gpio_ops,
+};