From: Lukasz Majewski <lukma@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3] Add single register pin controller driver
Date: Fri, 10 Mar 2017 05:46:35 +0100 [thread overview]
Message-ID: <20170310054635.1634bf4e@jawa> (raw)
In-Reply-To: <1489118144-1020-1-git-send-email-james@balean.com.au>
On Thu, 9 Mar 2017 21:55:44 -0600
James Balean <james@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@ltec.ch>
> [james at balean.com.au: changed .set_state_simple operation
> to .set_state] Signed-off-by: James Balean <james@balean.com.au>
Reviewed-by: Lukasz Majewski <lukma@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@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
next prev parent reply other threads:[~2017-03-10 4:46 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-10 3:55 [U-Boot] [PATCH v3] Add single register pin controller driver James Balean
2017-03-10 4:46 ` Lukasz Majewski [this message]
2017-03-10 13:07 ` Felix Brack
2017-03-11 11:52 ` James
2017-03-16 22:52 ` Simon Glass
2017-03-19 13:37 ` Felix Brack
2017-03-19 13:39 ` Felix Brack
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170310054635.1634bf4e@jawa \
--to=lukma@denx.de \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.