[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