summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig22
-rw-r--r--drivers/gpio/Makefile4
-rw-r--r--drivers/gpio/gpio-aspeed-g7.c151
-rw-r--r--drivers/gpio/msm_gpio.c97
-rw-r--r--drivers/gpio/mxc_gpio.c10
-rw-r--r--drivers/gpio/npcm_sgpio.c291
-rw-r--r--drivers/gpio/qcom_pmic_gpio.c27
7 files changed, 569 insertions, 33 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index fcca6941ebf..1e5711663eb 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -157,6 +157,13 @@ config ASPEED_GPIO
is found in the AST2400, AST2500 and AST2600 BMC SoCs and
provides access to over 200 GPIOs on each chip.
+config ASPEED_G7_GPIO
+ bool "Aspeed G7 GPIO Driver"
+ help
+ Say yes here to support the Aspeed G7 GPIO driver. The controller
+ is found in the AST2700 BMC SoCs and provides access to over 200
+ GPIOs on each chip.
+
config DA8XX_GPIO
bool "DA8xx GPIO Driver"
help
@@ -301,6 +308,15 @@ config NPCM_GPIO
Support GPIO controllers on Nuvovon NPCM SoCs.
NPCM7xx/NPCM8xx contain 8 GPIO banks, each bank contains 32 pins.
+config NPCM_SGPIO
+ bool "Nuvoton NPCM SGPIO driver"
+ depends on DM_GPIO
+ help
+ Support Nuvoton BMC NPCM7xx/NPCM8xx sgpio driver support.
+ Nuvoton NPCM SGPIO module is combine serial to parallel IC (HC595)
+ and parallel to serial IC (HC165).
+ BMC can use this driver to increase 64 GPI pins and 64 GPO pins to use.
+
config OMAP_GPIO
bool "TI OMAP GPIO driver"
depends on ARCH_OMAP2PLUS
@@ -684,4 +700,10 @@ config RZG2L_GPIO
Support the gpio functionality of the pin function controller (PFC)
on the Renesas RZ/G2L SoC family.
+config SPL_ADP5585_GPIO
+ bool "ADP5585 GPIO driver in SPL"
+ depends on SPL_DM_GPIO && SPL_I2C
+ help
+ Support ADP5585 GPIO expander in SPL.
+
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4a293154350..56c20e4c635 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_$(SPL_TPL_)DM_GPIO) += gpio-uclass.o
obj-$(CONFIG_$(SPL_)DM_PCA953X) += pca953x_gpio.o
obj-$(CONFIG_ASPEED_GPIO) += gpio-aspeed.o
+obj-$(CONFIG_ASPEED_G7_GPIO) += gpio-aspeed-g7.o
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
obj-$(CONFIG_BCM6345_GPIO) += bcm6345_gpio.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_$(SPL_TPL_)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_NPCM_SGPIO) += npcm_sgpio.o
obj-$(CONFIG_PCA953X) += pca953x.o
obj-$(CONFIG_ROCKCHIP_GPIO) += rk_gpio.o
obj-$(CONFIG_RCAR_GPIO) += gpio-rcar.o
@@ -74,5 +76,5 @@ obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o
obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o
obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o
obj-$(CONFIG_FTGPIO010) += ftgpio010.o
-obj-$(CONFIG_ADP5585_GPIO) += adp5585_gpio.o
+obj-$(CONFIG_$(SPL_)ADP5585_GPIO) += adp5585_gpio.o
obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o
diff --git a/drivers/gpio/gpio-aspeed-g7.c b/drivers/gpio/gpio-aspeed-g7.c
new file mode 100644
index 00000000000..4c6ab86203c
--- /dev/null
+++ b/drivers/gpio/gpio-aspeed-g7.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) ASPEED Technology Inc.
+ * Billy Tsai <billy_tsai@aspeedtech.com>
+ */
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#include <config.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/sizes.h>
+
+struct aspeed_gpio_priv {
+ void *regs;
+};
+
+#define GPIO_G7_IRQ_STS_BASE 0x100
+#define GPIO_G7_IRQ_STS_OFFSET(x) (GPIO_G7_IRQ_STS_BASE + (x) * 0x4)
+#define GPIO_G7_CTRL_REG_BASE 0x180
+#define GPIO_G7_CTRL_REG_OFFSET(x) (GPIO_G7_CTRL_REG_BASE + (x) * 0x4)
+#define GPIO_G7_OUT_DATA BIT(0)
+#define GPIO_G7_DIR BIT(1)
+#define GPIO_G7_IRQ_EN BIT(2)
+#define GPIO_G7_IRQ_TYPE0 BIT(3)
+#define GPIO_G7_IRQ_TYPE1 BIT(4)
+#define GPIO_G7_IRQ_TYPE2 BIT(5)
+#define GPIO_G7_RST_TOLERANCE BIT(6)
+#define GPIO_G7_DEBOUNCE_SEL GENMASK(8, 7)
+#define GPIO_G7_INPUT_MASK BIT(9)
+#define GPIO_G7_IRQ_STS BIT(12)
+#define GPIO_G7_IN_DATA BIT(13)
+/*
+ * The configuration of the following registers should be determined
+ * outside of the GPIO driver.
+ */
+#define GPIO_G7_PRIVILEGE_W_REG_BASE 0x810
+#define GPIO_G7_PRIVILEGE_W_REG_OFFSET(x) (GPIO_G7_PRIVILEGE_W_REG_BASE + ((x) >> 2) * 0x4)
+#define GPIO_G7_PRIVILEGE_R_REG_BASE 0x910
+#define GPIO_G7_PRIVILEGE_R_REG_OFFSET(x) (GPIO_G7_PRIVILEGE_R_REG_BASE + ((x) >> 2) * 0x4)
+#define GPIO_G7_IRQ_TARGET_REG_BASE 0xA10
+#define GPIO_G7_IRQ_TARGET_REG_OFFSET(x) (GPIO_G7_IRQ_TARGET_REG_BASE + ((x) >> 2) * 0x4)
+#define GPIO_G7_IRQ_TO_INTC2_18 BIT(0)
+#define GPIO_G7_IRQ_TO_INTC2_19 BIT(1)
+#define GPIO_G7_IRQ_TO_INTC2_20 BIT(2)
+#define GPIO_G7_IRQ_TO_SIO BIT(3)
+#define GPIO_G7_IRQ_TARGET_RESET_TOLERANCE BIT(6)
+#define GPIO_G7_IRQ_TARGET_W_PROTECT BIT(7)
+
+static int
+aspeed_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct aspeed_gpio_priv *priv = dev_get_priv(dev);
+ void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
+ u32 dir = readl(addr);
+
+ dir &= ~GPIO_G7_DIR;
+ writel(dir, addr);
+
+ return 0;
+}
+
+static int aspeed_gpio_direction_output(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct aspeed_gpio_priv *priv = dev_get_priv(dev);
+ void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
+ u32 data = readl(addr);
+
+ if (value)
+ data |= GPIO_G7_OUT_DATA;
+ else
+ data &= ~GPIO_G7_OUT_DATA;
+ writel(data, addr);
+ data |= GPIO_G7_DIR;
+ writel(data, addr);
+
+ return 0;
+}
+
+static int aspeed_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct aspeed_gpio_priv *priv = dev_get_priv(dev);
+ void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
+
+ return !!(readl(addr) & GPIO_G7_IN_DATA);
+}
+
+static int
+aspeed_gpio_set_value(struct udevice *dev, unsigned int offset, int value)
+{
+ struct aspeed_gpio_priv *priv = dev_get_priv(dev);
+ void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
+ u32 data = readl(addr);
+
+ if (value)
+ data |= GPIO_G7_OUT_DATA;
+ else
+ data &= ~GPIO_G7_OUT_DATA;
+
+ writel(data, addr);
+
+ return 0;
+}
+
+static int aspeed_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct aspeed_gpio_priv *priv = dev_get_priv(dev);
+ void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
+
+ if (readl(addr) & GPIO_G7_DIR)
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops aspeed_gpio_ops = {
+ .direction_input = aspeed_gpio_direction_input,
+ .direction_output = aspeed_gpio_direction_output,
+ .get_value = aspeed_gpio_get_value,
+ .set_value = aspeed_gpio_set_value,
+ .get_function = aspeed_gpio_get_function,
+};
+
+static int aspeed_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct aspeed_gpio_priv *priv = dev_get_priv(dev);
+
+ uc_priv->bank_name = dev->name;
+ ofnode_read_u32(dev_ofnode(dev), "ngpios", &uc_priv->gpio_count);
+ priv->regs = devfdt_get_addr_ptr(dev);
+
+ return 0;
+}
+
+static const struct udevice_id aspeed_gpio_ids[] = {
+ { .compatible = "aspeed,ast2700-gpio", },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_aspeed) = {
+ .name = "gpio-aspeed",
+ .id = UCLASS_GPIO,
+ .of_match = aspeed_gpio_ids,
+ .ops = &aspeed_gpio_ops,
+ .probe = aspeed_gpio_probe,
+ .priv_auto = sizeof(struct aspeed_gpio_priv),
+};
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index 2fb266f1285..cea073b3297 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -34,13 +34,31 @@ struct msm_gpio_bank {
#define GPIO_IN_OUT_REG(dev, x) \
(GPIO_CONFIG_REG(dev, x) + 0x4)
+static void msm_gpio_direction_input_special(struct msm_gpio_bank *priv,
+ unsigned int gpio)
+{
+ unsigned int offset = gpio - priv->pin_data->special_pins_start;
+ const struct msm_special_pin_data *data;
+
+ if (!priv->pin_data->special_pins_data)
+ return;
+
+ data = &priv->pin_data->special_pins_data[offset];
+
+ if (!data->ctl_reg || data->oe_bit >= 31)
+ return;
+
+ /* switch direction */
+ clrsetbits_le32(priv->base + data->ctl_reg,
+ BIT(data->oe_bit), 0);
+}
+
static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- /* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(priv->pin_data, gpio))
- return;
+ msm_gpio_direction_input_special(priv, gpio);
/* Disable OE bit */
clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
@@ -49,13 +67,33 @@ static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
return;
}
+static int msm_gpio_set_value_special(struct msm_gpio_bank *priv,
+ unsigned int gpio, int value)
+{
+ unsigned int offset = gpio - priv->pin_data->special_pins_start;
+ const struct msm_special_pin_data *data;
+
+ if (!priv->pin_data->special_pins_data)
+ return 0;
+
+ data = &priv->pin_data->special_pins_data[offset];
+
+ if (!data->io_reg || data->out_bit >= 31)
+ return 0;
+
+ value = !!value;
+ /* set value */
+ writel(value << data->out_bit, priv->base + data->io_reg);
+
+ return 0;
+}
+
static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- /* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(priv->pin_data, gpio))
- return 0;
+ return msm_gpio_set_value_special(priv, gpio, value);
value = !!value;
/* set value */
@@ -64,14 +102,42 @@ static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
return 0;
}
+static int msm_gpio_direction_output_special(struct msm_gpio_bank *priv,
+ unsigned int gpio,
+ int value)
+{
+ unsigned int offset = gpio - priv->pin_data->special_pins_start;
+ const struct msm_special_pin_data *data;
+
+ if (!priv->pin_data->special_pins_data)
+ return 0;
+
+ data = &priv->pin_data->special_pins_data[offset];
+
+ if (!data->io_reg || data->out_bit >= 31)
+ return 0;
+
+ value = !!value;
+ /* set value */
+ writel(value << data->out_bit, priv->base + data->io_reg);
+
+ if (!data->ctl_reg || data->oe_bit >= 31)
+ return 0;
+
+ /* switch direction */
+ clrsetbits_le32(priv->base + data->ctl_reg,
+ BIT(data->oe_bit), BIT(data->oe_bit));
+
+ return 0;
+}
+
static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
int value)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- /* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(priv->pin_data, gpio))
- return 0;
+ return msm_gpio_direction_output_special(priv, gpio, value);
value = !!value;
/* set value */
@@ -100,13 +166,28 @@ static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flag
return 0;
}
+static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int gpio)
+{
+ unsigned int offset = gpio - priv->pin_data->special_pins_start;
+ const struct msm_special_pin_data *data;
+
+ if (!priv->pin_data->special_pins_data)
+ return 0;
+
+ data = &priv->pin_data->special_pins_data[offset];
+
+ if (!data->io_reg || data->in_bit >= 31)
+ return 0;
+
+ return !!(readl(priv->base + data->io_reg) >> data->in_bit);
+}
+
static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
- /* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(priv->pin_data, gpio))
- return 0;
+ return msm_gpio_get_value_special(priv, gpio);
return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
}
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index cac6b32b279..28176e15b7d 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -133,7 +133,10 @@ int gpio_get_value(unsigned gpio)
regs = (struct gpio_regs *)gpio_ports[port];
- val = (readl(&regs->gpio_psr) >> gpio) & 0x01;
+ if ((readl(&regs->gpio_dir) >> gpio) & 0x01)
+ val = (readl(&regs->gpio_dr) >> gpio) & 0x01;
+ else
+ val = (readl(&regs->gpio_psr) >> gpio) & 0x01;
return val;
}
@@ -210,7 +213,10 @@ static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
{
- return (readl(&regs->gpio_psr) >> offset) & 0x01;
+ if ((readl(&regs->gpio_dir) >> offset) & 0x01)
+ return (readl(&regs->gpio_dr) >> offset) & 0x01;
+ else
+ return (readl(&regs->gpio_psr) >> offset) & 0x01;
}
/* set GPIO pin 'gpio' as an input */
diff --git a/drivers/gpio/npcm_sgpio.c b/drivers/gpio/npcm_sgpio.c
new file mode 100644
index 00000000000..6d73287c0a2
--- /dev/null
+++ b/drivers/gpio/npcm_sgpio.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024 Nuvoton Technology Corp.
+ */
+
+#include <dm.h>
+#include <asm/gpio.h>
+#include <linux/io.h>
+
+#define MAX_NR_HW_SGPIO 64
+#define NPCM_CLK_MHZ 8000000
+
+#define NPCM_IOXCFG1 0x2A
+
+#define NPCM_IOXCTS 0x28
+#define NPCM_IOXCTS_IOXIF_EN BIT(7)
+#define NPCM_IOXCTS_RD_MODE GENMASK(2, 1)
+#define NPCM_IOXCTS_RD_MODE_PERIODIC BIT(2)
+
+#define NPCM_IOXCFG2 0x2B
+#define NPCM_IOXCFG2_PORT GENMASK(3, 0)
+
+#define GPIO_BANK(x) ((x) / 8)
+#define GPIO_BIT(x) ((x) % 8)
+
+struct npcm_sgpio_priv {
+ void __iomem *base;
+ u32 nin_sgpio;
+ u32 nout_sgpio;
+ u32 in_port;
+ u32 out_port;
+};
+
+struct npcm_sgpio_bank {
+ u8 rdata_reg;
+ u8 wdata_reg;
+ u8 event_config;
+ u8 event_status;
+};
+
+enum npcm_sgpio_reg {
+ READ_DATA,
+ WRITE_DATA,
+ EVENT_CFG,
+ EVENT_STS,
+};
+
+static const struct npcm_sgpio_bank npcm_sgpio_banks[] = {
+ {
+ .wdata_reg = 0x00,
+ .rdata_reg = 0x08,
+ .event_config = 0x10,
+ .event_status = 0x20,
+ },
+ {
+ .wdata_reg = 0x01,
+ .rdata_reg = 0x09,
+ .event_config = 0x12,
+ .event_status = 0x21,
+ },
+ {
+ .wdata_reg = 0x02,
+ .rdata_reg = 0x0a,
+ .event_config = 0x14,
+ .event_status = 0x22,
+ },
+ {
+ .wdata_reg = 0x03,
+ .rdata_reg = 0x0b,
+ .event_config = 0x16,
+ .event_status = 0x23,
+ },
+ {
+ .wdata_reg = 0x04,
+ .rdata_reg = 0x0c,
+ .event_config = 0x18,
+ .event_status = 0x24,
+ },
+ {
+ .wdata_reg = 0x05,
+ .rdata_reg = 0x0d,
+ .event_config = 0x1a,
+ .event_status = 0x25,
+ },
+ {
+ .wdata_reg = 0x06,
+ .rdata_reg = 0x0e,
+ .event_config = 0x1c,
+ .event_status = 0x26,
+ },
+ {
+ .wdata_reg = 0x07,
+ .rdata_reg = 0x0f,
+ .event_config = 0x1e,
+ .event_status = 0x27,
+ },
+};
+
+static void __iomem *bank_reg(struct npcm_sgpio_priv *gpio,
+ const struct npcm_sgpio_bank *bank,
+ const enum npcm_sgpio_reg reg)
+{
+ switch (reg) {
+ case READ_DATA:
+ return gpio->base + bank->rdata_reg;
+ case WRITE_DATA:
+ return gpio->base + bank->wdata_reg;
+ case EVENT_CFG:
+ return gpio->base + bank->event_config;
+ case EVENT_STS:
+ return gpio->base + bank->event_status;
+ default:
+ /* actually if code runs to here, it's an error case */
+ printf("Getting here is an error condition\n");
+ return NULL;
+ }
+}
+
+static const struct npcm_sgpio_bank *offset_to_bank(unsigned int offset)
+{
+ unsigned int bank = GPIO_BANK(offset);
+
+ return &npcm_sgpio_banks[bank];
+}
+
+static int npcm_sgpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct npcm_sgpio_priv *priv = dev_get_priv(dev);
+
+ if (offset < priv->nout_sgpio) {
+ printf("Error: Offset %d is a output pin\n", offset);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int npcm_sgpio_direction_output(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct npcm_sgpio_priv *priv = dev_get_priv(dev);
+ const struct npcm_sgpio_bank *bank = offset_to_bank(offset);
+ void __iomem *addr;
+ u8 reg = 0;
+
+ if (offset >= priv->nout_sgpio) {
+ printf("Error: Offset %d is a input pin\n", offset);
+ return -EINVAL;
+ }
+
+ addr = bank_reg(priv, bank, WRITE_DATA);
+ reg = ioread8(addr);
+
+ if (value)
+ reg |= BIT(GPIO_BIT(offset));
+ else
+ reg &= ~BIT(GPIO_BIT(offset));
+
+ iowrite8(reg, addr);
+
+ return 0;
+}
+
+static int npcm_sgpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct npcm_sgpio_priv *priv = dev_get_priv(dev);
+ const struct npcm_sgpio_bank *bank;
+ void __iomem *addr;
+ u8 reg;
+
+ if (offset < priv->nout_sgpio) {
+ bank = offset_to_bank(offset);
+ addr = bank_reg(priv, bank, WRITE_DATA);
+ } else {
+ offset -= priv->nout_sgpio;
+ bank = offset_to_bank(offset);
+ addr = bank_reg(priv, bank, READ_DATA);
+ }
+
+ reg = ioread8(addr);
+
+ return !!(reg & BIT(GPIO_BIT(offset)));
+}
+
+static int npcm_sgpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ return npcm_sgpio_direction_output(dev, offset, value);
+}
+
+static int npcm_sgpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct npcm_sgpio_priv *priv = dev_get_priv(dev);
+
+ if (offset < priv->nout_sgpio)
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
+static void npcm_sgpio_setup_enable(struct npcm_sgpio_priv *gpio, bool enable)
+{
+ u8 reg;
+
+ reg = ioread8(gpio->base + NPCM_IOXCTS);
+ reg = (reg & ~NPCM_IOXCTS_RD_MODE) | NPCM_IOXCTS_RD_MODE_PERIODIC;
+
+ if (enable)
+ reg |= NPCM_IOXCTS_IOXIF_EN;
+ else
+ reg &= ~NPCM_IOXCTS_IOXIF_EN;
+
+ iowrite8(reg, gpio->base + NPCM_IOXCTS);
+}
+
+static int npcm_sgpio_init_port(struct udevice *dev)
+{
+ struct npcm_sgpio_priv *priv = dev_get_priv(dev);
+ u8 in_port, out_port, set_port, reg, set_clk;
+
+ npcm_sgpio_setup_enable(priv, false);
+
+ in_port = GPIO_BANK(priv->nin_sgpio);
+ if (GPIO_BIT(priv->nin_sgpio) > 0)
+ in_port += 1;
+
+ out_port = GPIO_BANK(priv->nout_sgpio);
+ if (GPIO_BIT(priv->nout_sgpio) > 0)
+ out_port += 1;
+
+ priv->in_port = in_port;
+ priv->out_port = out_port;
+
+ set_port = (out_port & NPCM_IOXCFG2_PORT) << 4 | (in_port & NPCM_IOXCFG2_PORT);
+ set_clk = 0x07;
+
+ iowrite8(set_port, priv->base + NPCM_IOXCFG2);
+ iowrite8(set_clk, priv->base + NPCM_IOXCFG1);
+
+ reg = ioread8(priv->base + NPCM_IOXCFG2);
+
+ return reg == set_port ? 0 : -EINVAL;
+}
+
+static const struct dm_gpio_ops npcm_sgpio_ops = {
+ .direction_input = npcm_sgpio_direction_input,
+ .direction_output = npcm_sgpio_direction_output,
+ .get_value = npcm_sgpio_get_value,
+ .set_value = npcm_sgpio_set_value,
+ .get_function = npcm_sgpio_get_function,
+};
+
+static int npcm_sgpio_probe(struct udevice *dev)
+{
+ struct npcm_sgpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int rc;
+
+ priv->base = dev_read_addr_ptr(dev);
+ ofnode_read_u32(dev_ofnode(dev), "nuvoton,input-ngpios", &priv->nin_sgpio);
+ ofnode_read_u32(dev_ofnode(dev), "nuvoton,output-ngpios", &priv->nout_sgpio);
+
+ if (priv->nin_sgpio > MAX_NR_HW_SGPIO || priv->nout_sgpio > MAX_NR_HW_SGPIO)
+ return -EINVAL;
+
+ rc = npcm_sgpio_init_port(dev);
+ if (rc < 0)
+ return rc;
+
+ uc_priv->gpio_count = priv->nin_sgpio + priv->nout_sgpio;
+ uc_priv->bank_name = dev->name;
+
+ npcm_sgpio_setup_enable(priv, true);
+
+ return 0;
+}
+
+static const struct udevice_id npcm_sgpio_match[] = {
+ { .compatible = "nuvoton,npcm845-sgpio" },
+ { .compatible = "nuvoton,npcm750-sgpio" },
+ { }
+};
+
+U_BOOT_DRIVER(npcm_sgpio) = {
+ .name = "npcm_sgpio",
+ .id = UCLASS_GPIO,
+ .of_match = npcm_sgpio_match,
+ .probe = npcm_sgpio_probe,
+ .priv_auto = sizeof(struct npcm_sgpio_priv),
+ .ops = &npcm_sgpio_ops,
+};
diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c
index 80fee841ee3..f2ef4e5ce14 100644
--- a/drivers/gpio/qcom_pmic_gpio.c
+++ b/drivers/gpio/qcom_pmic_gpio.c
@@ -69,17 +69,6 @@
#define REG_EN_CTL 0x46
#define REG_EN_CTL_ENABLE (1 << 7)
-/**
- * pmic_gpio_match_data - platform specific configuration
- *
- * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them.
- * This is a workaround for an unknown bug on some platforms where trying to write the
- * GPIO configuration registers causes the board to hang.
- */
-enum pmic_gpio_quirks {
- QCOM_PMIC_QUIRK_READONLY = (1 << 0),
-};
-
struct qcom_pmic_gpio_data {
uint32_t pid; /* Peripheral ID on SPMI bus */
bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */
@@ -128,13 +117,8 @@ static int qcom_gpio_set_direction(struct udevice *dev, unsigned int offset,
{
struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
- ulong quirks = dev_get_driver_data(dev);
int ret = 0;
- /* Some PMICs don't like their GPIOs being configured */
- if (quirks & QCOM_PMIC_QUIRK_READONLY)
- return 0;
-
/* Disable the GPIO */
ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
REG_EN_CTL_ENABLE, 0);
@@ -278,7 +262,6 @@ static int qcom_gpio_bind(struct udevice *dev)
{
struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
- ulong quirks = dev_get_driver_data(dev);
struct udevice *child;
struct driver *drv;
int ret;
@@ -292,7 +275,7 @@ static int qcom_gpio_bind(struct udevice *dev)
/* Bind the GPIO driver as a child of the PMIC. */
ret = device_bind_with_driver_data(dev, drv,
dev->name,
- quirks, dev_ofnode(dev), &child);
+ 0, dev_ofnode(dev), &child);
if (ret)
return log_msg_ret("bind", ret);
@@ -361,11 +344,11 @@ static int qcom_gpio_probe(struct udevice *dev)
static const struct udevice_id qcom_gpio_ids[] = {
{ .compatible = "qcom,pm8916-gpio" },
{ .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
- { .compatible = "qcom,pm8998-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
+ { .compatible = "qcom,pm8998-gpio" },
{ .compatible = "qcom,pms405-gpio" },
- { .compatible = "qcom,pm6125-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
- { .compatible = "qcom,pm8150-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
- { .compatible = "qcom,pm8550-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
+ { .compatible = "qcom,pm6125-gpio" },
+ { .compatible = "qcom,pm8150-gpio" },
+ { .compatible = "qcom,pm8550-gpio" },
{ }
};