diff options
author | Tom Rini <trini@konsulko.com> | 2021-07-14 16:48:23 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2021-07-14 16:48:23 -0400 |
commit | eae8c7c33829c3bd25a792600c1fe6ed842a1ddc (patch) | |
tree | 48ac04976fdc068a5f6aea009a153feb9dde34ff /drivers/gpio/nmk_gpio.c | |
parent | a7bdd2dd8e7685166767c5fecfdce7e5dc8a40be (diff) | |
parent | 845d9cf61c3a319fed0069c36f402e74a61ceb8c (diff) |
Merge branch '2021-07-14-platform-updates'
- Assorted platform updates
Diffstat (limited to 'drivers/gpio/nmk_gpio.c')
-rw-r--r-- | drivers/gpio/nmk_gpio.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/drivers/gpio/nmk_gpio.c b/drivers/gpio/nmk_gpio.c new file mode 100644 index 0000000000..e1bb41b196 --- /dev/null +++ b/drivers/gpio/nmk_gpio.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2019 Stephan Gerhold */ + +#include <common.h> +#include <dm.h> +#include <asm/gpio.h> +#include <asm/io.h> + +struct nmk_gpio_regs { + u32 dat; /* data */ + u32 dats; /* data set */ + u32 datc; /* data clear */ + u32 pdis; /* pull disable */ + u32 dir; /* direction */ + u32 dirs; /* direction set */ + u32 dirc; /* direction clear */ + u32 slpm; /* sleep mode */ + u32 afsla; /* alternate function select A */ + u32 afslb; /* alternate function select B */ + u32 lowemi; /* low EMI mode */ +}; + +struct nmk_gpio { + struct nmk_gpio_regs *regs; +}; + +static int nmk_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct nmk_gpio *priv = dev_get_priv(dev); + + return !!(readl(&priv->regs->dat) & BIT(offset)); +} + +static int nmk_gpio_set_value(struct udevice *dev, unsigned offset, int value) +{ + struct nmk_gpio *priv = dev_get_priv(dev); + + if (value) + writel(BIT(offset), &priv->regs->dats); + else + writel(BIT(offset), &priv->regs->datc); + + return 0; +} + +static int nmk_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct nmk_gpio *priv = dev_get_priv(dev); + + if (readl(&priv->regs->afsla) & BIT(offset) || + readl(&priv->regs->afslb) & BIT(offset)) + return GPIOF_FUNC; + + if (readl(&priv->regs->dir) & BIT(offset)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int nmk_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct nmk_gpio *priv = dev_get_priv(dev); + + writel(BIT(offset), &priv->regs->dirc); + return 0; +} + +static int nmk_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct nmk_gpio *priv = dev_get_priv(dev); + + writel(BIT(offset), &priv->regs->dirs); + return nmk_gpio_set_value(dev, offset, value); +} + +static const struct dm_gpio_ops nmk_gpio_ops = { + .get_value = nmk_gpio_get_value, + .set_value = nmk_gpio_set_value, + .get_function = nmk_gpio_get_function, + .direction_input = nmk_gpio_direction_input, + .direction_output = nmk_gpio_direction_output, +}; + +static int nmk_gpio_probe(struct udevice *dev) +{ + struct nmk_gpio *priv = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + char buf[20]; + u32 bank; + int ret; + + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) + return -EINVAL; + + ret = dev_read_u32(dev, "gpio-bank", &bank); + if (ret < 0) { + printf("nmk_gpio(%s): Failed to read gpio-bank\n", dev->name); + return ret; + } + + sprintf(buf, "nmk%u-gpio", bank); + uc_priv->bank_name = strdup(buf); + if (!uc_priv->bank_name) + return -ENOMEM; + + uc_priv->gpio_count = sizeof(priv->regs->dat) * BITS_PER_BYTE; + + return 0; +} + +static const struct udevice_id nmk_gpio_ids[] = { + { .compatible = "st,nomadik-gpio" }, + { } +}; + +U_BOOT_DRIVER(gpio_nmk) = { + .name = "nmk_gpio", + .id = UCLASS_GPIO, + .of_match = nmk_gpio_ids, + .probe = nmk_gpio_probe, + .ops = &nmk_gpio_ops, + .priv_auto = sizeof(struct nmk_gpio), +}; |