gpio: Add G7 Aspeed gpio controller driver

In the 7th generation of the SoC from Aspeed, the control logic of the
GPIO controller has been updated to support per-pin control. Each pin now
has its own 32-bit register, allowing for individual control of the pin’s
value, direction, interrupt type, and other settings.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
This commit is contained in:
Billy Tsai 2024-08-20 15:27:36 +08:00 committed by Tom Rini
parent 1bf048f21b
commit 7c2c235a27
3 changed files with 159 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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),
};