[U-Boot] [PATCH v3] Add single register pin controller driver

Lukasz Majewski lukma at denx.de
Fri Mar 10 04:46:35 UTC 2017


On Thu,  9 Mar 2017 21:55:44 -0600
James Balean <james at balean.com.au> wrote:

> This patch adds a pin controller driver supporting devices using a
> single configuration register per pin.
> 
> Signed-off-by: Felix Brack <fb at ltec.ch>
> [james at balean.com.au: changed .set_state_simple operation
> to .set_state] Signed-off-by: James Balean <james at balean.com.au>

Reviewed-by: Lukasz Majewski <lukma at denx.de>

> ---
>  drivers/pinctrl/Kconfig          |  10 +++
>  drivers/pinctrl/Makefile         |   1 +
>  drivers/pinctrl/pinctrl-single.c | 141
> +++++++++++++++++++++++++++++++++++++++ 3 files changed, 152
> insertions(+) create mode 100644 drivers/pinctrl/pinctrl-single.c
> 
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index efcb4c0..a2b9212 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -175,6 +175,16 @@ config PIC32_PINCTRL
>  	  by a device tree node which contains both GPIO defintion
> and pin control functions.
>  
> +config PINCTRL_SINGLE
> +	bool "Single register pin-control and pin-multiplex driver"
> +	depends on PINCTRL_FULL || SPL_PINCTRL_FULL
> +	help
> +	  This enables pinctrl driver for systems using a single
> register for
> +	  pin configuration and multiplexing. TI's AM335X SoCs are
> examples of
> +	  such systems.
> +	  Depending on the platform make sure to also enable
> OF_TRANSLATE and
> +	  eventually SPL_OF_TRANSLATE to get correct address
> translations. +
>  endif
>  
>  source "drivers/pinctrl/meson/Kconfig"
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index 512112a..f148f94 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -16,3 +16,4 @@ obj-$(CONFIG_PIC32_PINCTRL)	+=
> pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS)	+= exynos/
>  obj-$(CONFIG_PINCTRL_MESON)	+= meson/
>  obj-$(CONFIG_PINCTRL_MVEBU)	+= mvebu/
> +obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
> diff --git a/drivers/pinctrl/pinctrl-single.c
> b/drivers/pinctrl/pinctrl-single.c new file mode 100644
> index 0000000..a5b4d75
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-single.c
> @@ -0,0 +1,141 @@
> +/*
> + * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack at eets.ch>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <dm/device.h>
> +#include <dm/pinctrl.h>
> +#include <libfdt.h>
> +#include <asm/io.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct single_pdata {
> +	fdt_addr_t base;	/* first configuration register */
> +	int offset;		/* index of last configuration
> register */
> +	u32 mask;		/* configuration-value mask bits */
> +	int width;		/* configuration register bit
> width */ +};
> +
> +struct single_fdt_pin_cfg {
> +	fdt32_t reg;		/* configuration register offset
> */
> +	fdt32_t val;		/* configuration register value
> */ +};
> +
> +/**
> + * single_configure_pins() - Configure pins based on FDT data
> + *
> + * @dev: Pointer to single pin configuration device which is the
> parent of
> + *       the pins node holding the pin configuration data.
> + * @pins: Pointer to the first element of an array of register/value
> pairs
> + *        of type 'struct single_fdt_pin_cfg'. Each such pair
> describes the
> + *        the pin to be configured and the value to be used for
> configuration.
> + *        This pointer points to a 'pinctrl-single,pins' property in
> the
> + *        device-tree.
> + * @size: Size of the 'pins' array in bytes.
> + *        The number of register/value pairs in the 'pins' array
> therefore
> + *        equals to 'size / sizeof(struct single_fdt_pin_cfg)'.
> + */
> +static int single_configure_pins(struct udevice *dev,
> +				 const struct single_fdt_pin_cfg
> *pins,
> +				 int size)
> +{
> +	struct single_pdata *pdata = dev->platdata;
> +	int count = size / sizeof(struct single_fdt_pin_cfg);
> +	int n, reg;
> +	u32 val;
> +
> +	for (n = 0; n < count; n++) {
> +		reg = fdt32_to_cpu(pins->reg);
> +		if ((reg < 0) || (reg > pdata->offset)) {
> +			dev_dbg(dev, "  invalid register offset
> 0x%08x\n", reg);
> +			pins++;
> +			continue;
> +		}
> +		reg += pdata->base;
> +		switch (pdata->width) {
> +		case 32:
> +			val = readl(reg) & ~pdata->mask;
> +			val |= fdt32_to_cpu(pins->val) & pdata->mask;
> +			writel(val, reg);
> +			dev_dbg(dev, "  reg/val 0x%08x/0x%08x\n",
> +				reg, val);
> +			break;
> +		default:
> +			dev_warn(dev, "unsupported register width
> %i\n",
> +				 pdata->width);
> +		}
> +		pins++;
> +	}
> +	return 0;
> +}
> +
> +static int single_set_state(struct udevice *dev, struct udevice
> *config) +{
> +	const void *fdt = gd->fdt_blob;
> +	const struct single_fdt_pin_cfg *prop;
> +	int len;
> +
> +	prop = fdt_getprop(fdt, config->of_offset,
> "pinctrl-single,pins", &len);
> +	if (prop) {
> +		dev_dbg(dev, "configuring pins for %s\n",
> config->name);
> +		if (len % sizeof(struct single_fdt_pin_cfg)) {
> +			dev_dbg(dev, "  invalid pin configuration in
> fdt\n");
> +			return -FDT_ERR_BADSTRUCTURE;
> +		}
> +		single_configure_pins(dev, prop, len);
> +		len = 0;
> +	}
> +
> +	return len;
> +}
> +
> +static int single_ofdata_to_platdata(struct udevice *dev)
> +{
> +	fdt_addr_t addr;
> +	u32 of_reg[2];
> +	int res;
> +	struct single_pdata *pdata = dev->platdata;
> +
> +	pdata->width = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
> +
> "pinctrl-single,register-width", 0); +
> +	res = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
> +				   "reg", of_reg, 2);
> +	if (res)
> +		return res;
> +	pdata->offset = of_reg[1] - pdata->width / 8;
> +
> +	addr = dev_get_addr(dev);
> +	if (addr == FDT_ADDR_T_NONE) {
> +		dev_dbg(dev, "no valid base register address\n");
> +		return -EINVAL;
> +	}
> +	pdata->base = addr;
> +
> +	pdata->mask = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
> +				     "pinctrl-single,function-mask",
> +				     0xffffffff);
> +	return 0;
> +}
> +
> +const struct pinctrl_ops single_pinctrl_ops = {
> +	.set_state = single_set_state,
> +};
> +
> +static const struct udevice_id single_pinctrl_match[] = {
> +	{ .compatible = "pinctrl-single" },
> +	{ /* sentinel */ }
> +};
> +
> +U_BOOT_DRIVER(single_pinctrl) = {
> +	.name = "single-pinctrl",
> +	.id = UCLASS_PINCTRL,
> +	.of_match = single_pinctrl_match,
> +	.ops = &single_pinctrl_ops,
> +	.flags = DM_FLAG_PRE_RELOC,
> +	.platdata_auto_alloc_size = sizeof(struct single_pdata),
> +	.ofdata_to_platdata = single_ofdata_to_platdata,
> +};




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de


More information about the U-Boot mailing list