From: Peng Fan <van.freenix@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH V2 1/2] pinctrl: imx: Introduce pinctrl driver for i.MX6
Date: Mon, 15 Feb 2016 16:33:53 +0800 [thread overview]
Message-ID: <20160215083351.GA15584@linux-7smt.suse> (raw)
In-Reply-To: <1454465168-21060-1-git-send-email-van.freenix@gmail.com>
Hi Simon,
Gentle ping..
Thanks,
Peng.
On Wed, Feb 03, 2016 at 10:06:07AM +0800, Peng Fan wrote:
>Introduce pinctrl for i.MX6
>1. pinctrl-imx.c is for common usage. It's used by i.MX6/7.
>2. Add PINCTRL_IMX PINCTRL_IMX6 Kconfig entry.
>3. To the pinctrl_ops implementation, only set_state is implemented.
> To i.MX6/7, the pinctrl dts entry is as following:
>&iomuxc {
> pinctrl-names = "default";
>
> pinctrl_csi1: csi1grp {
> fsl,pins = <
> MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088
> MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088
> MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088
> >;
> };
>
> [.....]
>};
> there is no property named function or groups. So pinctrl_generic_set_state
> can not be used here.
>5. This driver is a simple implementation for i.mx iomux controller,
> only parse the fsl,pins property and write value to registers.
>6. With DEBUG enabled, we can see log when "i2c bus 0":
> "
> set_state_simple op missing
> imx_pinctrl_set_state: i2c1grp
> mux_reg 0x14c, conf_reg 0x3bc, input_reg 0x5d8, mux_mode 0x0, input_val 0x1, config_val 0x4000007f
> write mux: offset 0x14c val 0x10
> select_input: offset 0x5d8 val 0x1
> write config: offset 0x3bc val 0x7f
> mux_reg 0x148, conf_reg 0x3b8, input_reg 0x5d4, mux_mode 0x0, input_val 0x1, config_val 0x4000007f
> write mux: offset 0x148 val 0x10
> select_input: offset 0x5d4 val 0x1
> write config: offset 0x3b8 val 0x7f
> "
> this means imx6 pinctrl driver works as expected.
>
>Signed-off-by: Peng Fan <van.freenix@gmail.com>
>Reviewed-by: Simon Glass <sjg@chromium.org>
>---
>
>V2:
> Add more details in Kconfig entry
> Use fdt_getprop and fdtdec_get_int_array as suggested by Simon
> Add reviewed-by Simon
> Refer linux binding doc in code.
>
> drivers/pinctrl/Kconfig | 1 +
> drivers/pinctrl/Makefile | 1 +
> drivers/pinctrl/nxp/Kconfig | 16 +++
> drivers/pinctrl/nxp/Makefile | 2 +
> drivers/pinctrl/nxp/pinctrl-imx.c | 241 +++++++++++++++++++++++++++++++++++++
> drivers/pinctrl/nxp/pinctrl-imx.h | 50 ++++++++
> drivers/pinctrl/nxp/pinctrl-imx6.c | 41 +++++++
> 7 files changed, 352 insertions(+)
> create mode 100644 drivers/pinctrl/nxp/Kconfig
> create mode 100644 drivers/pinctrl/nxp/Makefile
> create mode 100644 drivers/pinctrl/nxp/pinctrl-imx.c
> create mode 100644 drivers/pinctrl/nxp/pinctrl-imx.h
> create mode 100644 drivers/pinctrl/nxp/pinctrl-imx6.c
>
>diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
>index 57e6142..9fd8f62 100644
>--- a/drivers/pinctrl/Kconfig
>+++ b/drivers/pinctrl/Kconfig
>@@ -133,6 +133,7 @@ config PINCTRL_SANDBOX
>
> endif
>
>+source "drivers/pinctrl/nxp/Kconfig"
> source "drivers/pinctrl/uniphier/Kconfig"
>
> endmenu
>diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
>index 70d25dc..dcd20bf 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-y += nxp/
> obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
> obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
>
>diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig
>new file mode 100644
>index 0000000..f1c9b92
>--- /dev/null
>+++ b/drivers/pinctrl/nxp/Kconfig
>@@ -0,0 +1,16 @@
>+config PINCTRL_IMX
>+ bool
>+
>+config PINCTRL_IMX6
>+ bool "IMX6 pinctrl driver"
>+ depends on ARCH_MX6 && PINCTRL_FULL
>+ select DEVRES
>+ select PINCTRL_IMX
>+ help
>+ Say Y here to enable the imx6 pinctrl driver
>+
>+ This provides a simple pinctrl driver for i.MX6 SoC familiy,
>+ i.MX6DQ/SL/SX/UL/DQP. This feature depends on device tree
>+ configuration. This driver is different from the linux one,
>+ this is a simple implementation, only parses the 'fsl,pins'
>+ property and configure related registers.
>diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile
>new file mode 100644
>index 0000000..7fd9850
>--- /dev/null
>+++ b/drivers/pinctrl/nxp/Makefile
>@@ -0,0 +1,2 @@
>+obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
>+obj-$(CONFIG_PINCTRL_IMX6) += pinctrl-imx6.o
>diff --git a/drivers/pinctrl/nxp/pinctrl-imx.c b/drivers/pinctrl/nxp/pinctrl-imx.c
>new file mode 100644
>index 0000000..40b0616
>--- /dev/null
>+++ b/drivers/pinctrl/nxp/pinctrl-imx.c
>@@ -0,0 +1,241 @@
>+/*
>+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
>+ *
>+ * SPDX-License-Identifier: GPL-2.0+
>+ */
>+
>+#include <common.h>
>+#include <mapmem.h>
>+#include <linux/io.h>
>+#include <linux/err.h>
>+#include <dm/device.h>
>+#include <dm/pinctrl.h>
>+
>+#include "pinctrl-imx.h"
>+
>+DECLARE_GLOBAL_DATA_PTR;
>+
>+static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
>+{
>+ struct imx_pinctrl_priv *priv = dev_get_priv(dev);
>+ struct imx_pinctrl_soc_info *info = priv->info;
>+ int node = config->of_offset;
>+ const struct fdt_property *prop;
>+ u32 *pin_data;
>+ int npins, size, pin_size;
>+ int mux_reg, conf_reg, input_reg, input_val, mux_mode, config_val;
>+ int i, j = 0;
>+
>+ dev_dbg(dev, "%s: %s\n", __func__, config->name);
>+
>+ if (info->flags & SHARE_MUX_CONF_REG)
>+ pin_size = SHARE_FSL_PIN_SIZE;
>+ else
>+ pin_size = FSL_PIN_SIZE;
>+
>+ prop = fdt_getprop(gd->fdt_blob, node, "fsl,pins", &size);
>+ if (!prop) {
>+ dev_err(dev, "No fsl,pins property in node %s\n", config->name);
>+ return -EINVAL;
>+ }
>+
>+ if (!size || size % pin_size) {
>+ dev_err(dev, "Invalid fsl,pins property in node %s\n",
>+ config->name);
>+ return -EINVAL;
>+ }
>+
>+ pin_data = devm_kzalloc(dev, size, 0);
>+ if (!pin_data)
>+ return -ENOMEM;
>+
>+ if (fdtdec_get_int_array(gd->fdt_blob, node, "fsl,pins",
>+ pin_data, size >> 2)) {
>+ dev_err(dev, "Error reading pin data.\n");
>+ return -EINVAL;
>+ }
>+
>+ npins = size / pin_size;
>+
>+ /*
>+ * Refer to linux documentation for details:
>+ * Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
>+ */
>+ for (i = 0; i < npins; i++) {
>+ mux_reg = pin_data[j++];
>+
>+ if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
>+ mux_reg = -1;
>+
>+ if (info->flags & SHARE_MUX_CONF_REG) {
>+ conf_reg = mux_reg;
>+ } else {
>+ conf_reg = pin_data[j++];
>+ if (!(info->flags & ZERO_OFFSET_VALID) && !conf_reg)
>+ conf_reg = -1;
>+ }
>+
>+ if ((mux_reg == -1) || (conf_reg == -1)) {
>+ dev_err(dev, "Error mux_reg or conf_reg\n");
>+ return -EINVAL;
>+ }
>+
>+ input_reg = pin_data[j++];
>+ mux_mode = pin_data[j++];
>+ input_val = pin_data[j++];
>+ config_val = pin_data[j++];
>+
>+ dev_dbg(dev, "mux_reg 0x%x, conf_reg 0x%x, input_reg 0x%x, "
>+ "mux_mode 0x%x, input_val 0x%x, config_val 0x%x\n",
>+ mux_reg, conf_reg, input_reg, mux_mode, input_val,
>+ config_val);
>+
>+ if (config_val & IMX_PAD_SION)
>+ mux_mode |= IOMUXC_CONFIG_SION;
>+
>+ config_val &= ~IMX_PAD_SION;
>+
>+ /* Set Mux */
>+ if (info->flags & SHARE_MUX_CONF_REG) {
>+ clrsetbits_le32(info->base + mux_reg, 0x7 << 20,
>+ mux_mode << 20);
>+ } else {
>+ writel(mux_mode, info->base + mux_reg);
>+ }
>+
>+ dev_dbg(dev, "write mux: offset 0x%x val 0x%x\n", mux_reg,
>+ mux_mode);
>+
>+ /*
>+ * Set select input
>+ *
>+ * If the select input value begins with 0xff, it's a quirky
>+ * select input and the value should be interpreted as below.
>+ * 31 23 15 7 0
>+ * | 0xff | shift | width | select |
>+ * It's used to work around the problem that the select
>+ * input for some pin is not implemented in the select
>+ * input register but in some general purpose register.
>+ * We encode the select input value, width and shift of
>+ * the bit field into input_val cell of pin function ID
>+ * in device tree, and then decode them here for setting
>+ * up the select input bits in general purpose register.
>+ */
>+
>+ if (input_val >> 24 == 0xff) {
>+ u32 val = input_val;
>+ u8 select = val & 0xff;
>+ u8 width = (val >> 8) & 0xff;
>+ u8 shift = (val >> 16) & 0xff;
>+ u32 mask = ((1 << width) - 1) << shift;
>+ /*
>+ * The input_reg[i] here is actually some IOMUXC general
>+ * purpose register, not regular select input register.
>+ */
>+ val = readl(info->base + input_reg);
>+ val &= ~mask;
>+ val |= select << shift;
>+ writel(val, info->base + input_reg);
>+ } else if (input_reg) {
>+ /*
>+ * Regular select input register can never be at offset
>+ * 0, and we only print register value for regular case.
>+ */
>+ if (info->input_sel_base)
>+ writel(input_val, info->input_sel_base +
>+ input_reg);
>+ else
>+ writel(input_val, info->base + input_reg);
>+
>+ dev_dbg(dev, "select_input: offset 0x%x val 0x%x\n",
>+ input_reg, input_val);
>+ }
>+
>+ /* Set config */
>+ if (!(config_val & IMX_NO_PAD_CTL)) {
>+ if (info->flags & SHARE_MUX_CONF_REG) {
>+ clrsetbits_le32(info->base + conf_reg, 0xffff,
>+ config_val);
>+ } else {
>+ writel(config_val, info->base + conf_reg);
>+ }
>+
>+ dev_dbg(dev, "write config: offset 0x%x val 0x%x\n",
>+ conf_reg, config_val);
>+ }
>+ }
>+
>+ return 0;
>+}
>+
>+const struct pinctrl_ops imx_pinctrl_ops = {
>+ .set_state = imx_pinctrl_set_state,
>+};
>+
>+int imx_pinctrl_probe(struct udevice *dev,
>+ struct imx_pinctrl_soc_info *info)
>+{
>+ struct imx_pinctrl_priv *priv = dev_get_priv(dev);
>+ int node = dev->of_offset, ret;
>+ struct fdtdec_phandle_args arg;
>+ fdt_addr_t addr;
>+ fdt_size_t size;
>+
>+ if (!info) {
>+ dev_err(dev, "wrong pinctrl info\n");
>+ return -EINVAL;
>+ }
>+
>+ priv->dev = dev;
>+ priv->info = info;
>+
>+ addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
>+
>+ if (addr == FDT_ADDR_T_NONE)
>+ return -EINVAL;
>+
>+ info->base = map_sysmem(addr, size);
>+ if (!info->base)
>+ return -ENOMEM;
>+ priv->info = info;
>+
>+ /*
>+ * Refer to linux documentation for details:
>+ * Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt
>+ */
>+ if (fdtdec_get_bool(gd->fdt_blob, node, "fsl,input-sel")) {
>+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
>+ node, "fsl,input-sel",
>+ NULL, 0, 0, &arg);
>+ if (ret) {
>+ dev_err(dev, "iomuxc fsl,input-sel property not found\n");
>+ return -EINVAL;
>+ }
>+
>+ addr = fdtdec_get_addr_size(gd->fdt_blob, arg.node, "reg",
>+ &size);
>+ if (addr == FDT_ADDR_T_NONE)
>+ return -EINVAL;
>+
>+ info->input_sel_base = map_sysmem(addr, size);
>+ if (!info->input_sel_base)
>+ return -ENOMEM;
>+ }
>+
>+ dev_info(dev, "initialized IMX pinctrl driver\n");
>+
>+ return 0;
>+}
>+
>+int imx_pinctrl_remove(struct udevice *dev)
>+{
>+ struct imx_pinctrl_priv *priv = dev_get_priv(dev);
>+ struct imx_pinctrl_soc_info *info = priv->info;
>+
>+ if (info->input_sel_base)
>+ unmap_sysmem(info->input_sel_base);
>+ if (info->base)
>+ unmap_sysmem(info->base);
>+
>+ return 0;
>+}
>diff --git a/drivers/pinctrl/nxp/pinctrl-imx.h b/drivers/pinctrl/nxp/pinctrl-imx.h
>new file mode 100644
>index 0000000..037c491
>--- /dev/null
>+++ b/drivers/pinctrl/nxp/pinctrl-imx.h
>@@ -0,0 +1,50 @@
>+/*
>+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
>+ *
>+ * SPDX-License-Identifier: GPL-2.0+
>+ */
>+
>+#ifndef __DRIVERS_PINCTRL_IMX_H
>+#define __DRIVERS_PINCTRL_IMX_H
>+
>+/**
>+ * @base: the address to the controller in virtual memory
>+ * @input_sel_base: the address of the select input in virtual memory.
>+ * @flags: flags specific for each soc
>+ */
>+struct imx_pinctrl_soc_info {
>+ void __iomem *base;
>+ void __iomem *input_sel_base;
>+ unsigned int flags;
>+};
>+
>+/**
>+ * @dev: a pointer back to containing device
>+ * @info: the soc info
>+ */
>+struct imx_pinctrl_priv {
>+ struct udevice *dev;
>+ struct imx_pinctrl_soc_info *info;
>+};
>+
>+extern const struct pinctrl_ops imx_pinctrl_ops;
>+
>+#define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */
>+#define IMX_PAD_SION 0x40000000 /* set SION */
>+
>+/*
>+ * Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
>+ * 1 u32 CONFIG, so 24 types in total for each pin.
>+ */
>+#define FSL_PIN_SIZE 24
>+#define SHARE_FSL_PIN_SIZE 20
>+
>+#define SHARE_MUX_CONF_REG 0x1
>+#define ZERO_OFFSET_VALID 0x2
>+
>+#define IOMUXC_CONFIG_SION (0x1 << 4)
>+
>+int imx_pinctrl_probe(struct udevice *dev, struct imx_pinctrl_soc_info *info);
>+
>+int imx_pinctrl_remove(struct udevice *dev);
>+#endif /* __DRIVERS_PINCTRL_IMX_H */
>diff --git a/drivers/pinctrl/nxp/pinctrl-imx6.c b/drivers/pinctrl/nxp/pinctrl-imx6.c
>new file mode 100644
>index 0000000..24f139e
>--- /dev/null
>+++ b/drivers/pinctrl/nxp/pinctrl-imx6.c
>@@ -0,0 +1,41 @@
>+
>+/*
>+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
>+ *
>+ * SPDX-License-Identifier: GPL-2.0+
>+ */
>+
>+#include <dm/device.h>
>+#include <dm/pinctrl.h>
>+
>+#include "pinctrl-imx.h"
>+
>+static struct imx_pinctrl_soc_info imx6_pinctrl_soc_info;
>+
>+static int imx6_pinctrl_probe(struct udevice *dev)
>+{
>+ struct imx_pinctrl_soc_info *info =
>+ (struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
>+
>+ return imx_pinctrl_probe(dev, info);
>+}
>+
>+static const struct udevice_id imx6_pinctrl_match[] = {
>+ { .compatible = "fsl,imx6q-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
>+ { .compatible = "fsl,imx6dl-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
>+ { .compatible = "fsl,imx6sl-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
>+ { .compatible = "fsl,imx6sx-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
>+ { .compatible = "fsl,imx6ul-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
>+ { /* sentinel */ }
>+};
>+
>+U_BOOT_DRIVER(imx6_pinctrl) = {
>+ .name = "imx6-pinctrl",
>+ .id = UCLASS_PINCTRL,
>+ .of_match = of_match_ptr(imx6_pinctrl_match),
>+ .probe = imx6_pinctrl_probe,
>+ .remove = imx_pinctrl_remove,
>+ .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
>+ .ops = &imx_pinctrl_ops,
>+ .flags = DM_FLAG_PRE_RELOC,
>+};
>--
>2.6.2
>
next prev parent reply other threads:[~2016-02-15 8:33 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-03 2:06 [U-Boot] [PATCH V2 1/2] pinctrl: imx: Introduce pinctrl driver for i.MX6 Peng Fan
2016-02-03 2:06 ` [U-Boot] [PATCH V2 2/2] pinctrl: imx: Support i.MX7D Peng Fan
2016-02-15 8:33 ` Peng Fan [this message]
2016-02-16 16:00 ` [U-Boot] [PATCH V2 1/2] pinctrl: imx: Introduce pinctrl driver for i.MX6 Simon Glass
2016-02-17 2:45 ` Peng Fan
2016-02-17 2:50 ` Simon Glass
2016-02-17 5:23 ` Peng Fan
2016-02-21 10:24 ` Stefano Babic
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=20160215083351.GA15584@linux-7smt.suse \
--to=van.freenix@gmail.com \
--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.