Hi Wenyou, On 7 June 2016 at 01:24, Wenyou Yang <wenyou.y...@atmel.com> wrote: > AT91 PIO4 controller is a combined gpio-controller, pin-mux and > pin-config module. The peripheral's pins are assigned through > per-pin based muxing logic. > > The pin configuration is performed on specific registers which > are shared along with the gpio controller. So regard the pinctrl > device as a child of atmel_pio4 device. > > Signed-off-by: Wenyou Yang <wenyou.y...@atmel.com> > --- > > Changes in v4: None > Changes in v3: > - Rework due to the pinctrl device is regarded as atmel_pio4 > device's child. > > Changes in v2: > - remove meaningless comment. > - add else path for argument of pinconf. > - add inline attribute for atmel_pio4_bank_base(). > - add handle if the pinmux entries is greater maximum value. > > drivers/pinctrl/Kconfig | 7 ++ > drivers/pinctrl/Makefile | 1 + > drivers/pinctrl/pinctrl-at91-pio4.c | 185 > ++++++++++++++++++++++++++++++++++++ > 3 files changed, 193 insertions(+) > create mode 100644 drivers/pinctrl/pinctrl-at91-pio4.c
Reviewed-by: Simon Glass <s...@chromium.org> With one nit below. > > diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig > index 567b766..68ecfbb 100644 > --- a/drivers/pinctrl/Kconfig > +++ b/drivers/pinctrl/Kconfig > @@ -123,6 +123,13 @@ config QCA953X_PINCTRL > both the GPIO definitions and pin control functions for each > available multiplex function. > > +config PINCTRL_AT91PIO4 > + bool "AT91 PIO4 pinctrl driver" > + depends on DM > + help > + This option is to enable the AT91 pinctrl driver for AT91 PIO4 > + controller which is available on SAMA5D2 SoC. > + > config ROCKCHIP_PINCTRL > bool "Rockchip pin control driver" > depends on DM > diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile > index b99ed2f..4df10a4 100644 > --- a/drivers/pinctrl/Makefile > +++ b/drivers/pinctrl/Makefile > @@ -5,6 +5,7 @@ > obj-y += pinctrl-uclass.o > obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o > > +obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o > obj-y += nxp/ > obj-$(CONFIG_ARCH_ATH79) += ath79/ > obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ > diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c > b/drivers/pinctrl/pinctrl-at91-pio4.c > new file mode 100644 > index 0000000..ed63f68 > --- /dev/null > +++ b/drivers/pinctrl/pinctrl-at91-pio4.c > @@ -0,0 +1,185 @@ > +/* > + * Atmel PIO4 pinctrl driver > + * > + * Copyright (C) 2016 Atmel Corporation > + * Wenyou.Yang <wenyou.y...@atmel.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <dm/device.h> > +#include <dm/pinctrl.h> > +#include <linux/io.h> > +#include <linux/err.h> > +#include <mach/atmel_pio4.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +/* > + * Warning: > + * In order to not introduce confusion between Atmel PIO groups and pinctrl > + * framework groups, Atmel PIO groups will be called banks. > + */ > + > +struct atmel_pio4_platdata { > + struct atmel_pio4_port *reg_base; > +}; > + > +static const struct pinconf_param conf_params[] = { > + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, > + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, > + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, > + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, > + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, > + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, > + { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, > +}; > + > +static u32 atmel_pinctrl_get_pinconf(const void *blob, int node) > +{ > + const struct pinconf_param *params; > + u32 param, arg, conf = 0; > + u32 i; > + > + for (i = 0; i < ARRAY_SIZE(conf_params); i++) { > + params = &conf_params[i]; > + if (!fdt_get_property(blob, node, params->property, NULL)) > + continue; > + > + param = params->param; > + arg = params->default_value; > + > + switch (param) { > + case PIN_CONFIG_BIAS_DISABLE: > + conf &= (~ATMEL_PIO_PUEN_MASK); > + conf &= (~ATMEL_PIO_PDEN_MASK); > + break; > + case PIN_CONFIG_BIAS_PULL_UP: > + conf |= ATMEL_PIO_PUEN_MASK; > + break; > + case PIN_CONFIG_BIAS_PULL_DOWN: > + conf |= ATMEL_PIO_PDEN_MASK; > + break; > + case PIN_CONFIG_DRIVE_OPEN_DRAIN: > + if (arg == 0) > + conf &= (~ATMEL_PIO_OPD_MASK); > + else > + conf |= ATMEL_PIO_OPD_MASK; > + break; > + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: > + if (arg == 0) > + conf |= ATMEL_PIO_SCHMITT_MASK; > + else > + conf &= (~ATMEL_PIO_SCHMITT_MASK); > + break; > + case PIN_CONFIG_INPUT_DEBOUNCE: > + if (arg == 0) { > + conf &= (~ATMEL_PIO_IFEN_MASK); > + conf &= (~ATMEL_PIO_IFSCEN_MASK); > + } else { > + conf |= ATMEL_PIO_IFEN_MASK; > + conf |= ATMEL_PIO_IFSCEN_MASK; > + } > + break; > + default: > + printf("%s: Unsupported configuration parameter: > %u\n", > + __func__, param); > + break; > + } > + } > + > + return conf; > +} > + > +static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice > *dev, > + u32 bank) > +{ > + struct atmel_pio4_platdata *plat = dev_get_platdata(dev); > + struct atmel_pio4_port *bank_base = > + (struct atmel_pio4_port *)((u32)plat->reg_base + > + ATMEL_PIO_BANK_OFFSET * bank); > + > + return bank_base; > +} > + > +#define MAX_PINMUX_ENTRIES 40 > + > +static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice > *config) > +{ > + struct atmel_pio4_port *bank_base; > + const void *blob = gd->fdt_blob; > + int node = config->of_offset; > + u32 offset, func, bank, line; > + u32 cells[MAX_PINMUX_ENTRIES]; > + u32 i, conf; > + int count; > + > + conf = atmel_pinctrl_get_pinconf(blob, node); > + > + count = fdtdec_get_int_array_count(blob, node, "pinmux", > + cells, ARRAY_SIZE(cells)); > + if (count < 0) { > + printf("%s: bad pinmux array %d\n", __func__, count); > + return -EINVAL; > + } > + > + if (count > MAX_PINMUX_ENTRIES) { > + printf("%s: unsupported pinmux array count %d\n", > + __func__, count); > + return -EINVAL; > + } > + > + for (i = 0 ; i < count; i++) { > + offset = ATMEL_GET_PIN_NO(cells[i]); > + func = ATMEL_GET_PIN_FUNC(cells[i]); > + > + bank = ATMEL_PIO_BANK(offset); > + line = ATMEL_PIO_LINE(offset); > + > + bank_base = atmel_pio4_bank_base(dev, bank); > + > + writel(BIT(line), &bank_base->mskr); > + conf &= (~ATMEL_PIO_CFGR_FUNC_MASK); > + conf |= (func & ATMEL_PIO_CFGR_FUNC_MASK); > + writel(conf, &bank_base->cfgr); > + } > + > + return 0; > +} > + > +const struct pinctrl_ops atmel_pinctrl_ops = { > + .set_state = atmel_pinctrl_set_state, > +}; > + > +static int atmel_pinctrl_probe(struct udevice *dev) > +{ > + struct atmel_pio4_platdata *plat = dev_get_platdata(dev); > + fdt_addr_t addr_base; > + > + dev = dev_get_parent(dev); > + if (!dev) > + return -EINVAL; > + > + addr_base = dev_get_addr(dev); > + if (addr_base == FDT_ADDR_T_NONE) > + return -ENODEV; -EINVAL > + > + plat->reg_base = (struct atmel_pio4_port *)addr_base; > + > + return 0; > +} > + > +static const struct udevice_id atmel_pinctrl_match[] = { > + { .compatible = "atmel,sama5d2-pinctrl" }, > + {} > +}; > + > +U_BOOT_DRIVER(atmel_pinctrl) = { > + .name = "pinctrl_atmel_pio4", > + .id = UCLASS_PINCTRL, > + .of_match = atmel_pinctrl_match, > + .probe = atmel_pinctrl_probe, > + .platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata), > + .ops = &atmel_pinctrl_ops, > +}; > -- > 2.7.4 > Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot