diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/gpio/bcm2835_gpio.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/gpio/bcm2835_gpio.c')
-rw-r--r-- | roms/u-boot/drivers/gpio/bcm2835_gpio.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/gpio/bcm2835_gpio.c b/roms/u-boot/drivers/gpio/bcm2835_gpio.c new file mode 100644 index 000000000..704a6fa71 --- /dev/null +++ b/roms/u-boot/drivers/gpio/bcm2835_gpio.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2012 Vikram Narayananan + * <vikram186@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <errno.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <fdtdec.h> + +struct bcm2835_gpios { + struct bcm2835_gpio_regs *reg; + struct udevice *pinctrl; +}; + +static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio) +{ + struct bcm2835_gpios *gpios = dev_get_priv(dev); + unsigned val; + + val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio)); + val |= (BCM2835_GPIO_INPUT << BCM2835_GPIO_FSEL_SHIFT(gpio)); + writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + + return 0; +} + +static int bcm2835_gpio_direction_output(struct udevice *dev, unsigned int gpio, + int value) +{ + struct bcm2835_gpios *gpios = dev_get_priv(dev); + unsigned val; + + gpio_set_value(gpio, value); + + val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio)); + val |= (BCM2835_GPIO_OUTPUT << BCM2835_GPIO_FSEL_SHIFT(gpio)); + writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + + return 0; +} + +static int bcm2835_get_value(const struct bcm2835_gpios *gpios, unsigned gpio) +{ + unsigned val; + + val = readl(&gpios->reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]); + + return (val >> BCM2835_GPIO_COMMON_SHIFT(gpio)) & 0x1; +} + +static int bcm2835_gpio_get_value(struct udevice *dev, unsigned gpio) +{ + const struct bcm2835_gpios *gpios = dev_get_priv(dev); + + return bcm2835_get_value(gpios, gpio); +} + +static int bcm2835_gpio_set_value(struct udevice *dev, unsigned gpio, + int value) +{ + struct bcm2835_gpios *gpios = dev_get_priv(dev); + u32 *output_reg = value ? gpios->reg->gpset : gpios->reg->gpclr; + + writel(1 << BCM2835_GPIO_COMMON_SHIFT(gpio), + &output_reg[BCM2835_GPIO_COMMON_BANK(gpio)]); + + return 0; +} + +static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct bcm2835_gpios *priv = dev_get_priv(dev); + int funcid; + + funcid = pinctrl_get_gpio_mux(priv->pinctrl, 0, offset); + + switch (funcid) { + case BCM2835_GPIO_OUTPUT: + return GPIOF_OUTPUT; + case BCM2835_GPIO_INPUT: + return GPIOF_INPUT; + default: + return GPIOF_FUNC; + } +} + +static const struct dm_gpio_ops gpio_bcm2835_ops = { + .direction_input = bcm2835_gpio_direction_input, + .direction_output = bcm2835_gpio_direction_output, + .get_value = bcm2835_gpio_get_value, + .set_value = bcm2835_gpio_set_value, + .get_function = bcm2835_gpio_get_function, +}; + +static int bcm2835_gpio_probe(struct udevice *dev) +{ + struct bcm2835_gpios *gpios = dev_get_priv(dev); + struct bcm2835_gpio_plat *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->bank_name = "GPIO"; + uc_priv->gpio_count = BCM2835_GPIO_COUNT; + gpios->reg = (struct bcm2835_gpio_regs *)plat->base; + + /* We know we're spawned by the pinctrl driver */ + gpios->pinctrl = dev->parent; + + return 0; +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static int bcm2835_gpio_of_to_plat(struct udevice *dev) +{ + struct bcm2835_gpio_plat *plat = dev_get_plat(dev); + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->base = addr; + return 0; +} +#endif + +U_BOOT_DRIVER(gpio_bcm2835) = { + .name = "gpio_bcm2835", + .id = UCLASS_GPIO, + .of_to_plat = of_match_ptr(bcm2835_gpio_of_to_plat), + .plat_auto = sizeof(struct bcm2835_gpio_plat), + .ops = &gpio_bcm2835_ops, + .probe = bcm2835_gpio_probe, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto = sizeof(struct bcm2835_gpios), +}; |