diff options
author | Stefan Roese <sr@denx.de> | 2018-10-08 12:38:01 +0200 |
---|---|---|
committer | Daniel Schwierzeck <daniel.schwierzeck@gmail.com> | 2018-11-18 16:02:22 +0100 |
commit | 4751e5595ee1e8ec121178a0ddaa99c3bbfa8e80 (patch) | |
tree | 5d4c20b312d7574d920b6dcd5ab2a2d6eda8f88a /drivers | |
parent | 053fce84c1505b1dac1ab75e2c4666bb36437514 (diff) | |
download | u-boot-4751e5595ee1e8ec121178a0ddaa99c3bbfa8e80.tar.gz u-boot-4751e5595ee1e8ec121178a0ddaa99c3bbfa8e80.tar.bz2 u-boot-4751e5595ee1e8ec121178a0ddaa99c3bbfa8e80.zip |
gpio: Add MT7621 GPIO support
This patch adds GPIO support for the Mediatek MT7621 SoC, tested on
MT7688 (Gardena smart-gateway). The driver is loosly based on the
Linux kernel version.
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
[fixed checkpatch.pl warnings: Prefer 'unsigned int' to bare use of 'unsigned']
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/mt7621_gpio.c | 183 |
3 files changed, 192 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5cd8b34400..35344e57c6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -314,4 +314,12 @@ config MPC8XXX_GPIO Aside from the standard functions of input/output mode, and output value setting, the open-drain feature, which can configure individual GPIOs to work as open-drain outputs, is supported. + +config MT7621_GPIO + bool "MediaTek MT7621 GPIO driver" + depends on DM_GPIO && ARCH_MT7620 + default y + help + Say yes here to support MediaTek MT7621 compatible GPIOs. + endmenu diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f186120684..7ed9a4ec42 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -58,3 +58,4 @@ 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_MT7621_GPIO) += mt7621_gpio.o diff --git a/drivers/gpio/mt7621_gpio.c b/drivers/gpio/mt7621_gpio.c new file mode 100644 index 0000000000..54d313d6f1 --- /dev/null +++ b/drivers/gpio/mt7621_gpio.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Stefan Roese <sr@denx.de> + * + * Based on the Linux driver version which is: + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <linux/io.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <dm/device-internal.h> +#include <dt-bindings/gpio/gpio.h> + +#define MTK_MAX_BANK 3 +#define MTK_BANK_WIDTH 32 + +enum mediatek_gpio_reg { + GPIO_REG_CTRL = 0, + GPIO_REG_POL, + GPIO_REG_DATA, + GPIO_REG_DSET, + GPIO_REG_DCLR, + GPIO_REG_REDGE, + GPIO_REG_FEDGE, + GPIO_REG_HLVL, + GPIO_REG_LLVL, + GPIO_REG_STAT, + GPIO_REG_EDGE, +}; + +static void __iomem *mediatek_gpio_membase; + +struct mediatek_gpio_platdata { + char bank_name[3]; /* Name of bank, e.g. "PA", "PB" etc */ + int gpio_count; + int bank; +}; + +static u32 reg_offs(struct mediatek_gpio_platdata *plat, int reg) +{ + return (reg * 0x10) + (plat->bank * 0x4); +} + +static int mediatek_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); + + return !!(ioread32(mediatek_gpio_membase + + reg_offs(plat, GPIO_REG_DATA)) & BIT(offset)); +} + +static int mediatek_gpio_set_value(struct udevice *dev, unsigned int offset, + int value) +{ + struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); + + iowrite32(BIT(offset), mediatek_gpio_membase + + reg_offs(plat, value ? GPIO_REG_DSET : GPIO_REG_DCLR)); + + return 0; +} + +static int mediatek_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); + + clrbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL), + BIT(offset)); + + return 0; +} + +static int mediatek_gpio_direction_output(struct udevice *dev, unsigned int offset, + int value) +{ + struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); + + setbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL), + BIT(offset)); + mediatek_gpio_set_value(dev, offset, value); + + return 0; +} + +static int mediatek_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); + u32 t; + + t = ioread32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL)); + if (t & BIT(offset)) + return GPIOF_OUTPUT; + + return GPIOF_INPUT; +} + +static const struct dm_gpio_ops gpio_mediatek_ops = { + .direction_input = mediatek_gpio_direction_input, + .direction_output = mediatek_gpio_direction_output, + .get_value = mediatek_gpio_get_value, + .set_value = mediatek_gpio_set_value, + .get_function = mediatek_gpio_get_function, +}; + +static int gpio_mediatek_probe(struct udevice *dev) +{ + struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + /* Tell the uclass how many GPIOs we have */ + if (plat) { + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + } + + return 0; +} + +/** + * We have a top-level GPIO device with no actual GPIOs. It has a child + * device for each Mediatek bank. + */ +static int gpio_mediatek_bind(struct udevice *parent) +{ + struct mediatek_gpio_platdata *plat = parent->platdata; + ofnode node; + int bank = 0; + int ret; + + /* If this is a child device, there is nothing to do here */ + if (plat) + return 0; + + mediatek_gpio_membase = dev_remap_addr(parent); + if (!mediatek_gpio_membase) + return -EINVAL; + + for (node = dev_read_first_subnode(parent); ofnode_valid(node); + node = dev_read_next_subnode(node)) { + struct mediatek_gpio_platdata *plat; + struct udevice *dev; + + plat = calloc(1, sizeof(*plat)); + if (!plat) + return -ENOMEM; + plat->bank_name[0] = 'P'; + plat->bank_name[1] = 'A' + bank; + plat->bank_name[2] = '\0'; + plat->gpio_count = MTK_BANK_WIDTH; + plat->bank = bank; + + ret = device_bind(parent, parent->driver, + plat->bank_name, plat, -1, &dev); + if (ret) + return ret; + + dev->node = node; + bank++; + } + + return 0; +} + +static const struct udevice_id mediatek_gpio_ids[] = { + { .compatible = "mtk,mt7621-gpio" }, + { } +}; + +U_BOOT_DRIVER(gpio_mediatek) = { + .name = "gpio_mediatek", + .id = UCLASS_GPIO, + .ops = &gpio_mediatek_ops, + .of_match = mediatek_gpio_ids, + .bind = gpio_mediatek_bind, + .probe = gpio_mediatek_probe, +}; |