X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fgpio%2Fbcm2835_gpio.c;h=beaa21853a473dfaa4e59a58f995cce871afc045;hb=4d686041895a8fd419bbc3842856239c6298d1f2;hp=1d50dbd5e0433d49b6448b6209d206557e7f9835;hpb=6e2fbdea1b26d75314d87c380a36b0015bf824cf;p=oweals%2Fu-boot.git diff --git a/drivers/gpio/bcm2835_gpio.c b/drivers/gpio/bcm2835_gpio.c index 1d50dbd5e0..beaa21853a 100644 --- a/drivers/gpio/bcm2835_gpio.c +++ b/drivers/gpio/bcm2835_gpio.c @@ -2,88 +2,151 @@ * Copyright (C) 2012 Vikram Narayananan * * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * SPDX-License-Identifier: GPL-2.0+ */ #include +#include +#include #include #include +#include -inline int gpio_is_valid(unsigned gpio) -{ - return (gpio < BCM2835_GPIO_COUNT); -} - -int gpio_request(unsigned gpio, const char *label) -{ - return !gpio_is_valid(gpio); -} +struct bcm2835_gpios { + struct bcm2835_gpio_regs *reg; +}; -int gpio_free(unsigned gpio) +static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio) { - return 0; -} - -int gpio_direction_input(unsigned gpio) -{ - struct bcm2835_gpio_regs *reg = - (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE; + struct bcm2835_gpios *gpios = dev_get_priv(dev); unsigned val; - val = readl(®->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + 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, ®->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); return 0; } -int gpio_direction_output(unsigned gpio, int value) +static int bcm2835_gpio_direction_output(struct udevice *dev, unsigned gpio, + int value) { - struct bcm2835_gpio_regs *reg = - (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE; + struct bcm2835_gpios *gpios = dev_get_priv(dev); unsigned val; gpio_set_value(gpio, value); - val = readl(®->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + 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, ®->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); return 0; } -int gpio_get_value(unsigned gpio) +static int bcm2835_get_value(const struct bcm2835_gpios *gpios, unsigned gpio) { - struct bcm2835_gpio_regs *reg = - (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE; unsigned val; - val = readl(®->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]); + val = readl(&gpios->reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]); return (val >> BCM2835_GPIO_COMMON_SHIFT(gpio)) & 0x1; } -int gpio_set_value(unsigned gpio, int value) +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_gpio_regs *reg = - (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE; - u32 *output_reg = value ? reg->gpset : reg->gpclr; + 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; } + +int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned gpio) +{ + struct bcm2835_gpios *gpios = dev_get_priv(dev); + u32 val; + + val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + + return (val >> BCM2835_GPIO_FSEL_SHIFT(gpio) & BCM2835_GPIO_FSEL_MASK); +} + +static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset) +{ + int funcid = bcm2835_gpio_get_func_id(dev, 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_platdata *plat = dev_get_platdata(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; + + return 0; +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static const struct udevice_id bcm2835_gpio_id[] = { + {.compatible = "brcm,bcm2835-gpio"}, + {} +}; + +static int bcm2835_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev); + fdt_addr_t addr; + + addr = devfdt_get_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_match = of_match_ptr(bcm2835_gpio_id), + .ofdata_to_platdata = of_match_ptr(bcm2835_gpio_ofdata_to_platdata), + .platdata_auto_alloc_size = sizeof(struct bcm2835_gpio_platdata), + .ops = &gpio_bcm2835_ops, + .probe = bcm2835_gpio_probe, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct bcm2835_gpios), +};