From ca610ddf973eeafad26cacf54db820ca8843e026 Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Thu, 12 Nov 2020 16:36:33 +0800 Subject: [PATCH] gpio: add GPIO controller driver for MediaTek MT7620 SoC This patch adds GPIO controller driver for MediaTek MT7620 SoC Reviewed-by: Stefan Roese Reviewed-by: Simon Glass Signed-off-by: Weijie Gao --- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/mt7620_gpio.c | 146 +++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 drivers/gpio/mt7620_gpio.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 202fcc6f47..7e94759a79 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -471,6 +471,14 @@ config MPC83XX_SPISEL_BOOT This pin is typically used as spi chip select to a spi nor flash. +config MT7620_GPIO + bool "MediaTek MT7620 GPIO driver" + depends on DM_GPIO && SOC_MT7620 + default y + help + Device model driver for GPIO controller present in MediaTek MT7620 + and earlier SoCs. + config MT7621_GPIO bool "MediaTek MT7621 GPIO driver" depends on DM_GPIO && SOC_MT7628 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index d3d0d3cacf..8541ba0b0a 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o +obj-$(CONFIG_MT7620_GPIO) += mt7620_gpio.o obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o obj-$(CONFIG_NX_GPIO) += nx_gpio.o diff --git a/drivers/gpio/mt7620_gpio.c b/drivers/gpio/mt7620_gpio.c new file mode 100644 index 0000000000..713fa2ed78 --- /dev/null +++ b/drivers/gpio/mt7620_gpio.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + * + * GPIO controller driver for MediaTek MT7620 SoC + */ + +#include +#include +#include +#include +#include +#include + +enum mt7620_regs { + GPIO_REG_DATA, + GPIO_REG_DIR, + GPIO_REG_SET, + GPIO_REG_CLR, + + __GPIO_REG_MAX +}; + +struct mt7620_gpio_priv { + void __iomem *base; + u32 regs[__GPIO_REG_MAX]; + u32 count; +}; + +static int mt7620_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct mt7620_gpio_priv *priv = dev_get_priv(dev); + + return !!(readl(priv->base + priv->regs[GPIO_REG_DATA]) & BIT(offset)); +} + +static int mt7620_gpio_set_value(struct udevice *dev, unsigned int offset, + int value) +{ + struct mt7620_gpio_priv *priv = dev_get_priv(dev); + u32 reg; + + reg = value ? priv->regs[GPIO_REG_SET] : priv->regs[GPIO_REG_CLR]; + + writel(BIT(offset), priv->base + reg); + + return 0; +} + +static int mt7620_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct mt7620_gpio_priv *priv = dev_get_priv(dev); + + clrbits_32(priv->base + priv->regs[GPIO_REG_DIR], BIT(offset)); + + return 0; +} + +static int mt7620_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + struct mt7620_gpio_priv *priv = dev_get_priv(dev); + + /* Set value first */ + mt7620_gpio_set_value(dev, offset, value); + + setbits_32(priv->base + priv->regs[GPIO_REG_DIR], BIT(offset)); + + return 0; +} + +static int mt7620_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + struct mt7620_gpio_priv *priv = dev_get_priv(dev); + + return (readl(priv->base + priv->regs[GPIO_REG_DIR]) & BIT(offset)) ? + GPIOF_OUTPUT : GPIOF_INPUT; +} + +static const struct dm_gpio_ops mt7620_gpio_ops = { + .direction_input = mt7620_gpio_direction_input, + .direction_output = mt7620_gpio_direction_output, + .get_value = mt7620_gpio_get_value, + .set_value = mt7620_gpio_set_value, + .get_function = mt7620_gpio_get_function, +}; + +static int mt7620_gpio_probe(struct udevice *dev) +{ + struct mt7620_gpio_priv *priv = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + const char *name; + + name = dev_read_string(dev, "mediatek,bank-name"); + if (!name) + name = dev->name; + + uc_priv->gpio_count = priv->count; + uc_priv->bank_name = name; + + return 0; +} + +static int mt7620_gpio_of_to_plat(struct udevice *dev) +{ + struct mt7620_gpio_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_remap_addr_index(dev, 0); + if (!priv->base) { + dev_err(dev, "mt7620_gpio: unable to map registers\n"); + return -EINVAL; + } + + ret = dev_read_u32(dev, "mediatek,gpio-num", &priv->count); + if (ret) { + dev_err(dev, "mt7620_gpio: failed to get GPIO count\n"); + return -EINVAL; + } + + ret = dev_read_u32_array(dev, "mediatek,register-map", priv->regs, + __GPIO_REG_MAX); + if (ret) { + dev_err(dev, "mt7620_gpio: unable to get register map\n"); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id mt7620_gpio_ids[] = { + { .compatible = "mediatek,mt7620-gpio" }, + { } +}; + +U_BOOT_DRIVER(mt7620_gpio) = { + .name = "mt7620_gpio", + .id = UCLASS_GPIO, + .ops = &mt7620_gpio_ops, + .of_match = mt7620_gpio_ids, + .probe = mt7620_gpio_probe, + .of_to_plat = mt7620_gpio_of_to_plat, + .priv_auto = sizeof(struct mt7620_gpio_priv), +};