diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/dwapb_gpio.c | 33 | ||||
-rw-r--r-- | drivers/gpio/mpc8xxx_gpio.c | 108 | ||||
-rw-r--r-- | drivers/gpio/sandbox.c | 10 | ||||
-rw-r--r-- | drivers/gpio/stm32_gpio.c | 2 |
4 files changed, 121 insertions, 32 deletions
diff --git a/drivers/gpio/dwapb_gpio.c b/drivers/gpio/dwapb_gpio.c index e5e3518194..37916e7771 100644 --- a/drivers/gpio/dwapb_gpio.c +++ b/drivers/gpio/dwapb_gpio.c @@ -40,7 +40,7 @@ struct gpio_dwapb_platdata { const char *name; int bank; int pins; - fdt_addr_t base; + void __iomem *base; }; static int dwapb_gpio_direction_input(struct udevice *dev, unsigned pin) @@ -66,13 +66,6 @@ static int dwapb_gpio_direction_output(struct udevice *dev, unsigned pin, return 0; } -static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin) -{ - struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); - return !!(readl(plat->base + GPIO_EXT_PORT(plat->bank)) & (1 << pin)); -} - - static int dwapb_gpio_set_value(struct udevice *dev, unsigned pin, int val) { struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); @@ -98,6 +91,18 @@ static int dwapb_gpio_get_function(struct udevice *dev, unsigned offset) return GPIOF_INPUT; } +static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin) +{ + struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); + u32 value; + + if (dwapb_gpio_get_function(dev, pin) == GPIOF_OUTPUT) + value = readl(plat->base + GPIO_SWPORT_DR(plat->bank)); + else + value = readl(plat->base + GPIO_EXT_PORT(plat->bank)); + return !!(value & BIT(pin)); +} + static const struct dm_gpio_ops gpio_dwapb_ops = { .direction_input = dwapb_gpio_direction_input, .direction_output = dwapb_gpio_direction_output, @@ -176,7 +181,7 @@ static int gpio_dwapb_bind(struct udevice *dev) if (!plat) return -ENOMEM; - plat->base = base; + plat->base = (void *)base; plat->bank = bank; plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0); @@ -186,7 +191,15 @@ static int gpio_dwapb_bind(struct udevice *dev) * Fall back to node name. This means accessing pins * via bank name won't work. */ - plat->name = ofnode_get_name(node); + char name[32]; + + snprintf(name, sizeof(name), "%s_", + ofnode_get_name(node)); + plat->name = strdup(name); + if (!plat->name) { + kfree(plat); + return -ENOMEM; + } } ret = device_bind_ofnode(dev, dev->driver, plat->name, diff --git a/drivers/gpio/mpc8xxx_gpio.c b/drivers/gpio/mpc8xxx_gpio.c index 1dfd22522c..27881a7322 100644 --- a/drivers/gpio/mpc8xxx_gpio.c +++ b/drivers/gpio/mpc8xxx_gpio.c @@ -6,12 +6,15 @@ * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is * * Copyright 2010 eXMeritus, A Boeing Company + * Copyright 2020 NXP */ #include <common.h> #include <dm.h> #include <mapmem.h> #include <asm/gpio.h> +#include <asm/io.h> +#include <dm/of_access.h> struct ccsr_gpio { u32 gpdir; @@ -20,6 +23,7 @@ struct ccsr_gpio { u32 gpier; u32 gpimr; u32 gpicr; + u32 gpibe; }; struct mpc8xxx_gpio_data { @@ -35,6 +39,7 @@ struct mpc8xxx_gpio_data { */ u32 dat_shadow; ulong type; + bool little_endian; }; enum { @@ -47,33 +52,56 @@ inline u32 gpio_mask(uint gpio) return (1U << (31 - (gpio))); } -static inline u32 mpc8xxx_gpio_get_val(struct ccsr_gpio *base, u32 mask) +static inline u32 mpc8xxx_gpio_get_val(struct udevice *dev, u32 mask) { - return in_be32(&base->gpdat) & mask; + struct mpc8xxx_gpio_data *data = dev_get_priv(dev); + + if (data->little_endian) + return in_le32(&data->base->gpdat) & mask; + else + return in_be32(&data->base->gpdat) & mask; } -static inline u32 mpc8xxx_gpio_get_dir(struct ccsr_gpio *base, u32 mask) +static inline u32 mpc8xxx_gpio_get_dir(struct udevice *dev, u32 mask) { - return in_be32(&base->gpdir) & mask; + struct mpc8xxx_gpio_data *data = dev_get_priv(dev); + + if (data->little_endian) + return in_le32(&data->base->gpdir) & mask; + else + return in_be32(&data->base->gpdir) & mask; } -static inline int mpc8xxx_gpio_open_drain_val(struct ccsr_gpio *base, u32 mask) +static inline int mpc8xxx_gpio_open_drain_val(struct udevice *dev, u32 mask) { - return in_be32(&base->gpodr) & mask; + struct mpc8xxx_gpio_data *data = dev_get_priv(dev); + + if (data->little_endian) + return in_le32(&data->base->gpodr) & mask; + else + return in_be32(&data->base->gpodr) & mask; } -static inline void mpc8xxx_gpio_open_drain_on(struct ccsr_gpio *base, u32 +static inline void mpc8xxx_gpio_open_drain_on(struct udevice *dev, u32 gpios) { + struct mpc8xxx_gpio_data *data = dev_get_priv(dev); /* GPODR register 1 -> open drain on */ - setbits_be32(&base->gpodr, gpios); + if (data->little_endian) + setbits_le32(&data->base->gpodr, gpios); + else + setbits_be32(&data->base->gpodr, gpios); } -static inline void mpc8xxx_gpio_open_drain_off(struct ccsr_gpio *base, +static inline void mpc8xxx_gpio_open_drain_off(struct udevice *dev, u32 gpios) { + struct mpc8xxx_gpio_data *data = dev_get_priv(dev); /* GPODR register 0 -> open drain off (actively driven) */ - clrbits_be32(&base->gpodr, gpios); + if (data->little_endian) + clrbits_le32(&data->base->gpodr, gpios); + else + clrbits_be32(&data->base->gpodr, gpios); } static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio) @@ -82,7 +110,10 @@ static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio) u32 mask = gpio_mask(gpio); /* GPDIR register 0 -> input */ - clrbits_be32(&data->base->gpdir, mask); + if (data->little_endian) + clrbits_le32(&data->base->gpdir, mask); + else + clrbits_be32(&data->base->gpdir, mask); return 0; } @@ -100,10 +131,20 @@ static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value) data->dat_shadow &= ~mask; } - gpdir = in_be32(&base->gpdir); + if (data->little_endian) + gpdir = in_le32(&base->gpdir); + else + gpdir = in_be32(&base->gpdir); + gpdir |= gpio_mask(gpio); - out_be32(&base->gpdat, gpdir & data->dat_shadow); - out_be32(&base->gpdir, gpdir); + + if (data->little_endian) { + out_le32(&base->gpdat, gpdir & data->dat_shadow); + out_le32(&base->gpdir, gpdir); + } else { + out_be32(&base->gpdat, gpdir & data->dat_shadow); + out_be32(&base->gpdir, gpdir); + } return 0; } @@ -124,21 +165,20 @@ static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio) { struct mpc8xxx_gpio_data *data = dev_get_priv(dev); - if (!!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio))) { + if (!!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio))) { /* Output -> use shadowed value */ return !!(data->dat_shadow & gpio_mask(gpio)); } /* Input -> read value from GPDAT register */ - return !!mpc8xxx_gpio_get_val(data->base, gpio_mask(gpio)); + return !!mpc8xxx_gpio_get_val(dev, gpio_mask(gpio)); } static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio) { - struct mpc8xxx_gpio_data *data = dev_get_priv(dev); int dir; - dir = !!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio)); + dir = !!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio)); return dir ? GPIOF_OUTPUT : GPIOF_INPUT; } @@ -146,14 +186,33 @@ static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio) static int mpc8xxx_gpio_ofdata_to_platdata(struct udevice *dev) { struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev); + struct mpc8xxx_gpio_data *data = dev_get_priv(dev); fdt_addr_t addr; - u32 reg[2]; + u32 i; + u32 reg[4]; + + if (ofnode_read_bool(dev->node, "little-endian")) + data->little_endian = true; + + if (data->little_endian) + dev_read_u32_array(dev, "reg", reg, 4); + else + dev_read_u32_array(dev, "reg", reg, 2); + + if (data->little_endian) { + for (i = 0; i < 2; i++) + reg[i] = be32_to_cpu(reg[i]); + } - dev_read_u32_array(dev, "reg", reg, 2); addr = dev_translate_address(dev, reg); plat->addr = addr; - plat->size = reg[1]; + + if (data->little_endian) + plat->size = reg[3]; + else + plat->size = reg[1]; + plat->ngpios = dev_read_u32_default(dev, "ngpios", 32); return 0; @@ -198,6 +257,13 @@ static int mpc8xxx_gpio_probe(struct udevice *dev) if (!str) return -ENOMEM; + if (ofnode_device_is_compatible(dev->node, "fsl,qoriq-gpio")) { + unsigned long gpibe = data->addr + sizeof(struct ccsr_gpio) + - sizeof(u32); + + out_be32((unsigned int *)gpibe, 0xffffffff); + } + uc_priv->bank_name = str; uc_priv->gpio_count = data->gpio_count; diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index c2f80472b8..eb2600de31 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -185,7 +185,15 @@ static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, dir_flags = get_gpio_dir_flags(dev, offset); - *dir_flags = flags; + /* + * For testing purposes keep the output value when switching to input. + * This allows us to manipulate the input value via the gpio command. + */ + if (flags & GPIOD_IS_IN) + *dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) | + (*dir_flags & GPIOD_IS_OUT_ACTIVE); + else + *dir_flags = flags; return 0; } diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 473e364796..b885cfb57e 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -18,6 +18,8 @@ #include <linux/errno.h> #include <linux/io.h> +#define STM32_GPIOS_PER_BANK 16 + #define MODE_BITS(gpio_pin) ((gpio_pin) * 2) #define MODE_BITS_MASK 3 #define BSRR_BIT(gpio_pin, value) BIT((gpio_pin) + (value ? 0 : 16)) |