On 27/12/2016 11:04, Peng Fan wrote: > Add the imx_rgpio2p driver for Rapid GPIO2P controllers on i.MX7ULP. > Have added all ports on RGPIO2P_0 and RGPIO2P_1. > > The configurations CONFIG_IMX_RGPIO2P and CONFIG_DM_GPIO must be set > to y to enable the drivers. > > To use the GPIO function, the IBE and OBE needs to set in IOMUXC. > We did not set the bits in driver, but leave them to IOMUXC settings > of the GPIO pins. User should use IMX_GPIO_NR to generate the GPIO number > for gpio APIs access. > > Signed-off-by: Peng Fan <[email protected]> > Signed-off-by: Ye Li <[email protected]> > Cc: Stefano Babic <[email protected]> > --- > > V2: > None > > arch/arm/include/asm/arch-mx7ulp/gpio.h | 22 ++++ > drivers/gpio/Kconfig | 7 + > drivers/gpio/Makefile | 1 + > drivers/gpio/imx_rgpio2p.c | 224 > ++++++++++++++++++++++++++++++++ > 4 files changed, 254 insertions(+) > create mode 100644 arch/arm/include/asm/arch-mx7ulp/gpio.h > create mode 100644 drivers/gpio/imx_rgpio2p.c > > diff --git a/arch/arm/include/asm/arch-mx7ulp/gpio.h > b/arch/arm/include/asm/arch-mx7ulp/gpio.h > new file mode 100644 > index 0000000..fe41101 > --- /dev/null > +++ b/arch/arm/include/asm/arch-mx7ulp/gpio.h > @@ -0,0 +1,22 @@ > +/* > + * Copyright (C) 2016 Freescale Semiconductor, Inc. > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef __ASM_ARCH_MX7ULP_GPIO_H > +#define __ASM_ARCH_MX7ULP_GPIO_H > + > +struct gpio_regs { > + u32 gpio_pdor; > + u32 gpio_psor; > + u32 gpio_pcor; > + u32 gpio_ptor; > + u32 gpio_pdir; > + u32 gpio_pddr; > + u32 gpio_gacr; > +}; > + > +#define IMX_GPIO_NR(port, index) ((((port)-1)*32)+((index)&31)) > + > +#endif /* __ASM_ARCH_MX7ULP_GPIO_H */ > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index 8d9ab52..dc4108f 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -48,6 +48,13 @@ config INTEL_BROADWELL_GPIO > driver from the common Intel ICH6 driver. It supports a total of > 95 GPIOs which can be configured from the device tree. > > +config IMX_RGPIO2P > + bool "i.MX7ULP RGPIO2P driver" > + depends on DM > + default n > + help > + This driver supports i.MX7ULP Rapid GPIO2P controller. > + > config LPC32XX_GPIO > bool "LPC32XX GPIO driver" > depends on DM > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index 8939226..27f8068 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -53,6 +53,7 @@ obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o > obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o > obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o > obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o > +obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o > obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o > obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o > obj-$(CONFIG_MSM_GPIO) += msm_gpio.o > diff --git a/drivers/gpio/imx_rgpio2p.c b/drivers/gpio/imx_rgpio2p.c > new file mode 100644 > index 0000000..886b161 > --- /dev/null > +++ b/drivers/gpio/imx_rgpio2p.c > @@ -0,0 +1,224 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * RGPIO2P driver for the Freescale i.MX7ULP. > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <errno.h> > +#include <fdtdec.h> > +#include <asm/gpio.h> > +#include <asm/io.h> > +#include <malloc.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +enum imx_rgpio2p_direction { > + IMX_RGPIO2P_DIRECTION_IN, > + IMX_RGPIO2P_DIRECTION_OUT, > +}; > + > +#define GPIO_PER_BANK 32 > + > +struct imx_rgpio2p_data { > + struct gpio_regs *regs; > +}; > + > +struct imx_rgpio2p_plat { > + int bank_index; > + struct gpio_regs *regs; > +}; > + > +static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset) > +{ > + u32 val; > + > + val = readl(®s->gpio_pddr); > + > + return val & (1 << offset) ? 1 : 0; > +} > + > +static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset, > + enum imx_rgpio2p_direction direction) > +{ > + u32 l; > + > + l = readl(®s->gpio_pddr); > + > + switch (direction) { > + case IMX_RGPIO2P_DIRECTION_OUT: > + l |= 1 << offset; > + break; > + case IMX_RGPIO2P_DIRECTION_IN: > + l &= ~(1 << offset); > + } > + writel(l, ®s->gpio_pddr); > +} > + > +static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset, > + int value) > +{ > + if (value) > + writel((1 << offset), ®s->gpio_psor); > + else > + writel((1 << offset), ®s->gpio_pcor); > +} > + > +static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset) > +{ > + return (readl(®s->gpio_pdir) >> offset) & 0x01; > +} > + > +static int imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset) > +{ > + struct imx_rgpio2p_data *bank = dev_get_priv(dev); > + > + /* Configure GPIO direction as input. */ > + imx_rgpio2p_bank_direction(bank->regs, offset, > IMX_RGPIO2P_DIRECTION_IN); > + > + return 0; > +} > + > +static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset, > + int value) > +{ > + struct imx_rgpio2p_data *bank = dev_get_priv(dev); > + > + /* Configure GPIO output value. */ > + imx_rgpio2p_bank_set_value(bank->regs, offset, value); > + > + /* Configure GPIO direction as output. */ > + imx_rgpio2p_bank_direction(bank->regs, offset, > IMX_RGPIO2P_DIRECTION_OUT); > + > + return 0; > +} > + > +static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset) > +{ > + struct imx_rgpio2p_data *bank = dev_get_priv(dev); > + > + return imx_rgpio2p_bank_get_value(bank->regs, offset); > +} > + > +static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset, > + int value) > +{ > + struct imx_rgpio2p_data *bank = dev_get_priv(dev); > + > + imx_rgpio2p_bank_set_value(bank->regs, offset, value); > + > + return 0; > +} > + > +static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset) > +{ > + struct imx_rgpio2p_data *bank = dev_get_priv(dev); > + > + /* GPIOF_FUNC is not implemented yet */ > + if (imx_rgpio2p_is_output(bank->regs, offset)) > + return GPIOF_OUTPUT; > + else > + return GPIOF_INPUT; > +} > + > +static const struct dm_gpio_ops imx_rgpio2p_ops = { > + .direction_input = imx_rgpio2p_direction_input, > + .direction_output = imx_rgpio2p_direction_output, > + .get_value = imx_rgpio2p_get_value, > + .set_value = imx_rgpio2p_set_value, > + .get_function = imx_rgpio2p_get_function, > +}; > + > +static int imx_rgpio2p_probe(struct udevice *dev) > +{ > + struct imx_rgpio2p_data *bank = dev_get_priv(dev); > + struct imx_rgpio2p_plat *plat = dev_get_platdata(dev); > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > + int banknum; > + char name[18], *str; > + > + banknum = plat->bank_index; > + sprintf(name, "GPIO%d_", banknum + 1); > + str = strdup(name); > + if (!str) > + return -ENOMEM; > + uc_priv->bank_name = str; > + uc_priv->gpio_count = GPIO_PER_BANK; > + bank->regs = plat->regs; > + > + return 0; > +} > + > +static int imx_rgpio2p_bind(struct udevice *dev) > +{ > + struct imx_rgpio2p_plat *plat = dev->platdata; > + fdt_addr_t addr; > + > + /* > + * If platdata already exsits, directly return. > + * Actually only when DT is not supported, platdata > + * is statically initialized in U_BOOT_DEVICES.Here > + * will return. > + */ > + if (plat) > + return 0; > + > + addr = dev_get_addr_index(dev, 1); > + if (addr == FDT_ADDR_T_NONE) > + return -ENODEV; > + > + /* > + * TODO: > + * When every board is converted to driver model and DT is supported, > + * this can be done by auto-alloc feature, but not using calloc > + * to alloc memory for platdata. > + */ > + plat = calloc(1, sizeof(*plat)); > + if (!plat) > + return -ENOMEM; > + > + plat->regs = (struct gpio_regs *)addr; > + plat->bank_index = dev->req_seq; > + dev->platdata = plat; > + > + return 0; > +} > + > + > +static const struct udevice_id imx_rgpio2p_ids[] = { > + { .compatible = "fsl,imx7ulp-gpio" }, > + { } > +}; > + > +U_BOOT_DRIVER(imx_rgpio2p) = { > + .name = "imx_rgpio2p", > + .id = UCLASS_GPIO, > + .ops = &imx_rgpio2p_ops, > + .probe = imx_rgpio2p_probe, > + .priv_auto_alloc_size = sizeof(struct imx_rgpio2p_plat), > + .of_match = imx_rgpio2p_ids, > + .bind = imx_rgpio2p_bind, > +}; > + > +#if !CONFIG_IS_ENABLED(OF_CONTROL) > +static const struct imx_rgpio2p_plat imx_plat[] = { > + { 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR }, > + { 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR }, > + { 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR }, > + { 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR }, > + { 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR }, > + { 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR }, > +}; > + > +U_BOOT_DEVICES(imx_rgpio2ps) = { > + { "imx_rgpio2p", &imx_plat[0] }, > + { "imx_rgpio2p", &imx_plat[1] }, > + { "imx_rgpio2p", &imx_plat[2] }, > + { "imx_rgpio2p", &imx_plat[3] }, > + { "imx_rgpio2p", &imx_plat[4] }, > + { "imx_rgpio2p", &imx_plat[5] }, > +}; > +#endif >
Reviewed-by : Stefano Babic <[email protected]> Best regards, Stefano Babic -- ===================================================================== DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: [email protected] ===================================================================== _______________________________________________ U-Boot mailing list [email protected] http://lists.denx.de/mailman/listinfo/u-boot

