diff options
Diffstat (limited to 'drivers/gpio/gpio-aspeed-g7.c')
| -rw-r--r-- | drivers/gpio/gpio-aspeed-g7.c | 151 | 
1 files changed, 151 insertions, 0 deletions
| 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), +}; | 
