From 344e86c61ec2f88b2740b33ed65ccc34ed708baa Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Fri, 25 Feb 2022 10:14:50 +0800 Subject: [PATCH] gpio: npcm: Add support for Nuvoton NPCM SoCs Add Nuvoton BMC NPCM7xx/NPCM8xx gpio driver Signed-off-by: Stanley Chu --- drivers/gpio/Kconfig | 7 +++ drivers/gpio/Makefile | 1 + drivers/gpio/npcm_gpio.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 drivers/gpio/npcm_gpio.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 886cdbc..149a62f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -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 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index b39dde1..d755276 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -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 index 0000000..8afd57f --- /dev/null +++ b/drivers/gpio/npcm_gpio.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022 Nuvoton Technology Corp. + */ + +#include +#include +#include +#include + +#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, +}; -- 2.7.4