From 41e98e011da9a3a4461e8cb1479ce343898264fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 22 Sep 2014 17:30:56 -0600 Subject: [PATCH] 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 Tested-by: Stephen Warren Acked-by: Stephen Warren --- arch/arm/include/asm/arch-bcm2835/gpio.h | 9 ++ board/raspberrypi/rpi_b/rpi_b.c | 11 ++ drivers/gpio/bcm2835_gpio.c | 180 ++++++++++++++++++++--- include/configs/rpi_b.h | 5 + 4 files changed, 182 insertions(+), 23 deletions(-) diff --git a/arch/arm/include/asm/arch-bcm2835/gpio.h b/arch/arm/include/asm/arch-bcm2835/gpio.h index 9a49b6e05e..db42896201 100644 --- a/arch/arm/include/asm/arch-bcm2835/gpio.h +++ b/arch/arm/include/asm/arch-bcm2835/gpio.h @@ -52,4 +52,13 @@ struct bcm2835_gpio_regs { u32 gppudclk[2]; }; +/** + * struct bcm2835_gpio_platdata - GPIO platform description + * + * @base: Base address of GPIO controller + */ +struct bcm2835_gpio_platdata { + unsigned long base; +}; + #endif /* _BCM2835_GPIO_H_ */ diff --git a/board/raspberrypi/rpi_b/rpi_b.c b/board/raspberrypi/rpi_b/rpi_b.c index 220bb90dc1..447c940f63 100644 --- a/board/raspberrypi/rpi_b/rpi_b.c +++ b/board/raspberrypi/rpi_b/rpi_b.c @@ -16,15 +16,26 @@ #include #include +#include #include #include #include +#include #include #include #include DECLARE_GLOBAL_DATA_PTR; +static const struct bcm2835_gpio_platdata gpio_platdata = { + .base = BCM2835_GPIO_BASE, +}; + +U_BOOT_DEVICE(bcm2835_gpios) = { + .name = "gpio_bcm2835", + .platdata = &gpio_platdata, +}; + struct msg_get_arm_mem { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; 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 +#include +#include #include #include -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), +}; diff --git a/include/configs/rpi_b.h b/include/configs/rpi_b.h index 2d69809480..d9475e950b 100644 --- a/include/configs/rpi_b.h +++ b/include/configs/rpi_b.h @@ -31,6 +31,11 @@ */ #define CONFIG_MACH_TYPE MACH_TYPE_BCM2708 +/* Enable driver model */ +#define CONFIG_DM +#define CONFIG_CMD_DM +#define CONFIG_DM_GPIO + /* Memory layout */ #define CONFIG_NR_DRAM_BANKS 1 #define CONFIG_SYS_SDRAM_BASE 0x00000000 -- 2.39.5