diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/74x164_gpio.c | 3 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 14 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/bcm6345_gpio.c | 125 | ||||
-rw-r--r-- | drivers/gpio/gpio-uclass.c | 2 | ||||
-rw-r--r-- | drivers/gpio/intel_ich6_gpio.c | 30 |
6 files changed, 167 insertions, 8 deletions
diff --git a/drivers/gpio/74x164_gpio.c b/drivers/gpio/74x164_gpio.c index 750eedfffd0..53a639ae65b 100644 --- a/drivers/gpio/74x164_gpio.c +++ b/drivers/gpio/74x164_gpio.c @@ -156,8 +156,7 @@ static int gen_74x164_probe(struct udevice *dev) ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); if (ret) { - dev_err(dev, "No oe-pins property\n"); - goto free_buf; + dev_dbg(dev, "No oe-pins property\n"); } uc_priv->bank_name = str; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 99516119ff1..15135e538dc 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -21,6 +21,12 @@ config ALTERA_PIO Select this to enable PIO for Altera devices. Please find details on the "Embedded Peripherals IP User Guide" of Altera. +config BCM6345_GPIO + bool "BCM6345 GPIO driver" + depends on DM_GPIO && ARCH_BMIPS + help + This driver supports the GPIO banks on BCM6345 SoCs. + config DWAPB_GPIO bool "DWAPB GPIO driver" depends on DM && DM_GPIO @@ -89,6 +95,14 @@ config MSM_GPIO - APQ8016 - MSM8916 +config OMAP_GPIO + bool "TI OMAP GPIO driver" + depends on ARCH_OMAP2PLUS + default y + help + Support GPIO controllers on the TI OMAP3/4/5 and related (such as + AM335x/AM43xx/AM57xx/DRA7xx/etc) families of SoCs. + config PM8916_GPIO bool "Qualcomm PM8916 PMIC GPIO/keypad driver" depends on DM_GPIO && PMIC_PM8916 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 0ca845f54ca..03df558879b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_DM_74X164) += 74x164_gpio.o obj-$(CONFIG_AT91_GPIO) += at91_gpio.o obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o +obj-$(CONFIG_BCM6345_GPIO) += bcm6345_gpio.o obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o diff --git a/drivers/gpio/bcm6345_gpio.c b/drivers/gpio/bcm6345_gpio.c new file mode 100644 index 00000000000..1c46020aa4d --- /dev/null +++ b/drivers/gpio/bcm6345_gpio.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> + * + * Derived from linux/arch/mips/bcm63xx/gpio.c: + * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> + * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <dm/device.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct bcm6345_gpio_priv { + void __iomem *reg_dirout; + void __iomem *reg_data; +}; + +static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct bcm6345_gpio_priv *priv = dev_get_priv(dev); + + return !!(readl_be(priv->reg_data) & BIT(offset)); +} + +static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct bcm6345_gpio_priv *priv = dev_get_priv(dev); + + if (value) + setbits_be32(priv->reg_data, BIT(offset)); + else + clrbits_be32(priv->reg_data, BIT(offset)); + + return 0; +} + +static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset, + bool input) +{ + if (input) + clrbits_be32(dirout, BIT(offset)); + else + setbits_be32(dirout, BIT(offset)); + + return 0; +} + +static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct bcm6345_gpio_priv *priv = dev_get_priv(dev); + + return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1); +} + +static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct bcm6345_gpio_priv *priv = dev_get_priv(dev); + + return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0); +} + +static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct bcm6345_gpio_priv *priv = dev_get_priv(dev); + + if (readl_be(priv->reg_dirout) & BIT(offset)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static const struct dm_gpio_ops bcm6345_gpio_ops = { + .direction_input = bcm6345_gpio_direction_input, + .direction_output = bcm6345_gpio_direction_output, + .get_value = bcm6345_gpio_get_value, + .set_value = bcm6345_gpio_set_value, + .get_function = bcm6345_gpio_get_function, +}; + +static int bcm6345_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct bcm6345_gpio_priv *priv = dev_get_priv(dev); + fdt_addr_t data_addr, dirout_addr; + fdt_size_t data_size, dirout_size; + + dirout_addr = dev_get_addr_size_index(dev, 0, &dirout_size); + if (dirout_addr == FDT_ADDR_T_NONE) + return -EINVAL; + + data_addr = dev_get_addr_size_index(dev, 1, &data_size); + if (data_addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->reg_data = ioremap(data_addr, data_size); + priv->reg_dirout = ioremap(dirout_addr, dirout_size); + + uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), + "ngpios", 32); + uc_priv->bank_name = dev->name; + + return 0; +} + +static const struct udevice_id bcm6345_gpio_ids[] = { + { .compatible = "brcm,bcm6345-gpio" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(bcm6345_gpio) = { + .name = "bcm6345-gpio", + .id = UCLASS_GPIO, + .of_match = bcm6345_gpio_ids, + .ops = &bcm6345_gpio_ops, + .priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv), + .probe = bcm6345_gpio_probe, +}; diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 9ab9df4ce7a..ba4804083da 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -68,7 +68,7 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc) if (numeric != -1) { offset = numeric - uc_priv->gpio_base; /* Allow GPIOs to be numbered from 0 */ - if (offset >= 0 && offset < uc_priv->gpio_count) + if (offset < uc_priv->gpio_count) break; } diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c index 8b782260bc3..0a9eb03fd05 100644 --- a/drivers/gpio/intel_ich6_gpio.c +++ b/drivers/gpio/intel_ich6_gpio.c @@ -46,22 +46,31 @@ struct ich6_bank_priv { uint16_t use_sel; uint16_t io_sel; uint16_t lvl; + u32 lvl_write_cache; + bool use_lvl_write_cache; }; #define GPIO_USESEL_OFFSET(x) (x) #define GPIO_IOSEL_OFFSET(x) (x + 4) #define GPIO_LVL_OFFSET(x) (x + 8) -static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value) +static int _ich6_gpio_set_value(struct ich6_bank_priv *bank, unsigned offset, + int value) { u32 val; - val = inl(base); + if (bank->use_lvl_write_cache) + val = bank->lvl_write_cache; + else + val = inl(bank->lvl); + if (value) val |= (1UL << offset); else val &= ~(1UL << offset); - outl(val, base); + outl(val, bank->lvl); + if (bank->use_lvl_write_cache) + bank->lvl_write_cache = val; return 0; } @@ -112,6 +121,7 @@ static int ich6_gpio_probe(struct udevice *dev) struct ich6_bank_platdata *plat = dev_get_platdata(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct ich6_bank_priv *bank = dev_get_priv(dev); + const void *prop; uc_priv->gpio_count = GPIO_PER_BANK; uc_priv->bank_name = plat->bank_name; @@ -119,6 +129,14 @@ static int ich6_gpio_probe(struct udevice *dev) bank->io_sel = plat->base_addr + 4; bank->lvl = plat->base_addr + 8; + prop = fdt_getprop(gd->fdt_blob, dev->of_offset, + "use-lvl-write-cache", NULL); + if (prop) + bank->use_lvl_write_cache = true; + else + bank->use_lvl_write_cache = false; + bank->lvl_write_cache = 0; + return 0; } @@ -160,7 +178,7 @@ static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset, if (ret) return ret; - return _ich6_gpio_set_value(bank->lvl, offset, value); + return _ich6_gpio_set_value(bank, offset, value); } static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) @@ -170,6 +188,8 @@ static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) int r; tmplong = inl(bank->lvl); + if (bank->use_lvl_write_cache) + tmplong |= bank->lvl_write_cache; r = (tmplong & (1UL << offset)) ? 1 : 0; return r; } @@ -178,7 +198,7 @@ static int ich6_gpio_set_value(struct udevice *dev, unsigned offset, int value) { struct ich6_bank_priv *bank = dev_get_priv(dev); - return _ich6_gpio_set_value(bank->lvl, offset, value); + return _ich6_gpio_set_value(bank, offset, value); } static int ich6_gpio_get_function(struct udevice *dev, unsigned offset) |