diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 18 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/axp_gpio.c | 21 | ||||
-rw-r--r-- | drivers/gpio/gpio-uclass.c | 2 | ||||
-rw-r--r-- | drivers/gpio/qe_gpio.c | 170 | ||||
-rw-r--r-- | drivers/gpio/sunxi_gpio.c | 6 |
6 files changed, 195 insertions, 23 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7d5ddbdee0c..9bf6e428ded 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -547,6 +547,24 @@ config MPC8XXX_GPIO value setting, the open-drain feature, which can configure individual GPIOs to work as open-drain outputs, is supported. +config QE_GPIO + bool "Freescale QUICC ENGINE GPIO driver" + depends on DM_GPIO + depends on QE + help + This driver supports the QUICC Engine GPIOs of MPC83XX CPUs. + Each GPIO bank is identified by its own entry in the device tree, + i.e. + + qe_pio_a: gpio-controller@1400 { + compatible = "fsl,mpc8323-qe-pario-bank"; + reg = <0x1400 0x18>; + gpio-controller; + #gpio-cells = <2>; + }; + + Each bank has 32 GPIOs. + config MPC8XX_GPIO bool "Freescale MPC8XX GPIO driver" depends on DM_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1e81e369629..64a36c472eb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_TEGRA186_GPIO) += tegra186_gpio.o obj-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o obj-$(CONFIG_ALTERA_PIO) += altera_pio.o obj-$(CONFIG_MPC8XXX_GPIO) += mpc8xxx_gpio.o +obj-$(CONFIG_QE_GPIO) += qe_gpio.o obj-$(CONFIG_MPC8XX_GPIO) += mpc8xx_gpio.o obj-$(CONFIG_MPC83XX_SPISEL_BOOT) += mpc83xx_spisel_boot.o obj-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o diff --git a/drivers/gpio/axp_gpio.c b/drivers/gpio/axp_gpio.c index 35585dc8ac9..49672193ffc 100644 --- a/drivers/gpio/axp_gpio.c +++ b/drivers/gpio/axp_gpio.c @@ -36,18 +36,11 @@ static int axp_gpio_direction_input(struct udevice *dev, unsigned pin) { u8 reg; - switch (pin) { -#ifndef CONFIG_AXP152_POWER /* NA on axp152 */ - case SUNXI_GPIO_AXP0_VBUS_DETECT: - return 0; -#endif - default: - reg = axp_get_gpio_ctrl_reg(pin); - if (reg == 0) - return -EINVAL; + reg = axp_get_gpio_ctrl_reg(pin); + if (reg == 0) + return -EINVAL; - return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); - } + return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); } static int axp_gpio_direction_output(struct udevice *dev, unsigned pin, @@ -83,12 +76,6 @@ static int axp_gpio_get_value(struct udevice *dev, unsigned pin) int ret; switch (pin) { -#ifndef CONFIG_AXP152_POWER /* NA on axp152 */ - case SUNXI_GPIO_AXP0_VBUS_DETECT: - ret = pmic_bus_read(AXP_POWER_STATUS, &val); - mask = AXP_POWER_STATUS_VBUS_PRESENT; - break; -#endif #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC /* Only available on later PMICs */ case SUNXI_GPIO_AXP0_VBUS_ENABLE: diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index c8be5a4d668..712119c3415 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -1219,7 +1219,7 @@ int gpio_request_list_by_name_nodev(ofnode node, const char *list_name, return count; err: - gpio_free_list_nodev(desc, count - 1); + gpio_free_list_nodev(desc, count); return ret; } diff --git a/drivers/gpio/qe_gpio.c b/drivers/gpio/qe_gpio.c new file mode 100644 index 00000000000..16e8d1eae6e --- /dev/null +++ b/drivers/gpio/qe_gpio.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2023 CR GROUP France + * Christophe Leroy <christophe.leroy@csgroup.eu> + */ + +#include <common.h> +#include <dm.h> +#include <mapmem.h> +#include <asm/gpio.h> +#include <asm/immap_83xx.h> +#include <asm/io.h> +#include <dm/of_access.h> + +#define QE_DIR_NONE 0 +#define QE_DIR_OUT 1 +#define QE_DIR_IN 2 +#define QE_DIR_IN_OUT 3 + +struct qe_gpio_data { + /* The bank's register base in memory */ + struct gpio_n __iomem *base; + /* The address of the registers; used to identify the bank */ + phys_addr_t addr; +}; + +static inline u32 gpio_mask(uint gpio) +{ + return 1U << (31 - (gpio)); +} + +static inline u32 gpio_mask2(uint gpio) +{ + return 1U << (30 - ((gpio & 15) << 1)); +} + +static int qe_gpio_direction_input(struct udevice *dev, uint gpio) +{ + struct qe_gpio_data *data = dev_get_priv(dev); + struct gpio_n __iomem *base = data->base; + u32 mask2 = gpio_mask2(gpio); + + if (gpio < 16) + clrsetbits_be32(&base->dir1, mask2 * QE_DIR_OUT, mask2 * QE_DIR_IN); + else + clrsetbits_be32(&base->dir2, mask2 * QE_DIR_OUT, mask2 * QE_DIR_IN); + + return 0; +} + +static int qe_gpio_set_value(struct udevice *dev, uint gpio, int value) +{ + struct qe_gpio_data *data = dev_get_priv(dev); + struct gpio_n __iomem *base = data->base; + u32 mask = gpio_mask(gpio); + u32 mask2 = gpio_mask2(gpio); + + if (gpio < 16) + clrsetbits_be32(&base->dir1, mask2 * QE_DIR_IN, mask2 * QE_DIR_OUT); + else + clrsetbits_be32(&base->dir2, mask2 * QE_DIR_IN, mask2 * QE_DIR_OUT); + + if (value) + setbits_be32(&base->pdat, mask); + else + clrbits_be32(&base->pdat, mask); + + return 0; +} + +static int qe_gpio_get_value(struct udevice *dev, uint gpio) +{ + struct qe_gpio_data *data = dev_get_priv(dev); + struct gpio_n __iomem *base = data->base; + u32 mask = gpio_mask(gpio); + + return !!(in_be32(&base->pdat) & mask); +} + +static int qe_gpio_get_function(struct udevice *dev, uint gpio) +{ + struct qe_gpio_data *data = dev_get_priv(dev); + struct gpio_n __iomem *base = data->base; + u32 mask2 = gpio_mask2(gpio); + int dir; + + if (gpio < 16) + dir = in_be32(&base->dir1); + else + dir = in_be32(&base->dir2); + + if ((dir & (mask2 * QE_DIR_IN_OUT)) == (mask2 & QE_DIR_IN)) + return GPIOF_INPUT; + else if ((dir & (mask2 * QE_DIR_IN_OUT)) == (mask2 & QE_DIR_OUT)) + return GPIOF_OUTPUT; + else + return GPIOF_UNKNOWN; +} + +static int qe_gpio_of_to_plat(struct udevice *dev) +{ + struct qe_gpio_plat *plat = dev_get_plat(dev); + + plat->addr = dev_read_addr_size_index(dev, 0, (fdt_size_t *)&plat->size); + + return 0; +} + +static int qe_gpio_plat_to_priv(struct udevice *dev) +{ + struct qe_gpio_data *priv = dev_get_priv(dev); + struct qe_gpio_plat *plat = dev_get_plat(dev); + unsigned long size = plat->size; + + if (size == 0) + size = sizeof(struct gpio_n); + + priv->addr = plat->addr; + priv->base = (void __iomem *)plat->addr; + + if (!priv->base) + return -ENOMEM; + + return 0; +} + +static int qe_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct qe_gpio_data *data = dev_get_priv(dev); + char name[32], *str; + + qe_gpio_plat_to_priv(dev); + + snprintf(name, sizeof(name), "QE@%.8llx", + (unsigned long long)data->addr); + str = strdup(name); + + if (!str) + return -ENOMEM; + + uc_priv->bank_name = str; + uc_priv->gpio_count = 32; + + return 0; +} + +static const struct dm_gpio_ops gpio_qe_ops = { + .direction_input = qe_gpio_direction_input, + .direction_output = qe_gpio_set_value, + .get_value = qe_gpio_get_value, + .set_value = qe_gpio_set_value, + .get_function = qe_gpio_get_function, +}; + +static const struct udevice_id qe_gpio_ids[] = { + { .compatible = "fsl,mpc8323-qe-pario-bank"}, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(gpio_qe) = { + .name = "gpio_qe", + .id = UCLASS_GPIO, + .ops = &gpio_qe_ops, + .of_to_plat = qe_gpio_of_to_plat, + .plat_auto = sizeof(struct qe_gpio_plat), + .of_match = qe_gpio_ids, + .probe = qe_gpio_probe, + .priv_auto = sizeof(struct qe_gpio_data), +}; diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 1e85db179a6..f0b42e4fdb7 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -117,11 +117,7 @@ int sunxi_name_to_gpio(const char *name) #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO char lookup[8]; - if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) { - sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d", - SUNXI_GPIO_AXP0_VBUS_DETECT); - name = lookup; - } else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) { + if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) { sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d", SUNXI_GPIO_AXP0_VBUS_ENABLE); name = lookup; |