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 | |
parent | a7bdd2dd8e7685166767c5fecfdce7e5dc8a40be (diff) | |
parent | 845d9cf61c3a319fed0069c36f402e74a61ceb8c (diff) |
Merge branch '2021-07-14-platform-updates'
- Assorted platform updates
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpio/db8500_gpio.c | 221 | ||||
-rw-r--r-- | drivers/gpio/nmk_gpio.c | 125 |
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), +}; |