diff options
author | Simon Glass <sjg@chromium.org> | 2014-09-23 03:30:56 +0400 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2014-10-22 20:36:57 +0400 |
commit | 41e98e011da9a3a4461e8cb1479ce343898264fe (patch) | |
tree | ee5a4a4bcc3f57e39df466589913cc126ffc5a83 /drivers/gpio | |
parent | da802b9e2726c7467e0b402efeb6ad3d975f1282 (diff) | |
download | u-boot-41e98e011da9a3a4461e8cb1479ce343898264fe.tar.xz |
dm: rpi: Convert GPIO driver to driver model
Convert the BCM2835 GPIO driver to use driver model, and switch over
Raspberry Pi to use this, since it is the only board.
Signed-off-by: Simon Glass <sjg@chromium.org>
Tested-by: Stephen Warren <swarren@wwwdotorg.org>
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/bcm2835_gpio.c | 180 |
1 files changed, 157 insertions, 23 deletions
diff --git a/drivers/gpio/bcm2835_gpio.c b/drivers/gpio/bcm2835_gpio.c index 97b5137114..332cfc2b23 100644 --- a/drivers/gpio/bcm2835_gpio.c +++ b/drivers/gpio/bcm2835_gpio.c @@ -6,73 +6,207 @@ */ #include <common.h> +#include <dm.h> +#include <errno.h> #include <asm/gpio.h> #include <asm/io.h> -inline int gpio_is_valid(unsigned gpio) +#define GPIO_NAME_SIZE 20 + +struct bcm2835_gpios { + char label[BCM2835_GPIO_COUNT][GPIO_NAME_SIZE]; + struct bcm2835_gpio_regs *reg; +}; + +/** + * gpio_is_requested() - check if a GPIO has been requested + * + * @bank: Bank to check + * @offset: GPIO offset within bank to check + * @return true if marked as requested, false if not + */ +static inline bool gpio_is_requested(struct bcm2835_gpios *gpios, int offset) { - return (gpio < BCM2835_GPIO_COUNT); + return *gpios->label[offset] != '\0'; } -int gpio_request(unsigned gpio, const char *label) +static int check_requested(struct udevice *dev, unsigned offset, + const char *func) { - return !gpio_is_valid(gpio); + struct bcm2835_gpios *gpios = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + + if (!gpio_is_requested(gpios, offset)) { + printf("omap_gpio: %s: error: gpio %s%d not requested\n", + func, uc_priv->bank_name, offset); + return -EPERM; + } + + return 0; } -int gpio_free(unsigned gpio) +static int bcm2835_gpio_request(struct udevice *dev, unsigned offset, + const char *label) { + struct bcm2835_gpios *gpios = dev_get_priv(dev); + + if (gpio_is_requested(gpios, offset)) + return -EBUSY; + + strncpy(gpios->label[offset], label, GPIO_NAME_SIZE); + gpios->label[offset][GPIO_NAME_SIZE - 1] = '\0'; + return 0; } -int gpio_direction_input(unsigned gpio) +static int bcm2835_gpio_free(struct udevice *dev, unsigned offset) { - struct bcm2835_gpio_regs *reg = - (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE; + struct bcm2835_gpios *gpios = dev_get_priv(dev); + int ret; + + ret = check_requested(dev, offset, __func__); + if (ret) + return ret; + gpios->label[offset][0] = '\0'; + + return 0; +} + +static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio) +{ + 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 bool bcm2835_gpio_is_output(const struct bcm2835_gpios *gpios, int gpio) +{ + u32 val; + + val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]); + val &= BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio); + return val ? true : false; +} + +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) { - struct bcm2835_gpio_regs *reg = - (struct bcm2835_gpio_regs *)BCM2835_GPIO_BASE; - u32 *output_reg = value ? reg->gpset : reg->gpclr; + 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 *gpios = dev_get_priv(dev); + + if (!gpio_is_requested(gpios, offset)) + return GPIOF_UNUSED; + + /* GPIOF_FUNC is not implemented yet */ + if (bcm2835_gpio_is_output(gpios, offset)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int bcm2835_gpio_get_state(struct udevice *dev, unsigned int offset, + char *buf, int bufsize) +{ + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + struct bcm2835_gpios *gpios = dev_get_priv(dev); + const char *label; + bool requested; + bool is_output; + int size; + + label = gpios->label[offset]; + is_output = bcm2835_gpio_is_output(gpios, offset); + size = snprintf(buf, bufsize, "%s%d: ", + uc_priv->bank_name ? uc_priv->bank_name : "", offset); + buf += size; + bufsize -= size; + requested = gpio_is_requested(gpios, offset); + snprintf(buf, bufsize, "%s: %d [%c]%s%s", + is_output ? "out" : " in", + bcm2835_get_value(gpios, offset), + requested ? 'x' : ' ', + requested ? " " : "", + label); + + return 0; +} + +static const struct dm_gpio_ops gpio_bcm2835_ops = { + .request = bcm2835_gpio_request, + .free = bcm2835_gpio_free, + .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, + .get_state = bcm2835_gpio_get_state, +}; + +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->uclass_priv; + + uc_priv->bank_name = "GPIO"; + uc_priv->gpio_count = BCM2835_GPIO_COUNT; + gpios->reg = (struct bcm2835_gpio_regs *)plat->base; + + return 0; +} + +U_BOOT_DRIVER(gpio_bcm2835) = { + .name = "gpio_bcm2835", + .id = UCLASS_GPIO, + .ops = &gpio_bcm2835_ops, + .probe = bcm2835_gpio_probe, + .priv_auto_alloc_size = sizeof(struct bcm2835_gpios), +}; |