mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
gpio: stm32f7: Add gpio bank holes management
In some STM32 SoC packages, GPIO bank has not always 16 gpios. Several cases can occur, gpio hole can be located at the beginning, middle or end of the gpio bank or a combination of these 3 configurations. For that, gpio bindings offer the gpio-ranges DT property which described the gpio bank mapping. Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
This commit is contained in:
parent
043550415b
commit
dbf928dd26
3 changed files with 92 additions and 14 deletions
|
@ -109,6 +109,9 @@ struct stm32_gpio_regs {
|
||||||
|
|
||||||
struct stm32_gpio_priv {
|
struct stm32_gpio_priv {
|
||||||
struct stm32_gpio_regs *regs;
|
struct stm32_gpio_regs *regs;
|
||||||
|
unsigned int gpio_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int stm32_offset_to_index(struct udevice *dev, unsigned int offset);
|
||||||
|
|
||||||
#endif /* _GPIO_H_ */
|
#endif /* _GPIO_H_ */
|
||||||
|
|
|
@ -110,5 +110,9 @@ struct stm32_gpio_regs {
|
||||||
|
|
||||||
struct stm32_gpio_priv {
|
struct stm32_gpio_priv {
|
||||||
struct stm32_gpio_regs *regs;
|
struct stm32_gpio_regs *regs;
|
||||||
|
unsigned int gpio_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int stm32_offset_to_index(struct udevice *dev, unsigned int offset);
|
||||||
|
|
||||||
#endif /* _STM32_GPIO_H_ */
|
#endif /* _STM32_GPIO_H_ */
|
||||||
|
|
|
@ -20,12 +20,41 @@
|
||||||
#define MODE_BITS_MASK 3
|
#define MODE_BITS_MASK 3
|
||||||
#define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16))
|
#define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_priv *priv = dev_get_priv(dev);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset)
|
static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset)
|
||||||
{
|
{
|
||||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||||
struct stm32_gpio_regs *regs = priv->regs;
|
struct stm32_gpio_regs *regs = priv->regs;
|
||||||
int bits_index = MODE_BITS(offset);
|
int bits_index;
|
||||||
int mask = MODE_BITS_MASK << bits_index;
|
int mask;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
idx = stm32_offset_to_index(dev, offset);
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
bits_index = MODE_BITS(idx);
|
||||||
|
mask = MODE_BITS_MASK << bits_index;
|
||||||
|
|
||||||
clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index);
|
clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index);
|
||||||
|
|
||||||
|
@ -37,12 +66,20 @@ static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset,
|
||||||
{
|
{
|
||||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||||
struct stm32_gpio_regs *regs = priv->regs;
|
struct stm32_gpio_regs *regs = priv->regs;
|
||||||
int bits_index = MODE_BITS(offset);
|
int bits_index;
|
||||||
int mask = MODE_BITS_MASK << bits_index;
|
int mask;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
idx = stm32_offset_to_index(dev, offset);
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
bits_index = MODE_BITS(idx);
|
||||||
|
mask = MODE_BITS_MASK << bits_index;
|
||||||
|
|
||||||
clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
|
clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
|
||||||
|
|
||||||
writel(BSRR_BIT(offset, value), ®s->bsrr);
|
writel(BSRR_BIT(idx, value), ®s->bsrr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -51,16 +88,26 @@ static int stm32_gpio_get_value(struct udevice *dev, unsigned offset)
|
||||||
{
|
{
|
||||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||||
struct stm32_gpio_regs *regs = priv->regs;
|
struct stm32_gpio_regs *regs = priv->regs;
|
||||||
|
int idx;
|
||||||
|
|
||||||
return readl(®s->idr) & BIT(offset) ? 1 : 0;
|
idx = stm32_offset_to_index(dev, offset);
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
return readl(®s->idr) & BIT(idx) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value)
|
static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value)
|
||||||
{
|
{
|
||||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||||
struct stm32_gpio_regs *regs = priv->regs;
|
struct stm32_gpio_regs *regs = priv->regs;
|
||||||
|
int idx;
|
||||||
|
|
||||||
writel(BSRR_BIT(offset, value), ®s->bsrr);
|
idx = stm32_offset_to_index(dev, offset);
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
writel(BSRR_BIT(idx, value), ®s->bsrr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -69,10 +116,18 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset)
|
||||||
{
|
{
|
||||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||||
struct stm32_gpio_regs *regs = priv->regs;
|
struct stm32_gpio_regs *regs = priv->regs;
|
||||||
int bits_index = MODE_BITS(offset);
|
int bits_index;
|
||||||
int mask = MODE_BITS_MASK << bits_index;
|
int mask;
|
||||||
|
int idx;
|
||||||
u32 mode;
|
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;
|
mode = (readl(®s->moder) & mask) >> bits_index;
|
||||||
if (mode == STM32_GPIO_MODE_OUT)
|
if (mode == STM32_GPIO_MODE_OUT)
|
||||||
return GPIOF_OUTPUT;
|
return GPIOF_OUTPUT;
|
||||||
|
@ -96,8 +151,11 @@ static int gpio_stm32_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||||
|
struct ofnode_phandle_args args;
|
||||||
fdt_addr_t addr;
|
fdt_addr_t addr;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
addr = dev_read_addr(dev);
|
addr = dev_read_addr(dev);
|
||||||
if (addr == FDT_ADDR_T_NONE)
|
if (addr == FDT_ADDR_T_NONE)
|
||||||
|
@ -108,14 +166,27 @@ static int gpio_stm32_probe(struct udevice *dev)
|
||||||
if (!name)
|
if (!name)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
uc_priv->bank_name = name;
|
uc_priv->bank_name = name;
|
||||||
uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios",
|
|
||||||
STM32_GPIOS_PER_BANK);
|
i = 0;
|
||||||
debug("%s, addr = 0x%p, bank_name = %s\n", __func__, (u32 *)priv->regs,
|
ret = dev_read_phandle_with_args(dev, "gpio-ranges",
|
||||||
uc_priv->bank_name);
|
NULL, 3, i, &args);
|
||||||
|
|
||||||
|
while (ret != -ENOENT) {
|
||||||
|
priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1,
|
||||||
|
args.args[0]);
|
||||||
|
|
||||||
|
uc_priv->gpio_count += args.args[2];
|
||||||
|
|
||||||
|
ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
|
||||||
|
++i, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
#ifdef CONFIG_CLK
|
#ifdef CONFIG_CLK
|
||||||
struct clk clk;
|
struct clk clk;
|
||||||
int ret;
|
|
||||||
ret = clk_get_by_index(dev, 0, &clk);
|
ret = clk_get_by_index(dev, 0, &clk);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in a new issue