X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fgpio%2Fstm32_gpio.c;h=f55f834e7d667dcbd98665137a3c95eff5b51cc3;hb=9f2b066cda3dd0b4bf583c40610eba347f2c03cd;hp=9f9ff48c0a9343926945704fe644903732e8f9c0;hpb=14cec061139a8fb0461d8748d14a2dbcf8a56f2e;p=oweals%2Fu-boot.git diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 9f9ff48c0a..f55f834e7d 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -1,294 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2011 - * Yuri Tikhonov, Emcraft Systems, yur@emcraft.com - * - * (C) Copyright 2015 - * Kamil Lulko, - * - * Copyright 2015 ATS Advanced Telematics Systems GmbH - * Copyright 2015 Konsulko Group, Matt Porter - * - * SPDX-License-Identifier: GPL-2.0+ + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Vikas Manocha, for STMicroelectronics. */ #include -#include -#include -#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include -DECLARE_GLOBAL_DATA_PTR; - -#if defined(CONFIG_STM32F4) -#define STM32_GPIOA_BASE (STM32_AHB1PERIPH_BASE + 0x0000) -#define STM32_GPIOB_BASE (STM32_AHB1PERIPH_BASE + 0x0400) -#define STM32_GPIOC_BASE (STM32_AHB1PERIPH_BASE + 0x0800) -#define STM32_GPIOD_BASE (STM32_AHB1PERIPH_BASE + 0x0C00) -#define STM32_GPIOE_BASE (STM32_AHB1PERIPH_BASE + 0x1000) -#define STM32_GPIOF_BASE (STM32_AHB1PERIPH_BASE + 0x1400) -#define STM32_GPIOG_BASE (STM32_AHB1PERIPH_BASE + 0x1800) -#define STM32_GPIOH_BASE (STM32_AHB1PERIPH_BASE + 0x1C00) -#define STM32_GPIOI_BASE (STM32_AHB1PERIPH_BASE + 0x2000) - -static const unsigned long io_base[] = { - STM32_GPIOA_BASE, STM32_GPIOB_BASE, STM32_GPIOC_BASE, - STM32_GPIOD_BASE, STM32_GPIOE_BASE, STM32_GPIOF_BASE, - STM32_GPIOG_BASE, STM32_GPIOH_BASE, STM32_GPIOI_BASE -}; - -struct stm32_gpio_regs { - u32 moder; /* GPIO port mode */ - u32 otyper; /* GPIO port output type */ - u32 ospeedr; /* GPIO port output speed */ - u32 pupdr; /* GPIO port pull-up/pull-down */ - u32 idr; /* GPIO port input data */ - u32 odr; /* GPIO port output data */ - u32 bsrr; /* GPIO port bit set/reset */ - u32 lckr; /* GPIO port configuration lock */ - u32 afr[2]; /* GPIO alternate function */ -}; - -#define CHECK_DSC(x) (!x || x->port > 8 || x->pin > 15) -#define CHECK_CTL(x) (!x || x->af > 15 || x->mode > 3 || x->otype > 1 || \ - x->pupd > 2 || x->speed > 3) +#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)) -int stm32_gpio_config(const struct stm32_gpio_dsc *dsc, - const struct stm32_gpio_ctl *ctl) +#ifndef CONFIG_SPL_BUILD +/* + * convert gpio offset to gpio index taking into account gpio holes + * into gpio bank + */ +int stm32_offset_to_index(struct udevice *dev, unsigned int offset) { - struct stm32_gpio_regs *gpio_regs; - u32 i; - int rv; - - if (CHECK_DSC(dsc)) { - rv = -EINVAL; - goto out; - } - if (CHECK_CTL(ctl)) { - rv = -EINVAL; - goto out; + struct stm32_gpio_priv *priv = dev_get_priv(dev); + unsigned int idx = 0; + int i; + + for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { + if (priv->gpio_range & BIT(i)) { + if (idx == offset) + return idx; + idx++; + } } + /* shouldn't happen */ + return -EINVAL; +} - gpio_regs = (struct stm32_gpio_regs *)io_base[dsc->port]; +static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index; + int mask; + int idx; - i = (dsc->pin & 0x07) * 4; - clrsetbits_le32(&gpio_regs->afr[dsc->pin >> 3], 0xF << i, ctl->af << i); + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - i = dsc->pin * 2; + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; - clrsetbits_le32(&gpio_regs->moder, 0x3 << i, ctl->mode << i); - clrsetbits_le32(&gpio_regs->otyper, 0x3 << i, ctl->otype << i); - clrsetbits_le32(&gpio_regs->ospeedr, 0x3 << i, ctl->speed << i); - clrsetbits_le32(&gpio_regs->pupdr, 0x3 << i, ctl->pupd << i); + clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); - rv = 0; -out: - return rv; + return 0; } -#elif defined(CONFIG_STM32F1) -#define STM32_GPIOA_BASE (STM32_APB2PERIPH_BASE + 0x0800) -#define STM32_GPIOB_BASE (STM32_APB2PERIPH_BASE + 0x0C00) -#define STM32_GPIOC_BASE (STM32_APB2PERIPH_BASE + 0x1000) -#define STM32_GPIOD_BASE (STM32_APB2PERIPH_BASE + 0x1400) -#define STM32_GPIOE_BASE (STM32_APB2PERIPH_BASE + 0x1800) -#define STM32_GPIOF_BASE (STM32_APB2PERIPH_BASE + 0x1C00) -#define STM32_GPIOG_BASE (STM32_APB2PERIPH_BASE + 0x2000) - -static const unsigned long io_base[] = { - STM32_GPIOA_BASE, STM32_GPIOB_BASE, STM32_GPIOC_BASE, - STM32_GPIOD_BASE, STM32_GPIOE_BASE, STM32_GPIOF_BASE, - STM32_GPIOG_BASE -}; - -#define STM32_GPIO_CR_MODE_MASK 0x3 -#define STM32_GPIO_CR_MODE_SHIFT(p) (p * 4) -#define STM32_GPIO_CR_CNF_MASK 0x3 -#define STM32_GPIO_CR_CNF_SHIFT(p) (p * 4 + 2) - -struct stm32_gpio_regs { - u32 crl; /* GPIO port configuration low */ - u32 crh; /* GPIO port configuration high */ - u32 idr; /* GPIO port input data */ - u32 odr; /* GPIO port output data */ - u32 bsrr; /* GPIO port bit set/reset */ - u32 brr; /* GPIO port bit reset */ - u32 lckr; /* GPIO port configuration lock */ -}; - -#define CHECK_DSC(x) (!x || x->port > 6 || x->pin > 15) -#define CHECK_CTL(x) (!x || x->mode > 3 || x->icnf > 3 || x->ocnf > 3 || \ - x->pupd > 1) -int stm32_gpio_config(const struct stm32_gpio_dsc *dsc, - const struct stm32_gpio_ctl *ctl) +static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) { - struct stm32_gpio_regs *gpio_regs; - u32 *cr; - int p, crp; - int rv; - - if (CHECK_DSC(dsc)) { - rv = -EINVAL; - goto out; - } - if (CHECK_CTL(ctl)) { - rv = -EINVAL; - goto out; - } + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index; + int mask; + int idx; - p = dsc->pin; + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - gpio_regs = (struct stm32_gpio_regs *)io_base[dsc->port]; + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; - if (p < 8) { - cr = &gpio_regs->crl; - crp = p; - } else { - cr = &gpio_regs->crh; - crp = p - 8; - } + clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); - clrbits_le32(cr, 0x3 << STM32_GPIO_CR_MODE_SHIFT(crp)); - setbits_le32(cr, ctl->mode << STM32_GPIO_CR_MODE_SHIFT(crp)); - - clrbits_le32(cr, 0x3 << STM32_GPIO_CR_CNF_SHIFT(crp)); - /* Inputs set the optional pull up / pull down */ - if (ctl->mode == STM32_GPIO_MODE_IN) { - setbits_le32(cr, ctl->icnf << STM32_GPIO_CR_CNF_SHIFT(crp)); - clrbits_le32(&gpio_regs->odr, 0x1 << p); - setbits_le32(&gpio_regs->odr, ctl->pupd << p); - } else { - setbits_le32(cr, ctl->ocnf << STM32_GPIO_CR_CNF_SHIFT(crp)); - } + writel(BSRR_BIT(idx, value), ®s->bsrr); - rv = 0; -out: - return rv; + return 0; } -#else -#error STM32 family not supported -#endif -int stm32_gpout_set(const struct stm32_gpio_dsc *dsc, int state) +static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) { - struct stm32_gpio_regs *gpio_regs; - int rv; + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int idx; - if (CHECK_DSC(dsc)) { - rv = -EINVAL; - goto out; - } - - gpio_regs = (struct stm32_gpio_regs *)io_base[dsc->port]; + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - if (state) - writel(1 << dsc->pin, &gpio_regs->bsrr); - else - writel(1 << (dsc->pin + 16), &gpio_regs->bsrr); - - rv = 0; -out: - return rv; + return readl(®s->idr) & BIT(idx) ? 1 : 0; } -int stm32_gpin_get(const struct stm32_gpio_dsc *dsc) +static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) { - struct stm32_gpio_regs *gpio_regs; - int rv; + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int idx; - if (CHECK_DSC(dsc)) { - rv = -EINVAL; - goto out; - } + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - gpio_regs = (struct stm32_gpio_regs *)io_base[dsc->port]; - rv = readl(&gpio_regs->idr) & (1 << dsc->pin); -out: - return rv; -} - -/* Common GPIO API */ + writel(BSRR_BIT(idx, value), ®s->bsrr); -int gpio_request(unsigned gpio, const char *label) -{ return 0; } -int gpio_free(unsigned gpio) +static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) { - return 0; + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index; + int mask; + int idx; + u32 mode; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + + mode = (readl(®s->moder) & mask) >> bits_index; + if (mode == STM32_GPIO_MODE_OUT) + return GPIOF_OUTPUT; + if (mode == STM32_GPIO_MODE_IN) + return GPIOF_INPUT; + if (mode == STM32_GPIO_MODE_AN) + return GPIOF_UNUSED; + + return GPIOF_FUNC; } -int gpio_direction_input(unsigned gpio) -{ - struct stm32_gpio_dsc dsc; - struct stm32_gpio_ctl ctl; - - dsc.port = stm32_gpio_to_port(gpio); - dsc.pin = stm32_gpio_to_pin(gpio); -#if defined(CONFIG_STM32F4) - ctl.af = STM32_GPIO_AF0; - ctl.mode = STM32_GPIO_MODE_IN; - ctl.otype = STM32_GPIO_OTYPE_PP; - ctl.pupd = STM32_GPIO_PUPD_NO; - ctl.speed = STM32_GPIO_SPEED_50M; -#elif defined(CONFIG_STM32F1) - ctl.mode = STM32_GPIO_MODE_IN; - ctl.icnf = STM32_GPIO_ICNF_IN_FLT; - ctl.ocnf = STM32_GPIO_OCNF_GP_PP; /* ignored for input */ - ctl.pupd = STM32_GPIO_PUPD_UP; /* ignored for floating */ -#else -#error STM32 family not supported +static const struct dm_gpio_ops gpio_stm32_ops = { + .direction_input = stm32_gpio_direction_input, + .direction_output = stm32_gpio_direction_output, + .get_value = stm32_gpio_get_value, + .set_value = stm32_gpio_set_value, + .get_function = stm32_gpio_get_function, +}; #endif - return stm32_gpio_config(&dsc, &ctl); -} - -int gpio_direction_output(unsigned gpio, int value) +static int gpio_stm32_probe(struct udevice *dev) { - struct stm32_gpio_dsc dsc; - struct stm32_gpio_ctl ctl; - int res; - - dsc.port = stm32_gpio_to_port(gpio); - dsc.pin = stm32_gpio_to_pin(gpio); -#if defined(CONFIG_STM32F4) - ctl.af = STM32_GPIO_AF0; - ctl.mode = STM32_GPIO_MODE_OUT; - ctl.pupd = STM32_GPIO_PUPD_NO; - ctl.speed = STM32_GPIO_SPEED_50M; -#elif defined(CONFIG_STM32F1) - ctl.mode = STM32_GPIO_MODE_OUT_50M; - ctl.ocnf = STM32_GPIO_OCNF_GP_PP; - ctl.icnf = STM32_GPIO_ICNF_IN_FLT; /* ignored for output */ - ctl.pupd = STM32_GPIO_PUPD_UP; /* ignored for output */ -#else -#error STM32 family not supported -#endif + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct clk clk; + fdt_addr_t addr; + int ret; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = (struct stm32_gpio_regs *)addr; + +#ifndef CONFIG_SPL_BUILD + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct ofnode_phandle_args args; + const char *name; + int i; + + name = dev_read_string(dev, "st,bank-name"); + if (!name) + return -EINVAL; + uc_priv->bank_name = name; + + i = 0; + ret = dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, i, &args); + + if (ret == -ENOENT) { + uc_priv->gpio_count = STM32_GPIOS_PER_BANK; + priv->gpio_range = GENMASK(STM32_GPIOS_PER_BANK - 1, 0); + } - res = stm32_gpio_config(&dsc, &ctl); - if (res < 0) - goto out; - res = stm32_gpout_set(&dsc, value); -out: - return res; -} + while (ret != -ENOENT) { + priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1, + args.args[0]); -int gpio_get_value(unsigned gpio) -{ - struct stm32_gpio_dsc dsc; + uc_priv->gpio_count += args.args[2]; - dsc.port = stm32_gpio_to_port(gpio); - dsc.pin = stm32_gpio_to_pin(gpio); + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + ++i, &args); + } - return stm32_gpin_get(&dsc); -} + dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", + (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, + priv->gpio_range); +#endif + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; -int gpio_set_value(unsigned gpio, int value) -{ - struct stm32_gpio_dsc dsc; + ret = clk_enable(&clk); - dsc.port = stm32_gpio_to_port(gpio); - dsc.pin = stm32_gpio_to_pin(gpio); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + debug("clock enabled for device %s\n", dev->name); - return stm32_gpout_set(&dsc, value); + return 0; } + +U_BOOT_DRIVER(gpio_stm32) = { + .name = "gpio_stm32", + .id = UCLASS_GPIO, + .probe = gpio_stm32_probe, +#ifndef CONFIG_SPL_BUILD + .ops = &gpio_stm32_ops, +#endif + .flags = DM_UC_FLAG_SEQ_ALIAS, + .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv), +};