summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authoryanhong.wang <yanhong.wang@starfivetech.com>2022-03-22 12:17:37 +0300
committerYanhong Wang <yanhong.wang@linux.starfivetech.com>2022-10-18 11:24:33 +0300
commit53d9e9530ae20f804b7ca2766ab125b42ad5bdb3 (patch)
tree1dac7608790ca4bc58f8e0e46a69f4edce0bba61 /drivers
parent56c86383dc88850ee2e5af197532939b861f573b (diff)
downloadu-boot-53d9e9530ae20f804b7ca2766ab125b42ad5bdb3.tar.xz
GPIO:Starfive-jh7110: Add GPIO driver for JH7110
Support for GPIO controller on starfive JH7110 SoCs. Signed-off-by: yanhong.wang <yanhong.wang@starfivetech.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/starfive-gpio.c164
3 files changed, 171 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e37ac9f494..29e88f910c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -382,6 +382,12 @@ config SIFIVE_GPIO
Device model driver for GPIO controller present in SiFive FU540 SoC. This
driver enables GPIO interface on HiFive Unleashed A00 board.
+config STARFIVE_GPIO
+ bool "StarFive GPIO driver"
+ depends on DM_GPIO
+ help
+ Device model driver for GPIO controller present in StarFive JH7110 SoC.
+
config MVEBU_GPIO
bool "Marvell MVEBU GPIO driver"
depends on DM_GPIO && (ARCH_MVEBU || ARCH_KIRKWOOD)
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 58f4704f6b..2fb64c90c7 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
obj-$(CONFIG_NX_GPIO) += nx_gpio.o
obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o
+obj-$(CONFIG_STARFIVE_GPIO) += starfive-gpio.o \ No newline at end of file
diff --git a/drivers/gpio/starfive-gpio.c b/drivers/gpio/starfive-gpio.c
new file mode 100644
index 0000000000..9c715c1f9c
--- /dev/null
+++ b/drivers/gpio/starfive-gpio.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Starfive, Inc.
+ * Author: yanhong <yanhong.wang@starfivetech.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/arch/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+
+static int starfive_gpio_probe(struct udevice *dev)
+{
+ struct starfive_gpio_platdata *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char name[18], *str;
+
+ sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+
+ /*
+ * Use the gpio count mentioned in device tree,
+ * if not specified in dt, set NR_GPIOS as default
+ */
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", NR_GPIOS);
+
+ return 0;
+}
+
+static int starfive_gpio_direction_input(struct udevice *dev, u32 offset)
+{
+ struct starfive_gpio_platdata *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ /* Configure gpio direction as input */
+ clrsetbits_le32(plat->base + GPIO_OFFSET(offset),
+ GPIO_DOEN_MASK << GPIO_SHIFT(offset),
+ HIGH << GPIO_SHIFT(offset));
+
+ return 0;
+}
+
+static int starfive_gpio_direction_output(struct udevice *dev, u32 offset,
+ int value)
+{
+ struct starfive_gpio_platdata *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ /* Configure gpio direction as output */
+ clrsetbits_le32(plat->base + GPIO_OFFSET(offset),
+ GPIO_DOEN_MASK << GPIO_SHIFT(offset),
+ LOW << GPIO_SHIFT(offset));
+
+ /* Set the output value of the pin */
+ clrsetbits_le32(plat->base + GPIO_DOUT + GPIO_OFFSET(offset),
+ GPIO_DOUT_MASK << GPIO_SHIFT(offset),
+ (value & GPIO_DOUT_MASK) << GPIO_SHIFT(offset));
+
+ return 0;
+}
+
+static int starfive_gpio_get_value(struct udevice *dev, u32 offset)
+{
+ struct starfive_gpio_platdata *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int val;
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ /*Get dout value*/
+ val = readl(plat->base + GPIO_DIN + GPIO_OFFSET(offset));
+ val &= GPIO_DIN_MASK << GPIO_SHIFT(offset);
+
+ return val ? HIGH : LOW;
+}
+
+static int starfive_gpio_set_value(struct udevice *dev, u32 offset, int value)
+{
+ struct starfive_gpio_platdata *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ clrsetbits_le32(plat->base + GPIO_DOUT + GPIO_OFFSET(offset),
+ GPIO_DOUT_MASK << GPIO_SHIFT(offset),
+ (value & GPIO_DOUT_MASK) << GPIO_SHIFT(offset));
+
+ return 0;
+}
+
+static int starfive_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct starfive_gpio_platdata *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ u32 dir, val;
+
+ if (offset > uc_priv->gpio_count)
+ return -1;
+
+ /*Get doen value*/
+ val = readl(plat->base + GPIO_OFFSET(offset));
+ val &= (GPIO_DOEN_MASK << GPIO_SHIFT(offset));
+
+ dir = (val > 1) ? GPIOF_UNUSED : (val ? GPIOF_INPUT : GPIOF_OUTPUT);
+
+ return dir;
+}
+
+static int starfive_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+ struct starfive_gpio_platdata *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = (void *)addr;
+
+ writel(0, plat->base + GPIO_EN);
+ writel(0, plat->base + GPIO_LOW_IE);
+ writel(0, plat->base + GPIO_HIGH_IE);
+ writel(1, plat->base + GPIO_EN);
+
+ return 0;
+}
+
+static const struct udevice_id starfive_gpio_match[] = {
+ { .compatible = "starfive,jh7110-gpio" },
+ { }
+};
+
+static const struct dm_gpio_ops starfive_gpio_ops = {
+ .direction_input = starfive_gpio_direction_input,
+ .direction_output = starfive_gpio_direction_output,
+ .get_value = starfive_gpio_get_value,
+ .set_value = starfive_gpio_set_value,
+ .get_function = starfive_gpio_get_function,
+};
+
+U_BOOT_DRIVER(gpio_starfive) = {
+ .name = "gpio_starfive",
+ .id = UCLASS_GPIO,
+ .of_match = starfive_gpio_match,
+ .of_to_plat = starfive_gpio_ofdata_to_platdata,
+ .plat_auto = sizeof(struct starfive_gpio_platdata),
+ .ops = &starfive_gpio_ops,
+ .probe = starfive_gpio_probe,
+};