aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/db8500_gpio.c221
-rw-r--r--drivers/gpio/nmk_gpio.c125
4 files changed, 134 insertions, 222 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index de4dc51d4b..0817b12c5f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -495,4 +495,12 @@ config NX_GPIO
The GPIOs for a device are defined in the device tree with one node
for each bank.
+config NOMADIK_GPIO
+ bool "Nomadik GPIO driver"
+ depends on DM_GPIO
+ help
+ Support GPIO access on ST-Ericsson Ux500 SoCs. The GPIOs are arranged
+ into a number of banks each with 32 GPIOs. The GPIOs for a device are
+ defined in the device tree with one node for each bank.
+
endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 06dfc32fa5..16b09fb1b5 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -43,7 +43,6 @@ obj-$(CONFIG_MPC8XXX_GPIO) += mpc8xxx_gpio.o
obj-$(CONFIG_MPC83XX_SPISEL_BOOT) += mpc83xx_spisel_boot.o
obj-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o
obj-$(CONFIG_OMAP_GPIO) += omap_gpio.o
-obj-$(CONFIG_DB8500_GPIO) += db8500_gpio.o
obj-$(CONFIG_BCM2835_GPIO) += bcm2835_gpio.o
obj-$(CONFIG_XILINX_GPIO) += xilinx_gpio.o
obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o
@@ -68,3 +67,4 @@ obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
obj-$(CONFIG_NX_GPIO) += nx_gpio.o
obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
+obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o
diff --git a/drivers/gpio/db8500_gpio.c b/drivers/gpio/db8500_gpio.c
deleted file mode 100644
index eefb56d83f..0000000000
--- a/drivers/gpio/db8500_gpio.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code.
- * The purpose is that GPIO config found in kernel should work by simply
- * copy-paste it to U-Boot.
- *
- * Original Linux authors:
- * Copyright (C) 2008,2009 STMicroelectronics
- * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
- * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
- *
- * Ported to U-Boot by:
- * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <common.h>
-#include <asm/io.h>
-
-#include <asm/arch/db8500_gpio.h>
-#include <asm/arch/db8500_pincfg.h>
-#include <linux/compiler.h>
-
-#define IO_ADDR(x) (void *) (x)
-
-/*
- * The GPIO module in the db8500 Systems-on-Chip is an
- * AMBA device, managing 32 pins and alternate functions. The logic block
- * is currently only used in the db8500.
- */
-
-#define GPIO_TOTAL_PINS 268
-#define GPIO_PINS_PER_BLOCK 32
-#define GPIO_BLOCKS_COUNT (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1)
-#define GPIO_BLOCK(pin) (((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1)
-#define GPIO_PIN_WITHIN_BLOCK(pin) ((pin)%(GPIO_PINS_PER_BLOCK))
-
-/* Register in the logic block */
-#define DB8500_GPIO_DAT 0x00
-#define DB8500_GPIO_DATS 0x04
-#define DB8500_GPIO_DATC 0x08
-#define DB8500_GPIO_PDIS 0x0c
-#define DB8500_GPIO_DIR 0x10
-#define DB8500_GPIO_DIRS 0x14
-#define DB8500_GPIO_DIRC 0x18
-#define DB8500_GPIO_SLPC 0x1c
-#define DB8500_GPIO_AFSLA 0x20
-#define DB8500_GPIO_AFSLB 0x24
-
-#define DB8500_GPIO_RIMSC 0x40
-#define DB8500_GPIO_FIMSC 0x44
-#define DB8500_GPIO_IS 0x48
-#define DB8500_GPIO_IC 0x4c
-#define DB8500_GPIO_RWIMSC 0x50
-#define DB8500_GPIO_FWIMSC 0x54
-#define DB8500_GPIO_WKS 0x58
-
-static void __iomem *get_gpio_addr(unsigned gpio)
-{
- /* Our list of GPIO chips */
- static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = {
- IO_ADDR(CFG_GPIO_0_BASE),
- IO_ADDR(CFG_GPIO_1_BASE),
- IO_ADDR(CFG_GPIO_2_BASE),
- IO_ADDR(CFG_GPIO_3_BASE),
- IO_ADDR(CFG_GPIO_4_BASE),
- IO_ADDR(CFG_GPIO_5_BASE),
- IO_ADDR(CFG_GPIO_6_BASE),
- IO_ADDR(CFG_GPIO_7_BASE),
- IO_ADDR(CFG_GPIO_8_BASE)
- };
-
- return gpio_addrs[GPIO_BLOCK(gpio)];
-}
-
-static unsigned get_gpio_offset(unsigned gpio)
-{
- return GPIO_PIN_WITHIN_BLOCK(gpio);
-}
-
-/* Can only be called from config_pin. Don't configure alt-mode directly */
-static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode)
-{
- void __iomem *addr = get_gpio_addr(gpio);
- unsigned offset = get_gpio_offset(gpio);
- u32 bit = 1 << offset;
- u32 afunc, bfunc;
-
- afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit;
- bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit;
- if (mode & DB8500_GPIO_ALT_A)
- afunc |= bit;
- if (mode & DB8500_GPIO_ALT_B)
- bfunc |= bit;
- writel(afunc, addr + DB8500_GPIO_AFSLA);
- writel(bfunc, addr + DB8500_GPIO_AFSLB);
-}
-
-/**
- * db8500_gpio_set_pull() - enable/disable pull up/down on a gpio
- * @gpio: pin number
- * @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP,
- * and DB8500_GPIO_PULL_NONE
- *
- * Enables/disables pull up/down on a specified pin. This only takes effect if
- * the pin is configured as an input (either explicitly or by the alternate
- * function).
- *
- * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
- * configured as an input. Otherwise, due to the way the controller registers
- * work, this function will change the value output on the pin.
- */
-void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull)
-{
- void __iomem *addr = get_gpio_addr(gpio);
- unsigned offset = get_gpio_offset(gpio);
- u32 bit = 1 << offset;
- u32 pdis;
-
- pdis = readl(addr + DB8500_GPIO_PDIS);
- if (pull == DB8500_GPIO_PULL_NONE)
- pdis |= bit;
- else
- pdis &= ~bit;
- writel(pdis, addr + DB8500_GPIO_PDIS);
-
- if (pull == DB8500_GPIO_PULL_UP)
- writel(bit, addr + DB8500_GPIO_DATS);
- else if (pull == DB8500_GPIO_PULL_DOWN)
- writel(bit, addr + DB8500_GPIO_DATC);
-}
-
-void db8500_gpio_make_input(unsigned gpio)
-{
- void __iomem *addr = get_gpio_addr(gpio);
- unsigned offset = get_gpio_offset(gpio);
-
- writel(1 << offset, addr + DB8500_GPIO_DIRC);
-}
-
-int db8500_gpio_get_input(unsigned gpio)
-{
- void __iomem *addr = get_gpio_addr(gpio);
- unsigned offset = get_gpio_offset(gpio);
- u32 bit = 1 << offset;
-
- printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n",
- gpio, addr, offset, bit);
-
- return (readl(addr + DB8500_GPIO_DAT) & bit) != 0;
-}
-
-void db8500_gpio_make_output(unsigned gpio, int val)
-{
- void __iomem *addr = get_gpio_addr(gpio);
- unsigned offset = get_gpio_offset(gpio);
-
- writel(1 << offset, addr + DB8500_GPIO_DIRS);
- db8500_gpio_set_output(gpio, val);
-}
-
-void db8500_gpio_set_output(unsigned gpio, int val)
-{
- void __iomem *addr = get_gpio_addr(gpio);
- unsigned offset = get_gpio_offset(gpio);
-
- if (val)
- writel(1 << offset, addr + DB8500_GPIO_DATS);
- else
- writel(1 << offset, addr + DB8500_GPIO_DATC);
-}
-
-/**
- * config_pin - configure a pin's mux attributes
- * @cfg: pin configuration
- *
- * Configures a pin's mode (alternate function or GPIO), its pull up status,
- * and its sleep mode based on the specified configuration. The @cfg is
- * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
- * are constructed using, and can be further enhanced with, the macros in
- * plat/pincfg.h.
- *
- * If a pin's mode is set to GPIO, it is configured as an input to avoid
- * side-effects. The gpio can be manipulated later using standard GPIO API
- * calls.
- */
-static void config_pin(unsigned long cfg)
-{
- int pin = PIN_NUM(cfg);
- int pull = PIN_PULL(cfg);
- int af = PIN_ALT(cfg);
- int output = PIN_DIR(cfg);
- int val = PIN_VAL(cfg);
-
- if (output)
- db8500_gpio_make_output(pin, val);
- else {
- db8500_gpio_make_input(pin);
- db8500_gpio_set_pull(pin, pull);
- }
-
- gpio_set_mode(pin, af);
-}
-
-/**
- * db8500_config_pins - configure several pins at once
- * @cfgs: array of pin configurations
- * @num: number of elments in the array
- *
- * Configures several pins using config_pin(). Refer to that function for
- * further information.
- */
-void db8500_gpio_config_pins(unsigned long *cfgs, size_t num)
-{
- size_t i;
-
- for (i = 0; i < num; i++)
- config_pin(cfgs[i]);
-}
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),
+};