[U-Boot] [PATCH 06/23] dm: sunxi: Modify the GPIO driver to support driver model

Chen-Yu Tsai wens at csie.org
Sun Oct 5 04:07:03 CEST 2014


Hi,

On Sun, Oct 5, 2014 at 1:29 AM, Simon Glass <sjg at chromium.org> wrote:
> This adds driver model support to the sunxi GPIO driver, using the device
> tree to trigger binding of the driver. The driver will still operate
> without driver model too.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
>  drivers/gpio/sunxi_gpio.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++
>  include/configs/sun7i.h   |   1 +
>  2 files changed, 171 insertions(+)
>
> diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
> index 0c50a8f..f633c04 100644
> --- a/drivers/gpio/sunxi_gpio.c
> +++ b/drivers/gpio/sunxi_gpio.c
> @@ -11,9 +11,25 @@
>   */
>
>  #include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <fdtdec.h>
> +#include <malloc.h>
>  #include <asm/io.h>
>  #include <asm/gpio.h>
> +#include <dm/device-internal.h>
>
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define SUNXI_GPIOS_PER_PORT   SUNXI_GPIO_A_NR
> +
> +struct sunxi_gpio_platdata {
> +       struct sunxi_gpio *regs;
> +       const char *bank_name;  /* Name of port, e.g. "B" */
> +       int gpio_count;
> +};
> +
> +#ifndef CONFIG_DM_GPIO
>  static int sunxi_gpio_output(u32 pin, u32 val)
>  {
>         u32 dat;
> @@ -100,3 +116,157 @@ int sunxi_name_to_gpio(const char *name)
>                 return -1;
>         return group * 32 + pin;
>  }
> +#endif
> +
> +#ifdef CONFIG_DM_GPIO
> +static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
> +{
> +       struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
> +
> +       sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
> +
> +       return 0;
> +}
> +
> +static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
> +                                      int value)
> +{
> +       struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
> +       u32 num = GPIO_NUM(offset);
> +
> +       sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
> +       clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
> +
> +       return 0;
> +}
> +
> +static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
> +{
> +       struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
> +       u32 num = GPIO_NUM(offset);
> +       unsigned dat;
> +
> +       dat = readl(&plat->regs->dat);
> +       dat >>= num;
> +
> +       return dat & 0x1;
> +}
> +
> +static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
> +                               int value)
> +{
> +       struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
> +       u32 num = GPIO_NUM(offset);
> +
> +       clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
> +       return 0;
> +}
> +
> +static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
> +{
> +       struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
> +       int func;
> +
> +       func = sunxi_gpio_get_cfgbank(plat->regs, offset);
> +       if (func == SUNXI_GPIO_OUTPUT)
> +               return GPIOF_OUTPUT;
> +       else if (func == SUNXI_GPIO_INPUT)
> +               return GPIOF_INPUT;
> +       else
> +               return GPIOF_FUNC;
> +}
> +
> +static const struct dm_gpio_ops gpio_sunxi_ops = {
> +       .direction_input        = sunxi_gpio_direction_input,
> +       .direction_output       = sunxi_gpio_direction_output,
> +       .get_value              = sunxi_gpio_get_value,
> +       .set_value              = sunxi_gpio_set_value,
> +       .get_function           = sunxi_gpio_get_function,
> +};
> +
> +/**
> + * Returns the name of a GPIO bank
> + *
> + * GPIO banks are named A, B, C, ...
> + *
> + * @bank:      Bank number (0, 1..n-1)
> + * @return allocated string containing the name
> + */
> +static char *gpio_bank_name(int bank)
> +{
> +       char *name;
> +
> +       name = malloc(2);
> +       if (name) {
> +               name[0] = 'A' + bank;
> +               name[1] = '\0';
> +       }
> +
> +       return name;
> +}
> +
> +static int gpio_sunxi_probe(struct udevice *dev)
> +{
> +       struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
> +       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
> +
> +       /* Tell the uclass how many GPIOs we have */
> +       if (plat) {
> +               uc_priv->gpio_count = plat->gpio_count;
> +               uc_priv->bank_name = plat->bank_name;
> +       }
> +
> +       return 0;
> +}
> +/**
> + * We have a top-level GPIO device with no actual GPIOs. It has a child
> + * device for each Tegra port.

Might we get rid of references to Tegra?

> + */
> +static int gpio_sunxi_bind(struct udevice *parent)
> +{
> +       struct sunxi_gpio_platdata *plat = parent->platdata;
> +       struct sunxi_gpio_reg *ctlr;
> +       int bank;
> +       int ret;
> +
> +       /* If this is a child device, there is nothing to do here */
> +       if (plat)
> +               return 0;
> +
> +       ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
> +                                                  parent->of_offset, "reg");
> +       for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
> +               struct sunxi_gpio_platdata *plat;
> +               struct udevice *dev;
> +
> +               plat = calloc(1, sizeof(*plat));
> +               if (!plat)
> +                       return -ENOMEM;
> +               plat->regs = &ctlr->gpio_bank[bank];
> +               plat->bank_name = gpio_bank_name(bank);
> +               plat->gpio_count = SUNXI_GPIOS_PER_PORT;
> +
> +               ret = device_bind(parent, parent->driver,
> +                                       plat->bank_name, plat, -1, &dev);
> +               if (ret)
> +                       return ret;
> +               dev->of_offset = parent->of_offset;
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct udevice_id exynos_gpio_ids[] = {

And Exynos?

> +       { .compatible = "allwinner,sun7i-a20-pinctrl" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(gpio_sunxi) = {
> +       .name   = "gpio_sunxi",
> +       .id     = UCLASS_GPIO,
> +       .ops    = &gpio_sunxi_ops,
> +       .of_match = exynos_gpio_ids,
> +       .bind   = gpio_sunxi_bind,
> +       .probe  = gpio_sunxi_probe,
> +};
> +#endif
> diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h
> index 500d0e3..2314e97 100644
> --- a/include/configs/sun7i.h
> +++ b/include/configs/sun7i.h
> @@ -38,6 +38,7 @@
>
>  #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_DM)
>  # define CONFIG_CMD_DM
> +# define CONFIG_DM_GPIO
>  #endif
>
>  /*
> --


ChenYu


More information about the U-Boot mailing list