Currently most code to get child number in kernel are almost same,
add a helper to implement this function for dt to use.
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Grant Likely <grant....@secretlab.ca>
Cc: Rob Herring <rob.h...@calxeda.com>
---
include/linux/of.h | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/include/linux/of.h b/include/linux/of.h
index 4948552..09d53dc 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -189,6 +189,18 @@ extern struct device_node *of_get_next_child(const struct device_node *node,
for (child = of_get_next_child(parent, NULL); child != NULL; \
child = of_get_next_child(parent, child))
+static inline int of_get_child_number(struct device_node *np)
+
+{
+ struct device_node *child = NULL;
+ int num = 0;
+
+ while((child = of_get_next_child(np, child)))
+ num++;
+
+ return num;
+}
+
extern struct device_node *of_find_node_with_property(
struct device_node *from, const char *prop_name);
#define for_each_node_with_property(dn, prop_name) \
@@ -262,6 +274,11 @@ static inline bool of_have_populated_dt(void)
#define for_each_child_of_node(parent, child) \
while (0)
+static inline int of_get_child_number(struct device_node *np)
+{
+ return -ENOSYS;
+}
+
static inline int of_device_is_compatible(const struct device_node *device,
const char *name)
{
--
1.7.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Linus Walleij <linus....@linaro.org>
Cc: Sascha Hauer <s.h...@pengutronix.de>
Cc: Shawn Guo <shan...@freescale.com>
---
drivers/pinctrl/Kconfig | 20 ++
drivers/pinctrl/Makefile | 3 +
drivers/pinctrl/pinmux-imx-core.c | 435 ++++++++++++++++++++++++++++++++++++
drivers/pinctrl/pinmux-imx-core.h | 86 +++++++
drivers/pinctrl/pinmux-imx53.c | 443 +++++++++++++++++++++++++++++++++++++
drivers/pinctrl/pinmux-imx6q.c | 433 ++++++++++++++++++++++++++++++++++++
6 files changed, 1420 insertions(+), 0 deletions(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index e17e2f8..268c212 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -20,6 +20,26 @@ config DEBUG_PINCTRL
help
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+config PINMUX_IMX
+ bool "Freescale IMX core pinmux driver"
+ depends on ARCH_MXC
+
+config PINMUX_IMX53
+ bool "IMX53 pinmux driver"
+ depends on ARCH_MX5
+ select PINMUX
+ select PINMUX_IMX
+ help
+ Say Y here to enable the imx6q pinmux driver
+
+config PINMUX_IMX6Q
+ bool "IMX6Q pinmux driver"
+ depends on SOC_IMX6Q
+ select PINMUX
+ select PINMUX_IMX
+ help
+ Say Y here to enable the imx6q pinmux driver
+
config PINMUX_SIRF
bool "CSR SiRFprimaII pinmux driver"
depends on ARCH_PRIMA2
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index bdc548a..a9bca9f 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -4,5 +4,8 @@ ccflags-$(CONFIG_DEBUG_PINMUX) += -DDEBUG
obj-$(CONFIG_PINCTRL) += core.o
obj-$(CONFIG_PINMUX) += pinmux.o
+obj-$(CONFIG_PINMUX_IMX) += pinmux-imx-core.o
+obj-$(CONFIG_PINMUX_IMX53) += pinmux-imx53.o
+obj-$(CONFIG_PINMUX_IMX6Q) += pinmux-imx6q.o
obj-$(CONFIG_PINMUX_SIRF) += pinmux-sirf.o
obj-$(CONFIG_PINMUX_U300) += pinmux-u300.o
diff --git a/drivers/pinctrl/pinmux-imx-core.c b/drivers/pinctrl/pinmux-imx-core.c
new file mode 100644
index 0000000..4647d3b
--- /dev/null
+++ b/drivers/pinctrl/pinmux-imx-core.c
@@ -0,0 +1,435 @@
+/*
+ * Core driver for the imx pin controller
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "pinmux-imx-core.h"
+
+#define DRIVER_NAME "pinmux-imx"
+
+/**
+ * @dev: a pointer back to containing device
+ * @virtbase: the offset to the controller in virtual memory
+ */
+struct imx_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ void __iomem *virtbase;
+ struct imx_pinctrl_info *info;
+};
+
+#define IMX_PINCTRL_REG_SIZE 4
+#define IMX_PINCTRL_MAX_FUNC 7
+
+static int imx_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const char *imx_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->ngroups)
+ return NULL;
+
+ return info->groups[selector].name;
+}
+
+static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ *pins = info->groups[selector].pins;
+ *num_pins = info->groups[selector].num_pins;
+
+ return 0;
+}
+
+static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, " " DRIVER_NAME);
+}
+
+static struct pinctrl_ops imx_pctrl_ops = {
+ .list_groups = imx_list_groups,
+ .get_group_name = imx_get_group_name,
+ .get_group_pins = imx_get_group_pins,
+ .pin_dbg_show = imx_pin_dbg_show,
+};
+
+static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+ const unsigned *pins, *mux;
+ unsigned int num_pins, num_mux;
+ u32 regval, offset;
+ int i;
+
+ /*
+ * Configure the mux mode for each pin in the group for a specific
+ * function.
+ */
+ pins = info->groups[group].pins;
+ num_pins = info->groups[group].num_pins;
+ mux = info->groups[group].mux_mode;
+ num_mux = info->groups[group].num_mux;
+
+ dev_dbg(ipmx->dev, "function %s group %s\n",
+ info->functions[selector].name, info->groups[group].name);
+
+ if (num_pins != num_mux) {
+ dev_err(ipmx->dev, "num_mux is not equal to num_pins\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_pins; i++) {
+ if (mux[i] > IMX_PINCTRL_MAX_FUNC)
+ dev_err(ipmx->dev, "exceeds the maximum mux mode(0x7)\n");
+ offset = info->mux_offset + pins[i] * IMX_PINCTRL_REG_SIZE;
+ regval = readl(ipmx->virtbase + offset);
+ regval &= ~IMX_PINCTRL_MAX_FUNC;
+ writel(mux[i] | regval, ipmx->virtbase + offset);
+ dev_dbg(ipmx->dev, "write: offset 0x%x val 0x%x\n",
+ offset, regval | mux[i]);
+ }
+
+ return 0;
+}
+
+static void imx_pmx_disable(struct pinctrl_dev *pctldev, unsigned func_selector,
+ unsigned group_selector)
+{
+ /* nothing to do here */
+}
+
+static int imx_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->nfunctions)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ return info->functions[selector].name;
+}
+
+static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ *groups = info->functions[selector].groups;
+ *num_groups = info->functions[selector].num_groups;
+
+ return 0;
+}
+
+static struct pinmux_ops imx_pmx_ops = {
+ .list_functions = imx_pmx_list_funcs,
+ .get_function_name = imx_pmx_get_func_name,
+ .get_function_groups = imx_pmx_get_groups,
+ .enable = imx_pmx_enable,
+ .disable = imx_pmx_disable,
+};
+
+static struct pinctrl_desc imx_pmx_desc = {
+ .name = DRIVER_NAME,
+ .pctlops = &imx_pctrl_ops,
+ .pmxops = &imx_pmx_ops,
+ .owner = THIS_MODULE,
+};
+
+#ifdef CONFIG_OF
+static int __devinit imx_pmx_parse_functions(struct device_node *np,
+ struct imx_pinctrl_info *info, u32 num)
+{
+ struct imx_pmx_func *function;
+ struct imx_pin_group *group;
+ int ret, len;
+
+ dev_dbg(info->dev, "parse function %d\n", num);
+
+ group = &info->groups[num];
+ function = &info->functions[num];
+
+ /* Initialise group */
+ ret = of_property_read_string(np, "grp_name", &group->name);
+ if (ret) {
+ dev_err(info->dev, "failed to get grp_name\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "num_pins", &group->num_pins);
+ if (ret) {
+ dev_err(info->dev, "failed to get num_pins\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "num_mux", &group->num_mux);
+ if (ret) {
+ dev_err(info->dev, "failed to get num_mux\n");
+ return ret;
+ }
+
+ if (group->num_pins != group->num_mux)
+ return -EINVAL;
+
+ group->pins = devm_kzalloc(info->dev, group->num_pins * sizeof(unsigned int),
+ GFP_KERNEL);
+ group->mux_mode = devm_kzalloc(info->dev, group->num_mux * sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!group->pins || !group->mux_mode)
+ return -ENOMEM;
+
+ /* sanity check */
+ if (of_get_property(np, "grp_pins", &len) &&
+ len != group->num_pins * sizeof(unsigned int)) {
+ dev_err(info->dev, "wrong pins number?\n");
+ return -EINVAL;
+ }
+
+ if (of_get_property(np, "grp_mux", &len) &&
+ len != group->num_mux * sizeof(unsigned int)) {
+ dev_err(info->dev, "wrong pin mux number?\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(np, "grp_pins",
+ group->pins, group->num_pins);
+ if (ret) {
+ dev_err(info->dev, "failed to get grp_pins\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32_array(np, "grp_mux",
+ group->mux_mode, group->num_mux);
+ if (ret) {
+ dev_err(info->dev, "failed to get grp_mux\n");
+ return ret;
+ }
+
+ /* Initialise function */
+ ret = of_property_read_string(np, "func_name", &function->name);
+ if (ret) {
+ dev_err(info->dev, "failed to get func_name\n");
+ return ret;
+ }
+
+ function->groups = devm_kzalloc(info->dev, sizeof(char **), GFP_KERNEL);
+ function->num_groups = 1;
+ function->groups[0] = group->name;
+
+ dev_dbg(info->dev, "func_name %s grp_name %s num_groups %d\n",
+ function->name, function->groups[0],
+ function->num_groups);
+
+ return 0;
+}
+
+static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
+ struct imx_pinctrl_info *info)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child = NULL;
+ int ret, i;
+ u32 nfuncs = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ nfuncs = of_get_child_number(np);
+ if (nfuncs <= 0) {
+ dev_err(&pdev->dev, "no functions defined\n");
+ return -EINVAL;
+ }
+
+ info->nfunctions = nfuncs;
+ info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),
+ GFP_KERNEL);
+ if (!info->functions)
+ return -ENOMEM;
+
+ /* DT file only passes one group per one function */
+ info->ngroups = nfuncs;
+ info->groups = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pin_group),
+ GFP_KERNEL);
+ if (!info->groups)
+ return -ENOMEM;
+
+ child = NULL;
+ i = 0;
+ for_each_child_of_node(np, child) {
+ ret = imx_pmx_parse_functions(child, info, i++);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse function\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+#else
+static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
+ struct imx_pinctrl_info *info)
+{
+ return -ENODEV;
+}
+#endif
+
+static inline void imx_pmx_desc_init(struct pinctrl_desc *pmx_desc,
+ const struct imx_pinctrl_info *info)
+{
+ pmx_desc->pins = info->pins;
+ pmx_desc->npins = info->npins;
+ pmx_desc->maxpin = info->maxpin;
+}
+
+static const struct of_device_id imx_pmx_dt_ids[] = {
+#ifdef CONFIG_PINMUX_IMX6Q
+ { .compatible = "fsl,imx6q-iomuxc", .data = (void *) &imx6q_pinctrl_info, },
+#endif
+#ifdef CONFIG_PINMUX_IMX53
+ { .compatible = "fsl,imx53-iomuxc", .data = (void *) &imx53_pinctrl_info, },
+#endif
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pmx_dt_ids);
+
+static int __init imx_pmx_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(imx_pmx_dt_ids, &pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct imx_pmx *ipmx;
+ struct resource *res;
+ struct imx_pinctrl_info *info;
+ resource_size_t res_size;
+ int ret;
+
+ info = of_id->data;
+ if (!info || !info->pins || !(info->maxpin > info->npins)) {
+ dev_err(&pdev->dev, "wrong pinctrl info\n");
+ return -EINVAL;
+ }
+ info->dev = &pdev->dev;
+
+ /* Create state holders etc for this driver */
+ ipmx = devm_kzalloc(&pdev->dev, sizeof(*ipmx), GFP_KERNEL);
+ if (!ipmx)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ res_size = resource_size(res);
+ if (!devm_request_mem_region(dev, res->start, res_size, res->name))
+ return -EBUSY;
+
+ ipmx->virtbase = devm_ioremap_nocache(dev, res->start, res_size);
+ if (!ipmx->virtbase)
+ return -EBUSY;
+
+ imx_pmx_desc_init(&imx_pmx_desc, info);
+ ret = imx_pmx_probe_dt(pdev, info);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to probe dt properties\n");
+ return ret;
+ }
+
+ ipmx->pctl = pinctrl_register(&imx_pmx_desc, &pdev->dev, ipmx);
+ if (!ipmx->pctl) {
+ dev_err(&pdev->dev, "could not register IMX pinmux driver\n");
+ return -EINVAL;
+ }
+
+ ipmx->info = info;
+ ipmx->dev = info->dev;
+ platform_set_drvdata(pdev, ipmx);
+
+ dev_info(&pdev->dev, "initialized IMX pinmux driver\n");
+
+ return 0;
+}
+
+static int __exit imx_pmx_remove(struct platform_device *pdev)
+{
+ struct imx_pmx *ipmx = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(ipmx->pctl);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver imx_pmx_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = imx_pmx_dt_ids,
+ },
+ .remove = __exit_p(imx_pmx_remove),
+};
+
+static int __init imx_pmx_init(void)
+{
+ return platform_driver_probe(&imx_pmx_driver, imx_pmx_probe);
+}
+arch_initcall(imx_pmx_init);
+
+static void __exit imx_pmx_exit(void)
+{
+ platform_driver_unregister(&imx_pmx_driver);
+}
+module_exit(imx_pmx_exit);
+
+MODULE_AUTHOR("Dong Aisheng <dong.a...@linaro.org>");
+MODULE_DESCRIPTION("IMX Pin Control Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinmux-imx-core.h b/drivers/pinctrl/pinmux-imx-core.h
new file mode 100644
index 0000000..df69cd0
--- /dev/null
+++ b/drivers/pinctrl/pinmux-imx-core.h
@@ -0,0 +1,86 @@
+/*
+ * IMX pinmux core definitions
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __DRIVERS_PINCTRL_PINMUX_IMX_H
+#define __DRIVERS_PINCTRL_PINMUX_IMX_H
+
+/* Supported Pinctrl type */
+enum imx_pinctrl_type {
+ IMX53_PINCTRL,
+ IMX6Q_PINCTRL,
+};
+
+/**
+ * struct imx_pin_group - describes an IMX pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ * @mux_mode: the mux mode for each pins in this group. The size of this
+ * array is the same as pins.
+ */
+struct imx_pin_group {
+ const char *name;
+ unsigned int *pins;
+ unsigned num_pins;
+ unsigned int *mux_mode;
+ unsigned num_mux;
+};
+
+/**
+ * struct imx_pmx_func - describes IMX pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ */
+struct imx_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned num_groups;
+};
+
+struct imx_pinctrl_info {
+ struct device *dev;
+ u32 type;
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ unsigned int maxpin;
+ struct imx_pin_group *groups;
+ unsigned int ngroups;
+ struct imx_pmx_func *functions;
+ unsigned int nfunctions;
+ u32 mux_offset;
+};
+
+#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
+
+#define IMX_PIN_GROUP(n, p, m) \
+ { \
+ .name = n, \
+ .pins = p, \
+ .num_pins = ARRAY_SIZE(p), \
+ .mux_mode = m, \
+ .num_mux = ARRAY_SIZE(m), \
+ }
+
+#define IMX_PMX_FUNC(n, g) \
+ { \
+ .name = n, \
+ .groups = g, \
+ .num_groups = ARRAY_SIZE(g), \
+ }
+
+extern struct imx_pinctrl_info imx53_pinctrl_info;
+extern struct imx_pinctrl_info imx6q_pinctrl_info;
+#endif /* __DRIVERS_PINCTRL_PINMUX_IMX_H */
diff --git a/drivers/pinctrl/pinmux-imx53.c b/drivers/pinctrl/pinmux-imx53.c
new file mode 100644
index 0000000..0b2faa7
--- /dev/null
+++ b/drivers/pinctrl/pinmux-imx53.c
@@ -0,0 +1,443 @@
+/*
+ * imx53 pinmux driver based on imx pinmux core
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinmux-imx-core.h"
+
+#define IMX53_IOMUXC_MUX_OFFSET 0x20
+#define IMX53_IOMUXC_MAXPIN (23*23)
+
+enum imx_imx53_pinctrl_pads {
+ MX53_GPIO_19 = 0,
+ MX53_KEY_COL0 = 1,
+ MX53_KEY_ROW0 = 2,
+ MX53_KEY_COL1 = 3,
+ MX53_KEY_ROW1 = 4,
+ MX53_KEY_COL2 = 5,
+ MX53_KEY_ROW2 = 6,
+ MX53_KEY_COL3 = 7,
+ MX53_KEY_ROW3 = 8,
+ MX53_KEY_COL4 = 9,
+ MX53_KEY_ROW4 = 10,
+ MX53_DI0_DISP_CLK = 11,
+ MX53_DI0_PIN15 = 12,
+ MX53_DI0_PIN2 = 13,
+ MX53_DI0_PIN3 = 14,
+ MX53_DI0_PIN4 = 15,
+ MX53_DISP0_DAT0 = 16,
+ MX53_DISP0_DAT1 = 17,
+ MX53_DISP0_DAT2 = 18,
+ MX53_DISP0_DAT3 = 19,
+ MX53_DISP0_DAT4 = 20,
+ MX53_DISP0_DAT5 = 21,
+ MX53_DISP0_DAT6 = 22,
+ MX53_DISP0_DAT7 = 23,
+ MX53_DISP0_DAT8 = 24,
+ MX53_DISP0_DAT9 = 25,
+ MX53_DISP0_DAT10 = 26,
+ MX53_DISP0_DAT11 = 27,
+ MX53_DISP0_DAT12 = 28,
+ MX53_DISP0_DAT13 = 29,
+ MX53_DISP0_DAT14 = 30,
+ MX53_DISP0_DAT15 = 31,
+ MX53_DISP0_DAT16 = 32,
+ MX53_DISP0_DAT17 = 33,
+ MX53_DISP0_DAT18 = 34,
+ MX53_DISP0_DAT19 = 35,
+ MX53_DISP0_DAT20 = 36,
+ MX53_DISP0_DAT21 = 37,
+ MX53_DISP0_DAT22 = 38,
+ MX53_DISP0_DAT23 = 39,
+ MX53_CSI0_PIXCLK = 40,
+ MX53_CSI0_MCLK = 41,
+ MX53_CSI0_DATA_EN = 42,
+ MX53_CSI0_VSYNC = 43,
+ MX53_CSI0_DAT4 = 44,
+ MX53_CSI0_DAT5 = 45,
+ MX53_CSI0_DAT6 = 46,
+ MX53_CSI0_DAT7 = 47,
+ MX53_CSI0_DAT8 = 48,
+ MX53_CSI0_DAT9 = 49,
+ MX53_CSI0_DAT10 = 50,
+ MX53_CSI0_DAT11 = 51,
+ MX53_CSI0_DAT12 = 52,
+ MX53_CSI0_DAT13 = 53,
+ MX53_CSI0_DAT14 = 54,
+ MX53_CSI0_DAT15 = 55,
+ MX53_CSI0_DAT16 = 56,
+ MX53_CSI0_DAT17 = 57,
+ MX53_CSI0_DAT18 = 58,
+ MX53_CSI0_DAT19 = 59,
+ MX53_EIM_A25 = 60,
+ MX53_EIM_EB2 = 61,
+ MX53_EIM_D16 = 62,
+ MX53_EIM_D17 = 63,
+ MX53_EIM_D18 = 64,
+ MX53_EIM_D19 = 65,
+ MX53_EIM_D20 = 66,
+ MX53_EIM_D21 = 67,
+ MX53_EIM_D22 = 68,
+ MX53_EIM_D23 = 69,
+ MX53_EIM_EB3 = 70,
+ MX53_EIM_D24 = 71,
+ MX53_EIM_D25 = 72,
+ MX53_EIM_D26 = 73,
+ MX53_EIM_D27 = 74,
+ MX53_EIM_D28 = 75,
+ MX53_EIM_D29 = 76,
+ MX53_EIM_D30 = 77,
+ MX53_EIM_D31 = 78,
+ MX53_EIM_A24 = 79,
+ MX53_EIM_A23 = 80,
+ MX53_EIM_A22 = 81,
+ MX53_EIM_A21 = 82,
+ MX53_EIM_A20 = 83,
+ MX53_EIM_A19 = 84,
+ MX53_EIM_A18 = 85,
+ MX53_EIM_A17 = 86,
+ MX53_EIM_A16 = 87,
+ MX53_EIM_CS0 = 88,
+ MX53_EIM_CS1 = 89,
+ MX53_EIM_OE = 90,
+ MX53_EIM_RW = 91,
+ MX53_EIM_LBA = 92,
+ MX53_EIM_EB0 = 93,
+ MX53_EIM_EB1 = 94,
+ MX53_EIM_DA0 = 95,
+ MX53_EIM_DA1 = 96,
+ MX53_EIM_DA2 = 97,
+ MX53_EIM_DA3 = 98,
+ MX53_EIM_DA4 = 99,
+ MX53_EIM_DA5 = 100,
+ MX53_EIM_DA6 = 101,
+ MX53_EIM_DA7 = 102,
+ MX53_EIM_DA8 = 103,
+ MX53_EIM_DA9 = 104,
+ MX53_EIM_DA10 = 105,
+ MX53_EIM_DA11 = 106,
+ MX53_EIM_DA12 = 107,
+ MX53_EIM_DA13 = 108,
+ MX53_EIM_DA14 = 109,
+ MX53_EIM_DA15 = 110,
+ MX53_NANDF_WE_B = 111,
+ MX53_NANDF_RE_B = 112,
+ MX53_EIM_WAIT = 113,
+ MX53_EIM_BCLK = 114,
+ MX53_LVDS1_TX3_P = 115,
+ MX53_LVDS1_TX2_P = 116,
+ MX53_LVDS1_CLK_P = 117,
+ MX53_LVDS1_TX1_P = 118,
+ MX53_LVDS1_TX0_P = 119,
+ MX53_LVDS0_TX3_P = 120,
+ MX53_LVDS0_CLK_P = 121,
+ MX53_LVDS0_TX2_P = 122,
+ MX53_LVDS0_TX1_P = 123,
+ MX53_LVDS0_TX0_P = 124,
+ MX53_GPIO_10 = 125,
+ MX53_GPIO_11 = 126,
+ MX53_GPIO_12 = 127,
+ MX53_GPIO_13 = 128,
+ MX53_GPIO_14 = 129,
+ MX53_NANDF_CLE = 130,
+ MX53_NANDF_ALE = 131,
+ MX53_NANDF_WP_B = 132,
+ MX53_NANDF_RB0 = 133,
+ MX53_NANDF_CS0 = 134,
+ MX53_NANDF_CS1 = 135,
+ MX53_NANDF_CS2 = 136,
+ MX53_NANDF_CS3 = 137,
+ MX53_FEC_MDIO = 138,
+ MX53_FEC_REF_CLK = 139,
+ MX53_FEC_RX_ER = 140,
+ MX53_FEC_CRS_DV = 141,
+ MX53_FEC_RXD1 = 142,
+ MX53_FEC_RXD0 = 143,
+ MX53_FEC_TX_EN = 144,
+ MX53_FEC_TXD1 = 145,
+ MX53_FEC_TXD0 = 146,
+ MX53_FEC_MDC = 147,
+ MX53_PATA_DIOW = 148,
+ MX53_PATA_DMACK = 149,
+ MX53_PATA_DMARQ = 150,
+ MX53_PATA_BUFFER_EN = 151,
+ MX53_PATA_INTRQ = 152,
+ MX53_PATA_DIOR = 153,
+ MX53_PATA_RESET_B = 154,
+ MX53_PATA_IORDY = 155,
+ MX53_PATA_DA_0 = 156,
+ MX53_PATA_DA_1 = 157,
+ MX53_PATA_DA_2 = 158,
+ MX53_PATA_CS_0 = 159,
+ MX53_PATA_CS_1 = 160,
+ MX53_PATA_DATA0 = 161,
+ MX53_PATA_DATA1 = 162,
+ MX53_PATA_DATA2 = 163,
+ MX53_PATA_DATA3 = 164,
+ MX53_PATA_DATA4 = 165,
+ MX53_PATA_DATA5 = 166,
+ MX53_PATA_DATA6 = 167,
+ MX53_PATA_DATA7 = 168,
+ MX53_PATA_DATA8 = 169,
+ MX53_PATA_DATA9 = 170,
+ MX53_PATA_DATA10 = 171,
+ MX53_PATA_DATA11 = 172,
+ MX53_PATA_DATA12 = 173,
+ MX53_PATA_DATA13 = 174,
+ MX53_PATA_DATA14 = 175,
+ MX53_PATA_DATA15 = 176,
+ MX53_SD1_DATA0 = 177,
+ MX53_SD1_DATA1 = 178,
+ MX53_SD1_CMD = 179,
+ MX53_SD1_DATA2 = 180,
+ MX53_SD1_CLK = 181,
+ MX53_SD1_DATA3 = 182,
+ MX53_SD2_CLK = 183,
+ MX53_SD2_CMD = 184,
+ MX53_SD2_DATA3 = 185,
+ MX53_SD2_DATA2 = 186,
+ MX53_SD2_DATA1 = 187,
+ MX53_SD2_DATA0 = 188,
+ MX53_GPIO_0 = 189,
+ MX53_GPIO_1 = 190,
+ MX53_GPIO_9 = 191,
+ MX53_GPIO_3 = 192,
+ MX53_GPIO_6 = 193,
+ MX53_GPIO_2 = 194,
+ MX53_GPIO_4 = 195,
+ MX53_GPIO_5 = 196,
+ MX53_GPIO_7 = 197,
+ MX53_GPIO_8 = 198,
+ MX53_GPIO_16 = 199,
+ MX53_GPIO_17 = 200,
+ MX53_GPIO_18 = 201,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx53_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX53_GPIO_19),
+ IMX_PINCTRL_PIN(MX53_KEY_COL0),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX53_KEY_COL1),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX53_KEY_COL2),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX53_KEY_COL3),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX53_KEY_COL4),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW4),
+ IMX_PINCTRL_PIN(MX53_DI0_DISP_CLK),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN15),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN2),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN3),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN4),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT0),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT1),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT2),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT3),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT4),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT5),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT6),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT7),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT8),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT9),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT10),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT11),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT12),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT13),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT14),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT15),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT16),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT17),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT18),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT19),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT20),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT21),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT22),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT23),
+ IMX_PINCTRL_PIN(MX53_CSI0_PIXCLK),
+ IMX_PINCTRL_PIN(MX53_CSI0_MCLK),
+ IMX_PINCTRL_PIN(MX53_CSI0_DATA_EN),
+ IMX_PINCTRL_PIN(MX53_CSI0_VSYNC),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT4),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT5),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT6),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT7),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT8),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT9),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT10),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT11),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT12),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT13),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT14),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT15),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT16),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT17),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT18),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT19),
+ IMX_PINCTRL_PIN(MX53_EIM_A25),
+ IMX_PINCTRL_PIN(MX53_EIM_EB2),
+ IMX_PINCTRL_PIN(MX53_EIM_D16),
+ IMX_PINCTRL_PIN(MX53_EIM_D17),
+ IMX_PINCTRL_PIN(MX53_EIM_D18),
+ IMX_PINCTRL_PIN(MX53_EIM_D19),
+ IMX_PINCTRL_PIN(MX53_EIM_D20),
+ IMX_PINCTRL_PIN(MX53_EIM_D21),
+ IMX_PINCTRL_PIN(MX53_EIM_D22),
+ IMX_PINCTRL_PIN(MX53_EIM_D23),
+ IMX_PINCTRL_PIN(MX53_EIM_EB3),
+ IMX_PINCTRL_PIN(MX53_EIM_D24),
+ IMX_PINCTRL_PIN(MX53_EIM_D25),
+ IMX_PINCTRL_PIN(MX53_EIM_D26),
+ IMX_PINCTRL_PIN(MX53_EIM_D27),
+ IMX_PINCTRL_PIN(MX53_EIM_D28),
+ IMX_PINCTRL_PIN(MX53_EIM_D29),
+ IMX_PINCTRL_PIN(MX53_EIM_D30),
+ IMX_PINCTRL_PIN(MX53_EIM_D31),
+ IMX_PINCTRL_PIN(MX53_EIM_A24),
+ IMX_PINCTRL_PIN(MX53_EIM_A23),
+ IMX_PINCTRL_PIN(MX53_EIM_A22),
+ IMX_PINCTRL_PIN(MX53_EIM_A21),
+ IMX_PINCTRL_PIN(MX53_EIM_A20),
+ IMX_PINCTRL_PIN(MX53_EIM_A19),
+ IMX_PINCTRL_PIN(MX53_EIM_A18),
+ IMX_PINCTRL_PIN(MX53_EIM_A17),
+ IMX_PINCTRL_PIN(MX53_EIM_A16),
+ IMX_PINCTRL_PIN(MX53_EIM_CS0),
+ IMX_PINCTRL_PIN(MX53_EIM_CS1),
+ IMX_PINCTRL_PIN(MX53_EIM_OE),
+ IMX_PINCTRL_PIN(MX53_EIM_RW),
+ IMX_PINCTRL_PIN(MX53_EIM_LBA),
+ IMX_PINCTRL_PIN(MX53_EIM_EB0),
+ IMX_PINCTRL_PIN(MX53_EIM_EB1),
+ IMX_PINCTRL_PIN(MX53_EIM_DA0),
+ IMX_PINCTRL_PIN(MX53_EIM_DA1),
+ IMX_PINCTRL_PIN(MX53_EIM_DA2),
+ IMX_PINCTRL_PIN(MX53_EIM_DA3),
+ IMX_PINCTRL_PIN(MX53_EIM_DA4),
+ IMX_PINCTRL_PIN(MX53_EIM_DA5),
+ IMX_PINCTRL_PIN(MX53_EIM_DA6),
+ IMX_PINCTRL_PIN(MX53_EIM_DA7),
+ IMX_PINCTRL_PIN(MX53_EIM_DA8),
+ IMX_PINCTRL_PIN(MX53_EIM_DA9),
+ IMX_PINCTRL_PIN(MX53_EIM_DA10),
+ IMX_PINCTRL_PIN(MX53_EIM_DA11),
+ IMX_PINCTRL_PIN(MX53_EIM_DA12),
+ IMX_PINCTRL_PIN(MX53_EIM_DA13),
+ IMX_PINCTRL_PIN(MX53_EIM_DA14),
+ IMX_PINCTRL_PIN(MX53_EIM_DA15),
+ IMX_PINCTRL_PIN(MX53_NANDF_WE_B),
+ IMX_PINCTRL_PIN(MX53_NANDF_RE_B),
+ IMX_PINCTRL_PIN(MX53_EIM_WAIT),
+ IMX_PINCTRL_PIN(MX53_EIM_BCLK),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX3_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX2_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_CLK_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX1_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX0_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX3_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_CLK_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX2_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX1_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX0_P),
+ IMX_PINCTRL_PIN(MX53_GPIO_10),
+ IMX_PINCTRL_PIN(MX53_GPIO_11),
+ IMX_PINCTRL_PIN(MX53_GPIO_12),
+ IMX_PINCTRL_PIN(MX53_GPIO_13),
+ IMX_PINCTRL_PIN(MX53_GPIO_14),
+ IMX_PINCTRL_PIN(MX53_NANDF_CLE),
+ IMX_PINCTRL_PIN(MX53_NANDF_ALE),
+ IMX_PINCTRL_PIN(MX53_NANDF_WP_B),
+ IMX_PINCTRL_PIN(MX53_NANDF_RB0),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS0),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS1),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS2),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS3),
+ IMX_PINCTRL_PIN(MX53_FEC_MDIO),
+ IMX_PINCTRL_PIN(MX53_FEC_REF_CLK),
+ IMX_PINCTRL_PIN(MX53_FEC_RX_ER),
+ IMX_PINCTRL_PIN(MX53_FEC_CRS_DV),
+ IMX_PINCTRL_PIN(MX53_FEC_RXD1),
+ IMX_PINCTRL_PIN(MX53_FEC_RXD0),
+ IMX_PINCTRL_PIN(MX53_FEC_TX_EN),
+ IMX_PINCTRL_PIN(MX53_FEC_TXD1),
+ IMX_PINCTRL_PIN(MX53_FEC_TXD0),
+ IMX_PINCTRL_PIN(MX53_FEC_MDC),
+ IMX_PINCTRL_PIN(MX53_PATA_DIOW),
+ IMX_PINCTRL_PIN(MX53_PATA_DMACK),
+ IMX_PINCTRL_PIN(MX53_PATA_DMARQ),
+ IMX_PINCTRL_PIN(MX53_PATA_BUFFER_EN),
+ IMX_PINCTRL_PIN(MX53_PATA_INTRQ),
+ IMX_PINCTRL_PIN(MX53_PATA_DIOR),
+ IMX_PINCTRL_PIN(MX53_PATA_RESET_B),
+ IMX_PINCTRL_PIN(MX53_PATA_IORDY),
+ IMX_PINCTRL_PIN(MX53_PATA_DA_0),
+ IMX_PINCTRL_PIN(MX53_PATA_DA_1),
+ IMX_PINCTRL_PIN(MX53_PATA_DA_2),
+ IMX_PINCTRL_PIN(MX53_PATA_CS_0),
+ IMX_PINCTRL_PIN(MX53_PATA_CS_1),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA0),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA1),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA2),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA3),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA4),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA5),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA6),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA7),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA8),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA9),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA10),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA11),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA12),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA13),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA14),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA15),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX53_SD1_CMD),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX53_SD1_CLK),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX53_SD2_CLK),
+ IMX_PINCTRL_PIN(MX53_SD2_CMD),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX53_GPIO_0),
+ IMX_PINCTRL_PIN(MX53_GPIO_1),
+ IMX_PINCTRL_PIN(MX53_GPIO_9),
+ IMX_PINCTRL_PIN(MX53_GPIO_3),
+ IMX_PINCTRL_PIN(MX53_GPIO_6),
+ IMX_PINCTRL_PIN(MX53_GPIO_2),
+ IMX_PINCTRL_PIN(MX53_GPIO_4),
+ IMX_PINCTRL_PIN(MX53_GPIO_5),
+ IMX_PINCTRL_PIN(MX53_GPIO_7),
+ IMX_PINCTRL_PIN(MX53_GPIO_8),
+ IMX_PINCTRL_PIN(MX53_GPIO_16),
+ IMX_PINCTRL_PIN(MX53_GPIO_17),
+ IMX_PINCTRL_PIN(MX53_GPIO_18),
+};
+
+struct imx_pinctrl_info imx53_pinctrl_info = {
+ .type = IMX53_PINCTRL,
+ .pins = imx53_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx53_pinctrl_pads),
+ .maxpin = IMX53_IOMUXC_MAXPIN,
+ .mux_offset = IMX53_IOMUXC_MUX_OFFSET,
+};
diff --git a/drivers/pinctrl/pinmux-imx6q.c b/drivers/pinctrl/pinmux-imx6q.c
new file mode 100644
index 0000000..4749a4f
--- /dev/null
+++ b/drivers/pinctrl/pinmux-imx6q.c
@@ -0,0 +1,433 @@
+/*
+ * imx6q pinmux driver based on imx pinmux core
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinmux-imx-core.h"
+
+#define IMX6Q_IOMUXC_MUX_OFSSET 0x4c
+#define IMX6Q_IOMUXC_MAXPIN (25*25)
+
+enum imx6q_pads {
+ MX6Q_SD2_DAT1 = 0,
+ MX6Q_SD2_DAT2 = 1,
+ MX6Q_SD2_DAT0 = 2,
+ MX6Q_RGMII_TXC = 3,
+ MX6Q_RGMII_TD0 = 4,
+ MX6Q_RGMII_TD1 = 5,
+ MX6Q_RGMII_TD2 = 6,
+ MX6Q_RGMII_TD3 = 7,
+ MX6Q_RGMII_RX_CTL = 8,
+ MX6Q_RGMII_RD0 = 9,
+ MX6Q_RGMII_TX_CTL = 10,
+ MX6Q_RGMII_RD1 = 11,
+ MX6Q_RGMII_RD2 = 12,
+ MX6Q_RGMII_RD3 = 13,
+ MX6Q_RGMII_RXC = 14,
+ MX6Q_EIM_A25 = 15,
+ MX6Q_EIM_EB2 = 16,
+ MX6Q_EIM_D16 = 17,
+ MX6Q_EIM_D17 = 18,
+ MX6Q_EIM_D18 = 19,
+ MX6Q_EIM_D19 = 20,
+ MX6Q_EIM_D20 = 21,
+ MX6Q_EIM_D21 = 22,
+ MX6Q_EIM_D22 = 23,
+ MX6Q_EIM_D23 = 24,
+ MX6Q_EIM_EB3 = 25,
+ MX6Q_EIM_D24 = 26,
+ MX6Q_EIM_D25 = 27,
+ MX6Q_EIM_D26 = 28,
+ MX6Q_EIM_D27 = 29,
+ MX6Q_EIM_D28 = 30,
+ MX6Q_EIM_D29 = 31,
+ MX6Q_EIM_D30 = 32,
+ MX6Q_EIM_D31 = 33,
+ MX6Q_EIM_A24 = 34,
+ MX6Q_EIM_A23 = 35,
+ MX6Q_EIM_A22 = 36,
+ MX6Q_EIM_A21 = 37,
+ MX6Q_EIM_A20 = 38,
+ MX6Q_EIM_A19 = 39,
+ MX6Q_EIM_A18 = 40,
+ MX6Q_EIM_A17 = 41,
+ MX6Q_EIM_A16 = 42,
+ MX6Q_EIM_CS0 = 43,
+ MX6Q_EIM_CS1 = 44,
+ MX6Q_EIM_OE = 45,
+ MX6Q_EIM_RW = 46,
+ MX6Q_EIM_LBA = 47,
+ MX6Q_EIM_EB0 = 48,
+ MX6Q_EIM_EB1 = 49,
+ MX6Q_EIM_DA0 = 50,
+ MX6Q_EIM_DA1 = 51,
+ MX6Q_EIM_DA2 = 52,
+ MX6Q_EIM_DA3 = 53,
+ MX6Q_EIM_DA4 = 54,
+ MX6Q_EIM_DA5 = 55,
+ MX6Q_EIM_DA6 = 56,
+ MX6Q_EIM_DA7 = 57,
+ MX6Q_EIM_DA8 = 58,
+ MX6Q_EIM_DA9 = 59,
+ MX6Q_EIM_DA10 = 60,
+ MX6Q_EIM_DA11 = 61,
+ MX6Q_EIM_DA12 = 62,
+ MX6Q_EIM_DA13 = 63,
+ MX6Q_EIM_DA14 = 64,
+ MX6Q_EIM_DA15 = 65,
+ MX6Q_EIM_WAIT = 66,
+ MX6Q_EIM_BCLK = 67,
+ MX6Q_DI0_DISP_CLK = 68,
+ MX6Q_DI0_PIN15 = 69,
+ MX6Q_DI0_PIN2 = 70,
+ MX6Q_DI0_PIN3 = 71,
+ MX6Q_DI0_PIN4 = 72,
+ MX6Q_DISP0_DAT0 = 73,
+ MX6Q_DISP0_DAT1 = 74,
+ MX6Q_DISP0_DAT2 = 75,
+ MX6Q_DISP0_DAT3 = 76,
+ MX6Q_DISP0_DAT4 = 77,
+ MX6Q_DISP0_DAT5 = 78,
+ MX6Q_DISP0_DAT6 = 79,
+ MX6Q_DISP0_DAT7 = 80,
+ MX6Q_DISP0_DAT8 = 81,
+ MX6Q_DISP0_DAT9 = 82,
+ MX6Q_DISP0_DAT10 = 83,
+ MX6Q_DISP0_DAT11 = 84,
+ MX6Q_DISP0_DAT12 = 85,
+ MX6Q_DISP0_DAT13 = 86,
+ MX6Q_DISP0_DAT14 = 87,
+ MX6Q_DISP0_DAT15 = 88,
+ MX6Q_DISP0_DAT16 = 89,
+ MX6Q_DISP0_DAT17 = 90,
+ MX6Q_DISP0_DAT18 = 91,
+ MX6Q_DISP0_DAT19 = 92,
+ MX6Q_DISP0_DAT20 = 93,
+ MX6Q_DISP0_DAT21 = 94,
+ MX6Q_DISP0_DAT22 = 95,
+ MX6Q_DISP0_DAT23 = 96,
+ MX6Q_ENET_MDIO = 97,
+ MX6Q_ENET_REF_CLK = 98,
+ MX6Q_ENET_RX_ER = 99,
+ MX6Q_ENET_CRS_DV = 100,
+ MX6Q_ENET_RXD1 = 101,
+ MX6Q_ENET_RXD0 = 102,
+ MX6Q_ENET_TX_EN = 103,
+ MX6Q_ENET_TXD1 = 104,
+ MX6Q_ENET_TXD0 = 105,
+ MX6Q_ENET_MDC = 106,
+ MX6Q_KEY_COL0 = 107,
+ MX6Q_KEY_ROW0 = 108,
+ MX6Q_KEY_COL1 = 109,
+ MX6Q_KEY_ROW1 = 110,
+ MX6Q_KEY_COL2 = 111,
+ MX6Q_KEY_ROW2 = 112,
+ MX6Q_KEY_COL3 = 113,
+ MX6Q_KEY_ROW3 = 114,
+ MX6Q_KEY_COL4 = 115,
+ MX6Q_KEY_ROW4 = 116,
+ MX6Q_GPIO_0 = 117,
+ MX6Q_GPIO_1 = 118,
+ MX6Q_GPIO_9 = 119,
+ MX6Q_GPIO_3 = 120,
+ MX6Q_GPIO_6 = 121,
+ MX6Q_GPIO_2 = 122,
+ MX6Q_GPIO_4 = 123,
+ MX6Q_GPIO_5 = 124,
+ MX6Q_GPIO_7 = 125,
+ MX6Q_GPIO_8 = 126,
+ MX6Q_GPIO_16 = 127,
+ MX6Q_GPIO_17 = 128,
+ MX6Q_GPIO_18 = 129,
+ MX6Q_GPIO_19 = 130,
+ MX6Q_CSI0_PIXCLK = 131,
+ MX6Q_CSI0_MCLK = 132,
+ MX6Q_CSI0_DATA_EN = 133,
+ MX6Q_CSI0_VSYNC = 134,
+ MX6Q_CSI0_DAT4 = 135,
+ MX6Q_CSI0_DAT5 = 136,
+ MX6Q_CSI0_DAT6 = 137,
+ MX6Q_CSI0_DAT7 = 138,
+ MX6Q_CSI0_DAT8 = 139,
+ MX6Q_CSI0_DAT9 = 140,
+ MX6Q_CSI0_DAT10 = 141,
+ MX6Q_CSI0_DAT11 = 142,
+ MX6Q_CSI0_DAT12 = 143,
+ MX6Q_CSI0_DAT13 = 144,
+ MX6Q_CSI0_DAT14 = 145,
+ MX6Q_CSI0_DAT15 = 146,
+ MX6Q_CSI0_DAT16 = 147,
+ MX6Q_CSI0_DAT17 = 148,
+ MX6Q_CSI0_DAT18 = 149,
+ MX6Q_CSI0_DAT19 = 150,
+ MX6Q_SD3_DAT7 = 151,
+ MX6Q_SD3_DAT6 = 152,
+ MX6Q_SD3_DAT5 = 153,
+ MX6Q_SD3_DAT4 = 154,
+ MX6Q_SD3_CMD = 155,
+ MX6Q_SD3_CLK = 156,
+ MX6Q_SD3_DAT0 = 157,
+ MX6Q_SD3_DAT1 = 158,
+ MX6Q_SD3_DAT2 = 159,
+ MX6Q_SD3_DAT3 = 160,
+ MX6Q_SD3_RST = 161,
+ MX6Q_NANDF_CLE = 162,
+ MX6Q_NANDF_ALE = 163,
+ MX6Q_NANDF_WP_B = 164,
+ MX6Q_NANDF_RB0 = 165,
+ MX6Q_NANDF_CS0 = 166,
+ MX6Q_NANDF_CS1 = 167,
+ MX6Q_NANDF_CS2 = 168,
+ MX6Q_NANDF_CS3 = 169,
+ MX6Q_SD4_CMD = 170,
+ MX6Q_SD4_CLK = 171,
+ MX6Q_NANDF_D0 = 172,
+ MX6Q_NANDF_D1 = 173,
+ MX6Q_NANDF_D2 = 174,
+ MX6Q_NANDF_D3 = 175,
+ MX6Q_NANDF_D4 = 176,
+ MX6Q_NANDF_D5 = 177,
+ MX6Q_NANDF_D6 = 178,
+ MX6Q_NANDF_D7 = 179,
+ MX6Q_SD4_DAT0 = 180,
+ MX6Q_SD4_DAT1 = 181,
+ MX6Q_SD4_DAT2 = 182,
+ MX6Q_SD4_DAT3 = 183,
+ MX6Q_SD4_DAT4 = 184,
+ MX6Q_SD4_DAT5 = 185,
+ MX6Q_SD4_DAT6 = 186,
+ MX6Q_SD4_DAT7 = 187,
+ MX6Q_SD1_DAT1 = 188,
+ MX6Q_SD1_DAT0 = 189,
+ MX6Q_SD1_DAT3 = 190,
+ MX6Q_SD1_CMD = 191,
+ MX6Q_SD1_DAT2 = 192,
+ MX6Q_SD1_CLK = 193,
+ MX6Q_SD2_CLK = 194,
+ MX6Q_SD2_CMD = 195,
+ MX6Q_SD2_DAT3 = 196
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx6q_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TXC),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD0),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD1),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD2),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD3),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RX_CTL),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD0),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TX_CTL),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD1),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD2),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD3),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RXC),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A25),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB2),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D16),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D17),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D18),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D19),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D20),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D21),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D22),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D23),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB3),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D24),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D25),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D26),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D27),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D28),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D29),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D30),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D31),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A24),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A23),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A22),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A21),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A20),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A19),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A18),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A17),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A16),
+ IMX_PINCTRL_PIN(MX6Q_EIM_CS0),
+ IMX_PINCTRL_PIN(MX6Q_EIM_CS1),
+ IMX_PINCTRL_PIN(MX6Q_EIM_OE),
+ IMX_PINCTRL_PIN(MX6Q_EIM_RW),
+ IMX_PINCTRL_PIN(MX6Q_EIM_LBA),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB0),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB1),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA0),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA1),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA2),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA3),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA4),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA5),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA6),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA7),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA8),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA9),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA10),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA11),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA12),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA13),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA14),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA15),
+ IMX_PINCTRL_PIN(MX6Q_EIM_WAIT),
+ IMX_PINCTRL_PIN(MX6Q_EIM_BCLK),
+ IMX_PINCTRL_PIN(MX6Q_DI0_DISP_CLK),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN15),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN2),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN3),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN4),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT8),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT9),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT10),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT11),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT12),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT13),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT14),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT15),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT16),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT17),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT18),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT19),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT20),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT21),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT22),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT23),
+ IMX_PINCTRL_PIN(MX6Q_ENET_MDIO),
+ IMX_PINCTRL_PIN(MX6Q_ENET_REF_CLK),
+ IMX_PINCTRL_PIN(MX6Q_ENET_RX_ER),
+ IMX_PINCTRL_PIN(MX6Q_ENET_CRS_DV),
+ IMX_PINCTRL_PIN(MX6Q_ENET_RXD1),
+ IMX_PINCTRL_PIN(MX6Q_ENET_RXD0),
+ IMX_PINCTRL_PIN(MX6Q_ENET_TX_EN),
+ IMX_PINCTRL_PIN(MX6Q_ENET_TXD1),
+ IMX_PINCTRL_PIN(MX6Q_ENET_TXD0),
+ IMX_PINCTRL_PIN(MX6Q_ENET_MDC),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL0),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL1),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL2),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL3),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL4),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW4),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_0),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_1),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_9),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_3),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_6),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_2),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_4),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_5),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_7),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_8),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_16),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_17),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_18),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_19),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_PIXCLK),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_MCLK),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DATA_EN),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_VSYNC),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT8),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT9),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT10),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT11),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT12),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT13),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT14),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT15),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT16),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT17),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT18),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT19),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_SD3_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD3_CLK),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_SD3_RST),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CLE),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_ALE),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_WP_B),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_RB0),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS0),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS1),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS2),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS3),
+ IMX_PINCTRL_PIN(MX6Q_SD4_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD4_CLK),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D0),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D1),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D2),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D3),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D4),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D5),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D6),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D7),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_SD1_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD1_CLK),
+ IMX_PINCTRL_PIN(MX6Q_SD2_CLK),
+ IMX_PINCTRL_PIN(MX6Q_SD2_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT3),
+};
+
+struct imx_pinctrl_info imx6q_pinctrl_info = {
+ .type = IMX6Q_PINCTRL,
+ .pins = imx6q_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx6q_pinctrl_pads),
+ .maxpin = IMX6Q_IOMUXC_MAXPIN,
+ .mux_offset = IMX6Q_IOMUXC_MUX_OFSSET,
+};
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Linus Walleij <linus....@linaro.org>
Cc: Sascha Hauer <s.h...@pengutronix.de>
Cc: Shawn Guo <shan...@freescale.com>
---
arch/arm/boot/dts/imx6q-sabreauto.dts | 22 ++++++++++++++++++++++
arch/arm/boot/dts/imx6q.dtsi | 1 +
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/mach-imx6q.c | 8 +++++++-
4 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/arch/arm/boot/dts/imx6q-sabreauto.dts b/arch/arm/boot/dts/imx6q-sabreauto.dts
index 072974e..1bd1ef9 100644
--- a/arch/arm/boot/dts/imx6q-sabreauto.dts
+++ b/arch/arm/boot/dts/imx6q-sabreauto.dts
@@ -26,6 +26,28 @@
};
soc {
+ aips-bus@02000000 { /* AIPS1 */
+ iomuxc@020e0000 {
+ pinmux_uart4 {
+ func_name = "uart4";
+ grp_name = "uart4grp";
+ grp_pins = <107 108>;
+ num_pins = <2>;
+ grp_mux = <4 4>;
+ num_mux = <2>;
+ };
+
+ pinmux_sd4 {
+ func_name = "sd4";
+ grp_name = "sd4grp";
+ grp_pins = <170 171 180 181 182 183 184 185 186 187>;
+ num_pins = <10>;
+ grp_mux = <0 0 1 1 1 1 1 1 1 1>;
+ num_mux = <10>;
+ };
+ };
+ };
+
aips-bus@02100000 { /* AIPS2 */
enet@02188000 {
phy-mode = "rgmii";
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 7dda599..42499bb 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -386,6 +386,7 @@
};
iomuxc@020e0000 {
+ compatible = "fsl,imx6q-iomuxc";
reg = <0x020e0000 0x4000>;
};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index c44aa97..1e0befa 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -602,6 +602,7 @@ config SOC_IMX6Q
select HAVE_IMX_GPC
select HAVE_IMX_MMDC
select HAVE_IMX_SRC
+ select PINCTRL
select USE_OF
help
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 9cd860a..e12ae63 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
@@ -23,10 +24,15 @@
#include <mach/common.h>
#include <mach/hardware.h>
+static struct pinmux_map imx6q_pinmux_map[] = {
+ PINMUX_MAP_PRIMARY("usdhc4", "sd4", "219c000.usdhc"),
+};
+
static void __init imx6q_init_machine(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-
+ pinmux_register_mappings(imx6q_pinmux_map,
+ ARRAY_SIZE(imx6q_pinmux_map));
imx6q_pm_init();
> +config PINMUX_IMX53
> + Â Â Â bool "IMX53 pinmux driver"
> + Â Â Â depends on ARCH_MX5
Shouldn't this be SOC_IMX53 instead?
Regards,
Fabio Estevam
Signed-off-by: Shawn Guo <shaw...@linaro.org>
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Linus Walleij <linus....@linaro.org>
Cc: Chris Ball <c...@laptop.org>
Cc: Sascha Hauer <s.h...@pengutronix.de>
Cc: Wolfram Sang <w.s...@pengutronix.de>
---
drivers/mmc/host/sdhci-esdhc-imx.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 4b976f0..4504136 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -24,6 +24,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/pinmux.h>
#include <mach/esdhc.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -68,6 +69,7 @@ struct pltfm_imx_data {
int flags;
u32 scratchpad;
enum imx_esdhc_type devtype;
+ struct pinmux *pmx;
struct esdhc_platform_data boarddata;
};
@@ -439,6 +441,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
struct clk *clk;
int err;
struct pltfm_imx_data *imx_data;
+ struct pinmux *pmx;
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
if (IS_ERR(host))
@@ -466,6 +469,16 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
clk_enable(clk);
pltfm_host->clk = clk;
+ pmx = pinmux_get(&pdev->dev, NULL);
+ if (IS_ERR(pmx)) {
+ err = PTR_ERR(pmx);
+ goto err_pmx_get;
+ }
+ err = pinmux_enable(pmx);
+ if (err)
+ goto err_pmx_enable;
+ imx_data->pmx = pmx;
+
if (!is_imx25_esdhc(imx_data))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -558,6 +571,10 @@ no_card_detect_irq:
gpio_free(boarddata->wp_gpio);
no_card_detect_pin:
no_board_data:
+ pinmux_disable(imx_data->pmx);
+err_pmx_enable:
+ pinmux_put(imx_data->pmx);
+err_pmx_get:
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
err_clk_get:
@@ -585,6 +602,9 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
gpio_free(boarddata->cd_gpio);
}
+ pinmux_disable(imx_data->pmx);
+ pinmux_put(imx_data->pmx);
+
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
kfree(imx_data);
--
1.7.0.4
For DT support, there's still one issue that for pinmux_map,
since it's board specific, i wonder if it can be parsed by pinctrl
subsystem via dt rather than by each driver.
but pinctrl still does not supported that, i still only called
it in mach-imx6q.c which seems not a correct place.
The patch still has a few other work to do like add pinconf, gpio support and
one know issue is that when add pinconf support, the trick that using pin->id
to calculate the reg offset may not work since pin config registers are not
layout regularly and we may find a better way to do that.
So it's mainly for discussion on the visiable issues.
Changes since v1:
* add a cover letter
* remove the pin functon and group defines out of driver
* parsing data from device tree for imx6q support
* a few minor fixes suggested by Shawn
Dong Aisheng (4):
dt: add of_get_child_number helper function
pinctrl: imx: add pinmux imx driver
ARM: imx6q: using pinmux subsystem
mmc: sdhci-esdhc-imx: using pinmux subsystem
arch/arm/boot/dts/imx6q-sabreauto.dts | 22 ++
arch/arm/boot/dts/imx6q.dtsi | 1 +
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/mach-imx6q.c | 8 +-
drivers/mmc/host/sdhci-esdhc-imx.c | 20 ++
drivers/pinctrl/Kconfig | 20 ++
drivers/pinctrl/Makefile | 3 +
drivers/pinctrl/pinmux-imx-core.c | 435 ++++++++++++++++++++++++++++++++
drivers/pinctrl/pinmux-imx-core.h | 86 +++++++
drivers/pinctrl/pinmux-imx53.c | 443 +++++++++++++++++++++++++++++++++
drivers/pinctrl/pinmux-imx6q.c | 433 ++++++++++++++++++++++++++++++++
include/linux/of.h | 17 ++
12 files changed, 1488 insertions(+), 1 deletions(-)
create mode 100644 drivers/pinctrl/pinmux-imx-core.c
create mode 100644 drivers/pinctrl/pinmux-imx-core.h
create mode 100644 drivers/pinctrl/pinmux-imx53.c
create mode 100644 drivers/pinctrl/pinmux-imx6q.c
> For DT support, there's still one issue that for pinmux_map,
> since it's board specific, i wonder if it can be parsed by pinctrl
> subsystem via dt rather than by each driver.
That is definately how it should be done. Seems like a good
idea to me.
> but pinctrl still does not supported that, i still only called
> it in mach-imx6q.c which seems not a correct place.
Don't worry that pinctrl does not support it - patch pinctrl core!
Just make a separate patch which patches drivers/pinctrl/pinmux.c
to ass the device tree parsing you need from the core, and we'll
review it.
I am by far too incompetent in device tree mechanisms to do
that myself, I have never worked much on device tree.
Thanks,
Linus Walleij
> From: Dong Aisheng <dong.a...@linaro.org>
>
> Signed-off-by: Shawn Guo <shaw...@linaro.org>
> Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
> Cc: Linus Walleij <linus....@linaro.org>
> Cc: Chris Ball <c...@laptop.org>
> Cc: Sascha Hauer <s.h...@pengutronix.de>
> Cc: Wolfram Sang <w.s...@pengutronix.de>
From a pinctrl point of view everything is fine so
Acked-by: Linus Walleij <linus....@linaro.org>
...but I know Sascha may still have issues with this patch.
Thanks,
Linus Walleij
> The driver contains the initial support for imx53 and
> imx6q.
Cool! Comments below...
> --- /dev/null
> +++ b/drivers/pinctrl/pinmux-imx-core.c
We should start naming these pinctrl-* rather than pinmux-*
so just rename it.
Until here it looks like business as usual..
Looks clever to me! And I think we have agreed that this probing
must be inside each driver.
Can we have a look at the corresponding device tree?
(...)
> +++ b/drivers/pinctrl/pinmux-imx-core.h
Name this pinctrl-* too for consistency.
(...)
> +#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
Now I start to think about the range generators I discussed with
Haojian... but there doesn't seem to be very many ranges in this
driver so I guess it would only confuse things.
> +#define IMX_PIN_GROUP(n, p, m) �\
> + � � � { � � � � � � � � � � � \
> + � � � � � � � .name = n, � � �\
> + � � � � � � � .pins = p, � � �\
> + � � � � � � � .num_pins = ARRAY_SIZE(p), � � �\
> + � � � � � � � .mux_mode = m, �\
> + � � � � � � � .num_mux = ARRAY_SIZE(m), � � � \
> + � � � }
> +
> +#define IMX_PMX_FUNC(n, g) �\
> + � � � { � � � � � � � � � � � \
> + � � � � � � � .name = n, � � �\
> + � � � � � � � .groups = g, � �\
> + � � � � � � � .num_groups = ARRAY_SIZE(g), � �\
> + � � � }
This looks pretty smart!
> +++ b/drivers/pinctrl/pinmux-imx53.c
Name this pinctrl-*
> diff --git a/drivers/pinctrl/pinmux-imx6q.c b/drivers/pinctrl/pinmux-imx6q.c
This too.
This patch is overall very good, we're quickly approaching merge quality.
Yours,
Linus Walleij
> From: Dong Aisheng <dong.a...@linaro.org>
>
> Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
> Cc: Linus Walleij <linus....@linaro.org>
> Cc: Sascha Hauer <s.h...@pengutronix.de>
> Cc: Shawn Guo <shan...@freescale.com>
Acked-by: Linus Walleij <linus....@linaro.org>
> +static struct pinmux_map imx6q_pinmux_map[] = {
> + � � � PINMUX_MAP_PRIMARY("usdhc4", "sd4", "219c000.usdhc"),
> +};
> +
> �static void __init imx6q_init_machine(void)
> �{
> � � � �of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
> -
> + � � � pinmux_register_mappings(imx6q_pinmux_map,
> + � � � � � � � � � � � � � � � �ARRAY_SIZE(imx6q_pinmux_map));
> � � � �imx6q_pm_init();
> �}
So ideally this bit of code should also go into the device tree
and we should add a DT hook inside drivers/pinctrl/pinmux.c
Please make a patch for this if you have a clear idea on how
it should work!
Yours,
Linus Walleij
On 12/14/2011 10:03 AM, Dong Aisheng wrote:
> From: Dong Aisheng <dong.a...@linaro.org>
>
> Currently most code to get child number in kernel are almost same,
> add a helper to implement this function for dt to use.
>
> Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
> Cc: Grant Likely <grant....@secretlab.ca>
> Cc: Rob Herring <rob.h...@calxeda.com>
> ---
> include/linux/of.h | 17 +++++++++++++++++
> 1 files changed, 17 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/of.h b/include/linux/of.h
> index 4948552..09d53dc 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -189,6 +189,18 @@ extern struct device_node *of_get_next_child(const struct device_node *node,
> for (child = of_get_next_child(parent, NULL); child != NULL; \
> child = of_get_next_child(parent, child))
>
> +static inline int of_get_child_number(struct device_node *np)
I would call this of_get_child_count instead.
Rob
Won't this break every i.MX except i.MX6?
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
I agree.
>
> Rob
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
... and binding documentation. While on that topic, the convention is
for property names to use dash '-' characters, not underscores '_'.
The properties I see here are using the later.
g.
>> + � � pmx = pinmux_get(&pdev->dev, NULL);
>> + � � if (IS_ERR(pmx)) {
>> + � � � � � � err = PTR_ERR(pmx);
>> + � � � � � � goto err_pmx_get;
>> + � � }
>> + � � err = pinmux_enable(pmx);
>> + � � if (err)
>> + � � � � � � goto err_pmx_enable;
>> + � � imx_data->pmx = pmx;
>> +
>
> Won't this break every i.MX except i.MX6?
Not this patch on its own, first the machines have to
select PINCTRL
select PINMUX_FOO
*Then* it will break :-D
So if you want to do this for i.MX you need something like
selectable dummy pinmuxes, i.e. pinmux_get() to return something
that just say "OK" to everything like the dummy regulators.
Shall I try to create something like that?
Yours,
Linus Walleij
Regards
Dong Aisheng
> Not this patch on its own, first the machines have to
> select PINCTRL
> select PINMUX_FOO
>
> *Then* it will break :-D
>
> So if you want to do this for i.MX you need something like
> selectable dummy pinmuxes, i.e. pinmux_get() to return something
> that just say "OK" to everything like the dummy regulators.
>
> Shall I try to create something like that?
>
Isn't the empty functions defined in include/linux/pinctrl/pinmux.h
for this purpose? It does not solve the problem with single image.
You might probably mean that we create a dummy_pinctrl_desc and register
it to pinctrl core with pinctrl_register() if we detect that the kernel
is running on a soc that has no pinctrl support?
This is not a problem to pinctrl migration only. We have the same
problem with common clk migration. Unless we migrate imx3, imx5 and
imx6 to common clk at the same time, single image build just does not
cope with clk_* api.
--
Regards,
Shawn
If not select PINCTRL, pinmux_enable returns ok by default and pinmux_get
Returns NULL which also does not block.
So it will not break other i.MX currently since only mx6q are using PINCTRL.
> Not this patch on its own, first the machines have to select PINCTRL
> select PINMUX_FOO
>
> *Then* it will break :-D
>
After we move to one single image for mx5 and mx6, it could be an issue
Since PINCTRL may be selected by default.
So mx5 pinmux driver is in my TODO list.
> So if you want to do this for i.MX you need something like selectable
> dummy pinmuxes, i.e. pinmux_get() to return something that just say "OK"
> to everything like the dummy regulators.
>
> Shall I try to create something like that?
>
For those platforms do not select PINCTRL, current code does not block.
For platforms do select PINCTRL but does not have pinmux driver ready,
for example, single image for both mx5&mx6,
IMHO it may be better to fix in driver to avoid introduce too much
complexity in pinctrl core.
Regards
Dong Aisheng
> > +#ifdef CONFIG_OF
> > +static int __devinit imx_pmx_parse_functions(struct device_node *np,
> > + � � � � � � � � � � � struct imx_pinctrl_info *info, u32 num) {
> > + sizeof(unsigned int),
> > + � � � � � � � � � � � � � � � GFP_KERNEL);
> > + � � � group->mux_mode = devm_kzalloc(info->dev, group->num_mux *
> > + sizeof(unsigned int),
> > + &function->name);
> > + � � � if (ret) {
> > + � � � � � � � dev_err(info->dev, "failed to get func_name\n");
> > + � � � � � � � return ret;
> > + � � � }
> > +
> > + � � � function->groups = devm_kzalloc(info->dev, sizeof(char **),
> > + GFP_KERNEL);
> > + � � � function->num_groups = 1;
> > + � � � function->groups[0] = group->name;
> > +
> > + � � � dev_dbg(info->dev, "func_name %s grp_name %s num_groups %d\n",
> > + � � � � � � � � � � � � � � � function->name, function->groups[0],
> > + � � � � � � � � � � � � � � � function->num_groups);
> > +
> > + � � � return 0;
> > +}
> > +
> > +static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
> > + � � � � � � � � � � � � � � � struct imx_pinctrl_info *info) {
> > + � � � struct device_node *np = pdev->dev.of_node;
> > + � � � struct device_node *child = NULL;
> > + � � � int ret, i;
> > + � � � u32 nfuncs = 0;
> > +
> > + � � � if (!np)
> > + � � � � � � � return -ENODEV;
> > +
> > + � � � nfuncs = of_get_child_number(np);
> > + � � � if (nfuncs <= 0) {
> > + � � � � � � � dev_err(&pdev->dev, "no functions defined\n");
> > + � � � � � � � return -EINVAL;
> > + � � � }
> > +
> > + � � � info->nfunctions = nfuncs;
> > + � � � info->functions = devm_kzalloc(&pdev->dev, nfuncs *
> > + sizeof(struct imx_pmx_func),
> > + � � � � � � � � � � � � � � � � � � � GFP_KERNEL);
> > + � � � if (!info->functions)
> > + � � � � � � � return -ENOMEM;
> > +
> > + � � � /* DT file only passes one group per one function */
> > + � � � info->ngroups = nfuncs;
> > + � � � info->groups = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct
> > + imx_pin_group),
> > + � � � � � � � � � � � � � � � � � � � GFP_KERNEL);
> > + � � � if (!info->groups)
> > + � � � � � � � return -ENOMEM;
> > +
> > + � � � child = NULL;
> > + � � � i = 0;
> > + � � � for_each_child_of_node(np, child) {
> > + � � � � � � � ret = imx_pmx_parse_functions(child, info, i++);
> > + � � � � � � � if (ret) {
> > + � � � � � � � � � � � dev_err(&pdev->dev, "failed to parse
> > + function\n");
> > + � � � � � � � � � � � return ret;
> > + � � � � � � � }
> > + � � � }
> > +
> > + � � � return 0;
> > +}
> > +#else
> > +static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
> > + � � � � � � � � � � � � � � � struct imx_pinctrl_info *info) {
> > + � � � return -ENODEV;
> > +}
> > +#endif
>
> Looks clever to me! And I think we have agreed that this probing must be
> inside each driver.
>
Yes.
> Can we have a look at the corresponding device tree?
> (...)
>
> > +++ b/drivers/pinctrl/pinmux-imx-core.h
>
> Name this pinctrl-* too for consistency.
>
> (...)
> > +#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
>
> Now I start to think about the range generators I discussed with
> Haojian... but there doesn't seem to be very many ranges in this driver
> so I guess it would only confuse things.
>
Yes, I was once also thinking about it when I first looked at the pinctrl,
one concern is that we have to use the id for pin group defines,
So not sure if it's suitable to generate pin id dynamically.
> > +#define IMX_PIN_GROUP(n, p, m) �\
> > + � � � { � � � � � � � � � � � \
> > + � � � � � � � .name = n, � � �\
> > + � � � � � � � .pins = p, � � �\
> > + � � � � � � � .num_pins = ARRAY_SIZE(p), � � �\
> > + � � � � � � � .mux_mode = m, �\
> > + � � � � � � � .num_mux = ARRAY_SIZE(m), � � � \
> > + � � � }
> > +
> > +#define IMX_PMX_FUNC(n, g) �\
> > + � � � { � � � � � � � � � � � \
> > + � � � � � � � .name = n, � � �\
> > + � � � � � � � .groups = g, � �\
> > + � � � � � � � .num_groups = ARRAY_SIZE(g), � �\
> > + � � � }
>
> This looks pretty smart!
>
> > +++ b/drivers/pinctrl/pinmux-imx53.c
>
> Name this pinctrl-*
>
> > diff --git a/drivers/pinctrl/pinmux-imx6q.c
> > b/drivers/pinctrl/pinmux-imx6q.c
>
> This too.
>
> This patch is overall very good, we're quickly approaching merge quality.
>
Will fix them all.
Thanks for the review.
Regards
Dong Aisheng
Regards
Dong Aisheng
> -----Original Message-----
> From: gli...@secretlab.ca [mailto:gli...@secretlab.ca] On Behalf Of
> Grant Likely
> Sent: Thursday, December 15, 2011 5:47 AM
> To: Linus Walleij
> Cc: Dong Aisheng-B29396; linux-...@vger.kernel.org; linux-arm-
> ker...@lists.infradead.org; linus....@stericsson.com;
> s.h...@pengutronix.de; Guo Shawn-R65073; ker...@pengutronix.de;
> rob.h...@calxeda.com
> Subject: Re: [RFC PATCH v2 2/4] pinctrl: imx: add pinmux imx driver
> Importance: High
>
> On Wed, Dec 14, 2011 at 11:00 AM, Linus Walleij <linus....@linaro.org>
> wrote:
> > On Wed, Dec 14, 2011 at 5:03 PM, Dong Aisheng <b29...@freescale.com>
> wrote:
> >
> >> The driver contains the initial support for imx53 and imx6q.
> >
> > Cool! Comments below...
> >
> >> --- /dev/null
> >> +++ b/drivers/pinctrl/pinmux-imx-core.c
> >
> > We should start naming these pinctrl-* rather than pinmux-* so just
> > rename it.
> >
> > Until here it looks like business as usual..
> >
> >> +#ifdef CONFIG_OF
> >> +static int __devinit imx_pmx_parse_functions(struct device_node *np,
> >> + � � � � � � � � � � � struct imx_pinctrl_info *info, u32 num) {
> >> + sizeof(unsigned int),
> >> + � � � � � � � � � � � � � � � GFP_KERNEL);
> >> + � � � group->mux_mode = devm_kzalloc(info->dev, group->num_mux *
> >> + sizeof(unsigned int),
> >> + &function->name);
> >> + � � � if (ret) {
> >> + � � � � � � � dev_err(info->dev, "failed to get func_name\n");
> >> + � � � � � � � return ret;
> >> + � � � }
> >> +
> >> + � � � function->groups = devm_kzalloc(info->dev, sizeof(char **),
> >> + GFP_KERNEL);
> >> + � � � function->num_groups = 1;
> >> + � � � function->groups[0] = group->name;
> >> +
> >> + � � � dev_dbg(info->dev, "func_name %s grp_name %s num_groups
> >> + %d\n",
> >> + � � � � � � � � � � � � � � � function->name, function->groups[0],
> >> + � � � � � � � � � � � � � � � function->num_groups);
> >> +
> >> + � � � return 0;
> >> +}
> >> +
> >> +static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
> >> + � � � � � � � � � � � � � � � struct imx_pinctrl_info *info) {
> >> + � � � struct device_node *np = pdev->dev.of_node;
> >> + � � � struct device_node *child = NULL;
> >> + � � � int ret, i;
> >> + � � � u32 nfuncs = 0;
> >> +
> >> + � � � if (!np)
> >> + � � � � � � � return -ENODEV;
> >> +
> >> + � � � nfuncs = of_get_child_number(np);
> >> + � � � if (nfuncs <= 0) {
> >> + � � � � � � � dev_err(&pdev->dev, "no functions defined\n");
> >> + � � � � � � � return -EINVAL;
> >> + � � � }
> >> +
> >> + � � � info->nfunctions = nfuncs;
> >> + � � � info->functions = devm_kzalloc(&pdev->dev, nfuncs *
> >> + sizeof(struct imx_pmx_func),
> >> + � � � � � � � � � � � � � � � � � � � GFP_KERNEL);
> >> + � � � if (!info->functions)
> >> + � � � � � � � return -ENOMEM;
> >> +
> >> + � � � /* DT file only passes one group per one function */
> >> + � � � info->ngroups = nfuncs;
> >> + � � � info->groups = devm_kzalloc(&pdev->dev, nfuncs *
> >> + sizeof(struct imx_pin_group),
> >> + � � � � � � � � � � � � � � � � � � � GFP_KERNEL);
> >> + � � � if (!info->groups)
> >> + � � � � � � � return -ENOMEM;
> >> +
> >> + � � � child = NULL;
> >> + � � � i = 0;
> >> + � � � for_each_child_of_node(np, child) {
> >> + � � � � � � � ret = imx_pmx_parse_functions(child, info, i++);
> >> + � � � � � � � if (ret) {
> >> + � � � � � � � � � � � dev_err(&pdev->dev, "failed to parse
> >> + function\n");
> >> + � � � � � � � � � � � return ret;
> >> + � � � � � � � }
> >> + � � � }
> >> +
> >> + � � � return 0;
> >> +}
> >> +#else
> >> +static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
> >> + � � � � � � � � � � � � � � � struct imx_pinctrl_info *info) {
> >> + � � � return -ENODEV;
> >> +}
> >> +#endif
> >
> > Looks clever to me! And I think we have agreed that this probing must
> > be inside each driver.
> >
> > Can we have a look at the corresponding device tree?
>
> ... and binding documentation. While on that topic, the convention is
> for property names to use dash '-' characters, not underscores '_'.
> The properties I see here are using the later.
>
Yes, will follow the convention and add binding doc.
Thanks for your suggestion.
Regards
Dong Aisheng
s/imx6q/imx53
> +
> +config PINMUX_IMX6Q
> + bool "IMX6Q pinmux driver"
> + depends on SOC_IMX6Q
> + select PINMUX
> + select PINMUX_IMX
> + help
> + Say Y here to enable the imx6q pinmux driver
> +
[...]
Since we can figure out the 'num_pins' here, why do we bother to
encode it in dts?
> + dev_err(info->dev, "wrong pins number?\n");
> + return -EINVAL;
> + }
> +
> + if (of_get_property(np, "grp_mux", &len) &&
> + len != group->num_mux * sizeof(unsigned int)) {
ditto
> + dev_err(info->dev, "wrong pin mux number?\n");
> + return -EINVAL;
> + }
--
Regards,
Shawn
> > +
> > +config PINMUX_IMX6Q
> > + bool "IMX6Q pinmux driver"
> > + depends on SOC_IMX6Q
> > + select PINMUX
> > + select PINMUX_IMX
> > + help
> > + Say Y here to enable the imx6q pinmux driver
> > +
>
> [...]
>
> > +#ifdef CONFIG_OF
> > +static int __devinit imx_pmx_parse_functions(struct device_node *np,
> > + struct imx_pinctrl_info *info, u32 num) {
Since the pin group is easily to define wrongly by mistake when pins are many,
I would add num_pins in dts to double check in driver to improve the code
Stability.
No, these are for compiling it *out*, dummy pinmuxes would
be if you compile it *in*, but don't find an apropriate pinmux,
you still get something that does nothing and still works.
Dummy regulators work exactly this way.
> It does not solve the problem with single image.
I think it does.
> You might probably mean that we create a dummy_pinctrl_desc and register
> it to pinctrl core with pinctrl_register() if we detect that the kernel
> is running on a soc that has no pinctrl support?
No. You have a #ifdef CONFIG_PINMUX_DUMMY in pinmux_get()
that makes sure you return a working no-op pinmux handle even
though there is no real pinmux behind it.
> This is not a problem to pinctrl migration only. �We have the same
> problem with common clk migration. �Unless we migrate imx3, imx5 and
> imx6 to common clk at the same time, single image build just does not
> cope with clk_* api.
And you could have the same problem with regulator migration...
Luckily dummy regulators saves you in that case.
Thanks,
Linus Walleij
Yeah I know...
> For platforms do select PINCTRL but does not have pinmux driver ready,
> for example, single image for both mx5&mx6,
> IMHO it may be better to fix in driver to avoid introduce too much
> complexity in pinctrl core.
If you mean that you fix the i.MX driver for all the combines i.MX variants
then I agree.
If you mean to do stuff like allow the code to continue even if the pinmux
isn't found - no. That is not the way we proceed with clocks and
regulators as Mark has taught me recently, so for consistency we
need to error out if no pinmux is found.
Thanks,
Linus Walleij
> > This is not a problem to pinctrl migration only. �We have the same
> > problem with common clk migration. �Unless we migrate imx3, imx5 and
> > imx6 to common clk at the same time, single image build just does not
> > cope with clk_* api.
>
> And you could have the same problem with regulator migration...
> Luckily dummy regulators saves you in that case.
>
Not sure what will save me in common clk case though.
--
Regards,
Shawn
> If you mean to do stuff like allow the code to continue even if the
> pinmux isn't found - no. That is not the way we proceed with clocks and
> regulators as Mark has taught me recently, so for consistency we need to
> error out if no pinmux is found.
>
Regards
Dong Aisheng
I did not read the dummy regulator code too much.
But does it mean that the dummy regulator or dummy pinmux will also hide the
Real errors since it will always get a available one?
How do we distinguish between the two case(real error and fake error)?
Add i.MX3 which is compiled together with i.MX6 :)
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
We don't :(
That's the problem with the dummy regulator.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Regards
Dong Aisheng
What do you mean 'real error'? When driver calls pimnux api on a
platform with real pinmux support, the error is error. When driver
calls pinmux api on a platform support with dummy pinmux, it's totally
error free, as the pinmux core will ensure all the pinmux_* calls
always return success.
> > How do we distinguish between the two case(real error and fake error)?
>
What do we need to distinguish between two cases? The real success for
real pinmux from the fake success for the dummy pinmux? It does not
really matter.
> We don't :(
>
> That's the problem with the dummy regulator.
>
What is the problem exactly? I do not quite understand.
--
Regards,
Shawn
I just did a quick look at the regulator code and got this understanding,
please let me know if I understood wrong.
So i.MX3/5 people must know that it's safe to ignore this message
whereas i.MX6 people must know there's something wrong Adding messages
saying "there might or might not be something wrong" is not good.
People will frequently ask on the mailing list about these messages.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Anyway, it's not a problem to me. I have seen similar messages on my
kernel serial output. I fail to see why pinmux can not do something
that other subsystems are doing.
--
Regards,
Shawn
So we as developers have to figure out ourselves what can go wrong and
the users, well who cares about users?
>
> Anyway, it's not a problem to me. I have seen similar messages on my
> kernel serial output. I fail to see why pinmux can not do something
> that other subsystems are doing.
Yes, and everytime I see such a message I dig through the sourcecode
trying to find out if that's important or not. That's easy for me on
the systems I work with, but on my PC I am only a user, and honestly
on my PC I *want* to be only a user.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
BTW, I did not mean to leave imx3 and imx5 there forever, but mean,
with the dummy pinmux support, we do not have to strictly migrate imx3,
imx5 and imx6 all at the same time.
--
Regards,
Shawn
I'm afraid your plans for i.MX3/5 clash with Freescale's i.MX7
release...
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Change v2->v3:
- change the name from of_get_child_number to of_get_child_count
- pinctrl: add dt binding support for pinmux mappings
- Add phandle for pinmux mappings for imx6q
- binding pinmux mappings via pinctrl core API
- follow the dt convention to use dash '-' for property name
Changes v1->v2:
- add a cover letter
- remove the pin functon and group defines out of driver
- parsing data from device tree for imx6q support
- a few minor fixes suggested by Shawn
Dong Aisheng (5):
dt: add of_get_child_count helper function
pinctrl: add dt binding support for pinmux mappings
pinctrl: imx: add pinctrl imx driver
ARM: imx6q: using pinmux subsystem
mmc: sdhci-esdhc-imx: using pinmux subsystem
.../devicetree/bindings/pinctrl/pinctrl-imx.txt | 59 +++
.../devicetree/bindings/pinctrl/pinctrl.txt | 33 ++
arch/arm/boot/dts/imx6q-sabreauto.dts | 32 ++
arch/arm/boot/dts/imx6q.dtsi | 1 +
arch/arm/mach-imx/Kconfig | 1 +
drivers/mmc/host/sdhci-esdhc-imx.c | 20 +
drivers/pinctrl/Kconfig | 20 +
drivers/pinctrl/Makefile | 3 +
drivers/pinctrl/pinctrl-imx-core.c | 450 ++++++++++++++++++++
drivers/pinctrl/pinctrl-imx-core.h | 86 ++++
drivers/pinctrl/pinctrl-imx53.c | 443 +++++++++++++++++++
drivers/pinctrl/pinctrl-imx6q.c | 433 +++++++++++++++++++
drivers/pinctrl/pinmux.c | 101 +++++
include/linux/of.h | 16 +
include/linux/pinctrl/machine.h | 6 +
15 files changed, 1704 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-imx.txt
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl.txt
create mode 100644 drivers/pinctrl/pinctrl-imx-core.c
create mode 100644 drivers/pinctrl/pinctrl-imx-core.h
create mode 100644 drivers/pinctrl/pinctrl-imx53.c
create mode 100644 drivers/pinctrl/pinctrl-imx6q.c
Currently most code to get child count in kernel are almost same,
add a helper to implement this function for dt to use.
---
Changes v1->v2:
* change the name from of_get_child_number to of_get_child_count
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Grant Likely <grant....@secretlab.ca>
Cc: Rob Herring <rob.h...@calxeda.com>
---
include/linux/of.h | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/include/linux/of.h b/include/linux/of.h
index 4948552..d0d91a1 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -189,6 +189,17 @@ extern struct device_node *of_get_next_child(const struct device_node *node,
for (child = of_get_next_child(parent, NULL); child != NULL; \
child = of_get_next_child(parent, child))
+static inline int of_get_child_count(const struct device_node *np)
+{
+ struct device_node *child = NULL;
+ int num = 0;
+
+ while ((child = of_get_next_child(np, child)))
+ num++;
+
+ return num;
+}
+
extern struct device_node *of_find_node_with_property(
struct device_node *from, const char *prop_name);
#define for_each_node_with_property(dn, prop_name) \
@@ -262,6 +273,11 @@ static inline bool of_have_populated_dt(void)
#define for_each_child_of_node(parent, child) \
while (0)
+static inline int of_get_child_count(const struct device_node *np)
+{
+ return -ENOSYS;
+}
+
static inline int of_device_is_compatible(const struct device_node *device,
const char *name)
{
--
1.7.0.4
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Linus Walleij <linus....@linaro.org>
Cc: Sascha Hauer <s.h...@pengutronix.de>
Cc: Shawn Guo <shan...@freescale.com>
Cc: Grant Likely <grant....@secretlab.ca>
Cc: Rob Herring <rob.h...@calxeda.com>
---
ChangeLog v2->v3:
- Add phandle for pinmux mappings
- follow DT convention to use dash '-' for property name
ChangeLog v1->v2:
- Add basic binding for pinmux pins
---
arch/arm/boot/dts/imx6q-sabreauto.dts | 32 ++++++++++++++++++++++++++++++++
arch/arm/boot/dts/imx6q.dtsi | 1 +
arch/arm/mach-imx/Kconfig | 1 +
3 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/imx6q-sabreauto.dts b/arch/arm/boot/dts/imx6q-sabreauto.dts
index 072974e..c3e9070 100644
--- a/arch/arm/boot/dts/imx6q-sabreauto.dts
+++ b/arch/arm/boot/dts/imx6q-sabreauto.dts
@@ -25,7 +25,39 @@
reg = <0x10000000 0x80000000>;
};
+ pinmux: imx6q-sabreauto-map {
+ map-sd4 {
+ map-name = "usdhc4";
+ ctrl-dev-name = "20e0000.iomuxc";
+ function = "sd4";
+ dev-name = "219c000.usdhc";
+ };
+ };
+
soc {
+ aips-bus@02000000 { /* AIPS1 */
+ iomuxc@020e0000 {
+ fsl,pinmux-map = <&pinmux>;
+ pinmux-uart4 {
+ func-name = "uart4";
+ grp-name = "uart4grp";
+ grp-pins = <107 108>;
+ num-pins = <2>;
+ grp-mux = <4 4>;
+ num-mux = <2>;
+ };
+
+ pinmux-sd4 {
+ func-name = "sd4";
+ grp-name = "sd4grp";
+ grp-pins = <170 171 180 181 182 183 184 185 186 187>;
+ num-pins = <10>;
+ grp-mux = <0 0 1 1 1 1 1 1 1 1>;
+ num-mux = <10>;
+ };
+ };
+ };
+
aips-bus@02100000 { /* AIPS2 */
enet@02188000 {
phy-mode = "rgmii";
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 7dda599..42499bb 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -386,6 +386,7 @@
};
iomuxc@020e0000 {
+ compatible = "fsl,imx6q-iomuxc";
reg = <0x020e0000 0x4000>;
};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 5f7f9c2..d6a88fe 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -615,6 +615,7 @@ config SOC_IMX6Q
select HAVE_IMX_GPC
select HAVE_IMX_MMDC
select HAVE_IMX_SRC
+ select PINCTRL
select USE_OF
help
--
1.7.0.4
This patch provies a common API for driver to use to register pinmux
mappings from dts file. It is needed for dt support.
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Linus Walleij <linus....@linaro.org>
Cc: Grant Likely <grant....@secretlab.ca>
Cc: Rob Herring <rob.h...@calxeda.com>
---
.../devicetree/bindings/pinctrl/pinctrl.txt | 33 +++++++
drivers/pinctrl/pinmux.c | 101 ++++++++++++++++++++
include/linux/pinctrl/machine.h | 6 +
3 files changed, 140 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl.txt
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl.txt
new file mode 100644
index 0000000..a27a7ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl.txt
@@ -0,0 +1,33 @@
+The pin control subsystem
+
+The pin control subsystem provides a common API to support parsing pinmux
+mappings data from device tree. Each board dts file should provide a device
+node of which all the child nodes are the corresponding pinmux mappings.
+
+The required properties for pinmux mapping are:
+- map-name: the name of this specific map entry
+- clk-dev-name: the name of the device controlling this specific mapping
+- funcion: a function in the driver to use for this mapping
+
+Optional properties:
+- group: a certain specific pin group to activate for the function
+- dev-name: the name of the device using this specific mapping
+- hog-on-boot: indicate wether hog the mappings(do not need to specify value)
+
+Examples:
+
+pinmux: imx6q-sabreauto-map {
+ map-sd4 {
+ map-name = "usdhc4";
+ ctrl-dev-name = "20e0000.iomuxc";
+ function = "sd4";
+ dev-name = "219c000.usdhc";
+ };
+ ...
+};
+
+Then calling pinmux_of_register_mappings() with the device node of
+imx6q-sabreauto-map as parameter to register pinmux mappings from dts.
+
+Usually user can get this device node via a phandle in driver then call
+the function to register maps. Please refer to pinctrl-imx.txt for example.
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 432feb6..3ac3098 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/sysfs.h>
@@ -410,6 +411,106 @@ int __init pinmux_register_mappings(struct pinmux_map const *maps,
return 0;
}
+static int __devinit pinmux_of_parse_mapping(struct device_node *np,
+ struct pinmux_map *maps, unsigned id)
+{
+ struct pinmux_map *map = &maps[id];
+ int ret = 0;
+
+ pr_debug("parse pinmux map %d\n", id + 1);
+
+ if (of_find_property(np, "map-name", NULL)) {
+ ret = of_property_read_string(np, "map-name", &map->name);
+ if (ret) {
+ pr_err("failed to get map-name");
+ return ret;
+ }
+ }
+
+ if (of_find_property(np, "ctrl-dev-name", NULL)) {
+ ret = of_property_read_string(np, "ctrl-dev-name",
+ &map->ctrl_dev_name);
+ if (ret) {
+ pr_err("failed to get ctrl-dev-name");
+ return ret;
+ }
+ }
+
+ if (of_find_property(np, "function", NULL)) {
+ ret = of_property_read_string(np, "function", &map->function);
+ if (ret) {
+ pr_err("failed to get function");
+ return ret;
+ }
+ }
+
+ if (of_find_property(np, "group", NULL)) {
+ ret = of_property_read_string(np, "group", &map->group);
+ if (ret) {
+ pr_err("failed to get group");
+ return ret;
+ }
+ }
+
+ if (of_find_property(np, "dev-name", NULL)) {
+ ret = of_property_read_string(np, "dev-name", &map->dev_name);
+ if (ret) {
+ pr_err("failed to get dev-name");
+ return ret;
+ }
+ }
+
+ if (of_find_property(np, "hog-on-boot", NULL))
+ map->hog_on_boot = true;
+
+ pr_debug("map-name: %s ctrl-dev-name: %s function: %s group: %s dev-name: %s hog-on-boot: %d\n",
+ map->name, map->ctrl_dev_name, map->function,
+ map->group, map->dev_name, map->hog_on_boot);
+
+ return 0;
+}
+
+/**
+ * pinmux_of_register_mappings() - parse and register pinmux mappings from dt
+ * &np: a device node containing pinmux map properties
+ *
+ * Like pinmux_register_mappings(), the memory of pinmux maps are owned by
+ * pinctrl core and can not be freed.
+ */
+int __devinit pinmux_of_register_mappings(struct device_node *np)
+{
+ struct pinmux_map *maps;
+ struct device_node *child = NULL;
+ int count, i;
+ int ret;
+
+ pr_debug("parse pinmux maps from device node %s\n", np->name);
+
+ if (!np)
+ return -EINVAL;
+
+ count = of_get_child_count(np);
+ if (!count) {
+ pr_err("no available pinmux maps found\n");
+ return -EINVAL;
+ }
+
+ maps = kzalloc(count * sizeof(struct pinmux_map), GFP_KERNEL);
+ if (!maps)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_child_of_node(np, child) {
+ ret = pinmux_of_parse_mapping(child, maps, i++);
+ if (ret) {
+ pr_err("failed to parse pinmux map\n");
+ return ret;
+ }
+ }
+
+ return pinmux_register_mappings(maps, count);
+}
+
/**
* acquire_pins() - acquire all the pins for a certain funcion on a pinmux
* @pctldev: the device to take the pins on
diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
index ad430e0..74a695d 100644
--- a/include/linux/pinctrl/machine.h
+++ b/include/linux/pinctrl/machine.h
@@ -78,6 +78,7 @@ struct pinmux_map {
extern int pinmux_register_mappings(struct pinmux_map const *map,
unsigned num_maps);
+extern int pinmux_of_register_mappings(struct device_node *np);
#else
static inline int pinmux_register_mappings(struct pinmux_map const *map,
@@ -86,5 +87,10 @@ static inline int pinmux_register_mappings(struct pinmux_map const *map,
return 0;
}
+static inline int pinmux_of_register_mappings(struct device_node *np)
+{
+ return 0;
+}
+
#endif /* !CONFIG_PINMUX */
#endif
--
1.7.0.4
The driver contains the initial support for imx53 and
imx6q.
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Linus Walleij <linus....@linaro.org>
Cc: Sascha Hauer <s.h...@pengutronix.de>
Cc: Shawn Guo <shan...@freescale.com>
Cc: Grant Likely <grant....@secretlab.ca>
Cc: Rob Herring <rob.h...@calxeda.com>
---
ChangeLog v2->v3:
- binding pinmux mappings via pinctrl core API
- follow the dt convention to use dash '-' for property name
ChangeLog v1->v2:
- add basic binding from device tree
---
.../devicetree/bindings/pinctrl/pinctrl-imx.txt | 59 +++
drivers/pinctrl/Kconfig | 20 +
drivers/pinctrl/Makefile | 3 +
drivers/pinctrl/pinctrl-imx-core.c | 450 ++++++++++++++++++++
drivers/pinctrl/pinctrl-imx-core.h | 86 ++++
drivers/pinctrl/pinctrl-imx53.c | 443 +++++++++++++++++++
drivers/pinctrl/pinctrl-imx6q.c | 433 +++++++++++++++++++
7 files changed, 1494 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-imx.txt
create mode 100644 drivers/pinctrl/pinctrl-imx-core.c
create mode 100644 drivers/pinctrl/pinctrl-imx-core.h
create mode 100644 drivers/pinctrl/pinctrl-imx53.c
create mode 100644 drivers/pinctrl/pinctrl-imx6q.c
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-imx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-imx.txt
new file mode 100644
index 0000000..e45d745
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-imx.txt
@@ -0,0 +1,59 @@
+* Freescale IOMUX Controller (IOMUXC) for i.MX
+
+The IOMUX Controller (IOMUXC), together with the IOMUX, enables the IC
+to share one PAD to several functional blocks. The sharing is done by
+multiplexing the PAD input/output signals. For each PAD there are up to
+8 muxing options (called ALT modes). Since different modules require
+different PAD settings (like pull up, keeper, etc) the IOMUXC controls
+also the PAD settings parameters.
+
+Required properties:
+- compatible : Should be "fsl,<chip>-iomuxc"
+- reg : Should contain IOMUXC registers location and length
+- fsl,pinmux-map: phandle of pinmux mappings. Refer to pinctrl.txt for
+ detailed format.
+- child nodes containing pinmux data
+ Each child node corresponds to a specific pinmux function and the required
+ properties of the pinmux function are:
+ - func-name: the name of a specific function
+ - grp-name: the name of a group pins correspding to this function
+ - grp-pins: the list of pins for the group of grp-name
+ - num-pins: the pins number of grp-pins list
+ - grp-mux: the corresponding mux mode list for grp-pins.
+ Each pin in the grp-pins should have a corresponding mux mode for the
+ specific function of func-name.
+ - num-numx: the mux number of grp-mux list
+
+Examples:
+
+pinmux: imx6q-sabreauto-map {
+ map-sd4 {
+ map-name = "usdhc4";
+ ctrl-dev-name = "20e0000.iomuxc";
+ function = "sd4";
+ dev-name = "219c000.usdhc";
+ };
+};
+
+iomuxc@020e0000 {
+ compatible = "fsl,imx6q-iomuxc";
+ reg = <0x020e0000 0x4000>;
+ fsl,pinmux-map = <&pinmux>;
+ pinmux_uart4 {
+ func-name = "uart4";
+ grp-name = "uart4grp";
+ grp-pins = <107 108>;
+ num-pins = <2>;
+ grp-mux = <4 4>;
+ num-mux = <2>;
+ };
+
+ pinmux_sd4 {
+ func-name = "sd4";
+ grp-name = "sd4grp";
+ grp-pins = <170 171 180 181 182 183 184 185 186 187>;
+ num-pins = <10>;
+ grp-mux = <0 0 1 1 1 1 1 1 1 1>;
+ num-mux = <10>;
+ };
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c63c721..f65bf5a 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -23,6 +23,26 @@ config DEBUG_PINCTRL
help
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+config PINCTRL_IMX
+ bool "Freescale IMX core pinctrl driver"
+ depends on ARCH_MXC
+
+config PINCTRL_IMX53
+ bool "IMX53 pinctrl driver"
+ depends on SOC_IMX53
+ select PINMUX
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx53 pinctrl driver
+
+config PINCTRL_IMX6Q
+ bool "IMX6Q pinctrl driver"
+ depends on SOC_IMX6Q
+ select PINMUX
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx6q pinctrl driver
+
config PINMUX_SIRF
bool "CSR SiRFprimaII pinmux driver"
depends on ARCH_PRIMA2
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c046f78..cf85edc 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -5,6 +5,9 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
obj-$(CONFIG_PINCTRL) += core.o
obj-$(CONFIG_PINMUX) += pinmux.o
obj-$(CONFIG_PINCONF) += pinconf.o
+obj-$(CONFIG_PINMUX_IMX) += pinmux-imx-core.o
+obj-$(CONFIG_PINMUX_IMX53) += pinmux-imx53.o
+obj-$(CONFIG_PINMUX_IMX6Q) += pinmux-imx6q.o
obj-$(CONFIG_PINMUX_SIRF) += pinmux-sirf.o
obj-$(CONFIG_PINMUX_U300) += pinmux-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
diff --git a/drivers/pinctrl/pinctrl-imx-core.c b/drivers/pinctrl/pinctrl-imx-core.c
new file mode 100644
index 0000000..5c348ba
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx-core.c
@@ -0,0 +1,450 @@
+/*
+ * Core driver for the imx pin controller
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/slab.h>
+
+#include "pinctrl-imx-core.h"
+
+#define DRIVER_NAME "pinmux-imx"
+
+/**
+ * @dev: a pointer back to containing device
+ * @virtbase: the offset to the controller in virtual memory
+ */
+struct imx_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ void __iomem *virtbase;
+ struct imx_pinctrl_info *info;
+};
+
+#define IMX_PINCTRL_REG_SIZE 4
+#define IMX_PINCTRL_MAX_FUNC 7
+
+static int imx_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const char *imx_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->ngroups)
+ return NULL;
+
+ return info->groups[selector].name;
+}
+
+static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ *pins = info->groups[selector].pins;
+ *num_pins = info->groups[selector].num_pins;
+
+ return 0;
+}
+
+static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, " " DRIVER_NAME);
+}
+
+static struct pinctrl_ops imx_pctrl_ops = {
+ .list_groups = imx_list_groups,
+ .get_group_name = imx_get_group_name,
+ .get_group_pins = imx_get_group_pins,
+ .pin_dbg_show = imx_pin_dbg_show,
+};
+
+static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+ const unsigned *pins, *mux;
+ unsigned int num_pins, num_mux;
+ u32 regval, offset;
+ int i;
+
+ /*
+ * Configure the mux mode for each pin in the group for a specific
+ * function.
+ */
+ pins = info->groups[group].pins;
+ num_pins = info->groups[group].num_pins;
+ mux = info->groups[group].mux_mode;
+ num_mux = info->groups[group].num_mux;
+
+ dev_dbg(ipmx->dev, "function %s group %s\n",
+ info->functions[selector].name, info->groups[group].name);
+
+ if (num_pins != num_mux) {
+ dev_err(ipmx->dev, "num_mux is not equal to num_pins\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_pins; i++) {
+ if (mux[i] > IMX_PINCTRL_MAX_FUNC)
+ dev_err(ipmx->dev, "exceeds the maximum mux mode(0x7)\n");
+ offset = info->mux_offset + pins[i] * IMX_PINCTRL_REG_SIZE;
+ regval = readl(ipmx->virtbase + offset);
+ regval &= ~IMX_PINCTRL_MAX_FUNC;
+ writel(mux[i] | regval, ipmx->virtbase + offset);
+ dev_dbg(ipmx->dev, "write: offset 0x%x val 0x%x\n",
+ offset, regval | mux[i]);
+ }
+
+ return 0;
+}
+
+static void imx_pmx_disable(struct pinctrl_dev *pctldev, unsigned func_selector,
+ unsigned group_selector)
+{
+ /* nothing to do here */
+}
+
+static int imx_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ if (selector >= info->nfunctions)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ return info->functions[selector].name;
+}
+
+static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct imx_pmx *ipmx = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_info *info = ipmx->info;
+
+ *groups = info->functions[selector].groups;
+ *num_groups = info->functions[selector].num_groups;
+
+ return 0;
+}
+
+static struct pinmux_ops imx_pmx_ops = {
+ .list_functions = imx_pmx_list_funcs,
+ .get_function_name = imx_pmx_get_func_name,
+ .get_function_groups = imx_pmx_get_groups,
+ .enable = imx_pmx_enable,
+ .disable = imx_pmx_disable,
+};
+
+static struct pinctrl_desc imx_pmx_desc = {
+ .name = DRIVER_NAME,
+ .pctlops = &imx_pctrl_ops,
+ .pmxops = &imx_pmx_ops,
+ .owner = THIS_MODULE,
+};
+
+#ifdef CONFIG_OF
+static int __devinit imx_pmx_parse_functions(struct device_node *np,
+ struct imx_pinctrl_info *info, u32 num)
+{
+ struct imx_pmx_func *function;
+ struct imx_pin_group *group;
+ int ret, len;
+
+ dev_dbg(info->dev, "parse function %d\n", num);
+
+ group = &info->groups[num];
+ function = &info->functions[num];
+
+ /* Initialise group */
+ ret = of_property_read_string(np, "grp-name", &group->name);
+ if (ret) {
+ dev_err(info->dev, "failed to get grp-name\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "num-pins", &group->num_pins);
+ if (ret) {
+ dev_err(info->dev, "failed to get num-pins\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "num-mux", &group->num_mux);
+ if (ret) {
+ dev_err(info->dev, "failed to get num-mux\n");
+ return ret;
+ }
+
+ if (group->num_pins != group->num_mux)
+ return -EINVAL;
+
+ group->pins = devm_kzalloc(info->dev, group->num_pins * sizeof(unsigned int),
+ GFP_KERNEL);
+ group->mux_mode = devm_kzalloc(info->dev, group->num_mux * sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!group->pins || !group->mux_mode)
+ return -ENOMEM;
+
+ /* sanity check */
+ if (of_get_property(np, "grp-pins", &len) &&
+ len != group->num_pins * sizeof(unsigned int)) {
+ dev_err(info->dev, "wrong pins number?\n");
+ return -EINVAL;
+ }
+
+ if (of_get_property(np, "grp-mux", &len) &&
+ len != group->num_mux * sizeof(unsigned int)) {
+ dev_err(info->dev, "wrong pin mux number?\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(np, "grp-pins",
+ group->pins, group->num_pins);
+ if (ret) {
+ dev_err(info->dev, "failed to get grp-pins\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32_array(np, "grp-mux",
+ group->mux_mode, group->num_mux);
+ if (ret) {
+ dev_err(info->dev, "failed to get grp-mux\n");
+ return ret;
+ }
+
+ /* Initialise function */
+ ret = of_property_read_string(np, "func-name", &function->name);
+ if (ret) {
+ dev_err(info->dev, "failed to get func-name\n");
+ return ret;
+ }
+
+ function->groups = devm_kzalloc(info->dev, sizeof(char **), GFP_KERNEL);
+ function->num_groups = 1;
+ function->groups[0] = group->name;
+
+ dev_dbg(info->dev, "func-name %s grp-name %s num-groups %d\n",
+ function->name, function->groups[0],
+ function->num_groups);
+
+ return 0;
+}
+
+static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
+ struct imx_pinctrl_info *info)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child = NULL;
+ struct device_node *map_np;
+ int ret, i;
+ u32 nfuncs = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ nfuncs = of_get_child_count(np);
+ if (nfuncs <= 0) {
+ dev_err(&pdev->dev, "no functions defined\n");
+ return -EINVAL;
+ }
+
+ info->nfunctions = nfuncs;
+ info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),
+ GFP_KERNEL);
+ if (!info->functions)
+ return -ENOMEM;
+
+ /* DT file only passes one group per one function */
+ info->ngroups = nfuncs;
+ info->groups = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pin_group),
+ GFP_KERNEL);
+ if (!info->groups)
+ return -ENOMEM;
+
+ child = NULL;
+ i = 0;
+ for_each_child_of_node(np, child) {
+ ret = imx_pmx_parse_functions(child, info, i++);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse function\n");
+ return ret;
+ }
+ }
+
+ /* parse pinmux map */
+ map_np = of_parse_phandle(np, "fsl,pinmux-map", 0);
+ if (!map_np) {
+ dev_err(&pdev->dev, "failed to parse phandle fsl,pinmux-map\n");
+ return -EINVAL;
+ }
+
+ ret = pinmux_of_register_mappings(map_np);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register pinmux mappings\n");
+ return ret;
+ }
+
+ return 0;
+}
+#else
+static int __devinit imx_pmx_probe_dt(struct platform_device *pdev,
+ struct imx_pinctrl_info *info)
+{
+ return -ENODEV;
+}
+#endif
+
+static inline void imx_pmx_desc_init(struct pinctrl_desc *pmx_desc,
+ const struct imx_pinctrl_info *info)
+{
+ pmx_desc->pins = info->pins;
+ pmx_desc->npins = info->npins;
+ pmx_desc->maxpin = info->maxpin;
+}
+
+static const struct of_device_id imx_pmx_dt_ids[] = {
+#ifdef CONFIG_PINMUX_IMX6Q
+ { .compatible = "fsl,imx6q-iomuxc", .data = (void *) &imx6q_pinctrl_info, },
+#endif
+#ifdef CONFIG_PINMUX_IMX53
+ { .compatible = "fsl,imx53-iomuxc", .data = (void *) &imx53_pinctrl_info, },
+#endif
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pmx_dt_ids);
+
+static int __init imx_pmx_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(imx_pmx_dt_ids, &pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct imx_pmx *ipmx;
+ struct resource *res;
+ struct imx_pinctrl_info *info;
+ resource_size_t res_size;
+ int ret;
+
+ info = of_id->data;
+ if (!info || !info->pins || !(info->maxpin > info->npins)) {
+ dev_err(&pdev->dev, "wrong pinctrl info\n");
+ return -EINVAL;
+ }
+ info->dev = &pdev->dev;
+
+ /* Create state holders etc for this driver */
+ ipmx = devm_kzalloc(&pdev->dev, sizeof(*ipmx), GFP_KERNEL);
+ if (!ipmx)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ res_size = resource_size(res);
+ if (!devm_request_mem_region(dev, res->start, res_size, res->name))
+ return -EBUSY;
+
+ ipmx->virtbase = devm_ioremap_nocache(dev, res->start, res_size);
+ if (!ipmx->virtbase)
+ return -EBUSY;
+
+ imx_pmx_desc_init(&imx_pmx_desc, info);
+ ret = imx_pmx_probe_dt(pdev, info);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to probe dt properties\n");
+ return ret;
+ }
+
+ ipmx->pctl = pinctrl_register(&imx_pmx_desc, &pdev->dev, ipmx);
+ if (!ipmx->pctl) {
+ dev_err(&pdev->dev, "could not register IMX pinmux driver\n");
+ return -EINVAL;
+ }
+
+ ipmx->info = info;
+ ipmx->dev = info->dev;
+ platform_set_drvdata(pdev, ipmx);
+
+ dev_info(&pdev->dev, "initialized IMX pinmux driver\n");
+
+ return 0;
+}
+
+static int __exit imx_pmx_remove(struct platform_device *pdev)
+{
+ struct imx_pmx *ipmx = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(ipmx->pctl);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver imx_pmx_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = imx_pmx_dt_ids,
+ },
+ .remove = __exit_p(imx_pmx_remove),
+};
+
+static int __init imx_pmx_init(void)
+{
+ return platform_driver_probe(&imx_pmx_driver, imx_pmx_probe);
+}
+arch_initcall(imx_pmx_init);
+
+static void __exit imx_pmx_exit(void)
+{
+ platform_driver_unregister(&imx_pmx_driver);
+}
+module_exit(imx_pmx_exit);
+
+MODULE_AUTHOR("Dong Aisheng <dong.a...@linaro.org>");
+MODULE_DESCRIPTION("IMX Pin Control Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-imx-core.h b/drivers/pinctrl/pinctrl-imx-core.h
new file mode 100644
index 0000000..df69cd0
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx-core.h
@@ -0,0 +1,86 @@
+/*
+ * IMX pinmux core definitions
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __DRIVERS_PINCTRL_PINMUX_IMX_H
+#define __DRIVERS_PINCTRL_PINMUX_IMX_H
+
+/* Supported Pinctrl type */
+enum imx_pinctrl_type {
+ IMX53_PINCTRL,
+ IMX6Q_PINCTRL,
+};
+
+/**
+ * struct imx_pin_group - describes an IMX pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ * @mux_mode: the mux mode for each pins in this group. The size of this
+ * array is the same as pins.
+ */
+struct imx_pin_group {
+ const char *name;
+ unsigned int *pins;
+ unsigned num_pins;
+ unsigned int *mux_mode;
+ unsigned num_mux;
+};
+
+/**
+ * struct imx_pmx_func - describes IMX pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ */
+struct imx_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned num_groups;
+};
+
+struct imx_pinctrl_info {
+ struct device *dev;
+ u32 type;
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ unsigned int maxpin;
+ struct imx_pin_group *groups;
+ unsigned int ngroups;
+ struct imx_pmx_func *functions;
+ unsigned int nfunctions;
+ u32 mux_offset;
+};
+
+#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
+
+#define IMX_PIN_GROUP(n, p, m) \
+ { \
+ .name = n, \
+ .pins = p, \
+ .num_pins = ARRAY_SIZE(p), \
+ .mux_mode = m, \
+ .num_mux = ARRAY_SIZE(m), \
+ }
+
+#define IMX_PMX_FUNC(n, g) \
+ { \
+ .name = n, \
+ .groups = g, \
+ .num_groups = ARRAY_SIZE(g), \
+ }
+
+extern struct imx_pinctrl_info imx53_pinctrl_info;
+extern struct imx_pinctrl_info imx6q_pinctrl_info;
+#endif /* __DRIVERS_PINCTRL_PINMUX_IMX_H */
diff --git a/drivers/pinctrl/pinctrl-imx53.c b/drivers/pinctrl/pinctrl-imx53.c
new file mode 100644
index 0000000..079b25e
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx53.c
@@ -0,0 +1,443 @@
+/*
+ * imx53 pinctrl driver based on imx pinmux core
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-imx-core.h"
+
+#define IMX53_IOMUXC_MUX_OFFSET 0x20
+#define IMX53_IOMUXC_MAXPIN (23*23)
+
+enum imx_imx53_pinctrl_pads {
+ MX53_GPIO_19 = 0,
+ MX53_KEY_COL0 = 1,
+ MX53_KEY_ROW0 = 2,
+ MX53_KEY_COL1 = 3,
+ MX53_KEY_ROW1 = 4,
+ MX53_KEY_COL2 = 5,
+ MX53_KEY_ROW2 = 6,
+ MX53_KEY_COL3 = 7,
+ MX53_KEY_ROW3 = 8,
+ MX53_KEY_COL4 = 9,
+ MX53_KEY_ROW4 = 10,
+ MX53_DI0_DISP_CLK = 11,
+ MX53_DI0_PIN15 = 12,
+ MX53_DI0_PIN2 = 13,
+ MX53_DI0_PIN3 = 14,
+ MX53_DI0_PIN4 = 15,
+ MX53_DISP0_DAT0 = 16,
+ MX53_DISP0_DAT1 = 17,
+ MX53_DISP0_DAT2 = 18,
+ MX53_DISP0_DAT3 = 19,
+ MX53_DISP0_DAT4 = 20,
+ MX53_DISP0_DAT5 = 21,
+ MX53_DISP0_DAT6 = 22,
+ MX53_DISP0_DAT7 = 23,
+ MX53_DISP0_DAT8 = 24,
+ MX53_DISP0_DAT9 = 25,
+ MX53_DISP0_DAT10 = 26,
+ MX53_DISP0_DAT11 = 27,
+ MX53_DISP0_DAT12 = 28,
+ MX53_DISP0_DAT13 = 29,
+ MX53_DISP0_DAT14 = 30,
+ MX53_DISP0_DAT15 = 31,
+ MX53_DISP0_DAT16 = 32,
+ MX53_DISP0_DAT17 = 33,
+ MX53_DISP0_DAT18 = 34,
+ MX53_DISP0_DAT19 = 35,
+ MX53_DISP0_DAT20 = 36,
+ MX53_DISP0_DAT21 = 37,
+ MX53_DISP0_DAT22 = 38,
+ MX53_DISP0_DAT23 = 39,
+ MX53_CSI0_PIXCLK = 40,
+ MX53_CSI0_MCLK = 41,
+ MX53_CSI0_DATA_EN = 42,
+ MX53_CSI0_VSYNC = 43,
+ MX53_CSI0_DAT4 = 44,
+ MX53_CSI0_DAT5 = 45,
+ MX53_CSI0_DAT6 = 46,
+ MX53_CSI0_DAT7 = 47,
+ MX53_CSI0_DAT8 = 48,
+ MX53_CSI0_DAT9 = 49,
+ MX53_CSI0_DAT10 = 50,
+ MX53_CSI0_DAT11 = 51,
+ MX53_CSI0_DAT12 = 52,
+ MX53_CSI0_DAT13 = 53,
+ MX53_CSI0_DAT14 = 54,
+ MX53_CSI0_DAT15 = 55,
+ MX53_CSI0_DAT16 = 56,
+ MX53_CSI0_DAT17 = 57,
+ MX53_CSI0_DAT18 = 58,
+ MX53_CSI0_DAT19 = 59,
+ MX53_EIM_A25 = 60,
+ MX53_EIM_EB2 = 61,
+ MX53_EIM_D16 = 62,
+ MX53_EIM_D17 = 63,
+ MX53_EIM_D18 = 64,
+ MX53_EIM_D19 = 65,
+ MX53_EIM_D20 = 66,
+ MX53_EIM_D21 = 67,
+ MX53_EIM_D22 = 68,
+ MX53_EIM_D23 = 69,
+ MX53_EIM_EB3 = 70,
+ MX53_EIM_D24 = 71,
+ MX53_EIM_D25 = 72,
+ MX53_EIM_D26 = 73,
+ MX53_EIM_D27 = 74,
+ MX53_EIM_D28 = 75,
+ MX53_EIM_D29 = 76,
+ MX53_EIM_D30 = 77,
+ MX53_EIM_D31 = 78,
+ MX53_EIM_A24 = 79,
+ MX53_EIM_A23 = 80,
+ MX53_EIM_A22 = 81,
+ MX53_EIM_A21 = 82,
+ MX53_EIM_A20 = 83,
+ MX53_EIM_A19 = 84,
+ MX53_EIM_A18 = 85,
+ MX53_EIM_A17 = 86,
+ MX53_EIM_A16 = 87,
+ MX53_EIM_CS0 = 88,
+ MX53_EIM_CS1 = 89,
+ MX53_EIM_OE = 90,
+ MX53_EIM_RW = 91,
+ MX53_EIM_LBA = 92,
+ MX53_EIM_EB0 = 93,
+ MX53_EIM_EB1 = 94,
+ MX53_EIM_DA0 = 95,
+ MX53_EIM_DA1 = 96,
+ MX53_EIM_DA2 = 97,
+ MX53_EIM_DA3 = 98,
+ MX53_EIM_DA4 = 99,
+ MX53_EIM_DA5 = 100,
+ MX53_EIM_DA6 = 101,
+ MX53_EIM_DA7 = 102,
+ MX53_EIM_DA8 = 103,
+ MX53_EIM_DA9 = 104,
+ MX53_EIM_DA10 = 105,
+ MX53_EIM_DA11 = 106,
+ MX53_EIM_DA12 = 107,
+ MX53_EIM_DA13 = 108,
+ MX53_EIM_DA14 = 109,
+ MX53_EIM_DA15 = 110,
+ MX53_NANDF_WE_B = 111,
+ MX53_NANDF_RE_B = 112,
+ MX53_EIM_WAIT = 113,
+ MX53_EIM_BCLK = 114,
+ MX53_LVDS1_TX3_P = 115,
+ MX53_LVDS1_TX2_P = 116,
+ MX53_LVDS1_CLK_P = 117,
+ MX53_LVDS1_TX1_P = 118,
+ MX53_LVDS1_TX0_P = 119,
+ MX53_LVDS0_TX3_P = 120,
+ MX53_LVDS0_CLK_P = 121,
+ MX53_LVDS0_TX2_P = 122,
+ MX53_LVDS0_TX1_P = 123,
+ MX53_LVDS0_TX0_P = 124,
+ MX53_GPIO_10 = 125,
+ MX53_GPIO_11 = 126,
+ MX53_GPIO_12 = 127,
+ MX53_GPIO_13 = 128,
+ MX53_GPIO_14 = 129,
+ MX53_NANDF_CLE = 130,
+ MX53_NANDF_ALE = 131,
+ MX53_NANDF_WP_B = 132,
+ MX53_NANDF_RB0 = 133,
+ MX53_NANDF_CS0 = 134,
+ MX53_NANDF_CS1 = 135,
+ MX53_NANDF_CS2 = 136,
+ MX53_NANDF_CS3 = 137,
+ MX53_FEC_MDIO = 138,
+ MX53_FEC_REF_CLK = 139,
+ MX53_FEC_RX_ER = 140,
+ MX53_FEC_CRS_DV = 141,
+ MX53_FEC_RXD1 = 142,
+ MX53_FEC_RXD0 = 143,
+ MX53_FEC_TX_EN = 144,
+ MX53_FEC_TXD1 = 145,
+ MX53_FEC_TXD0 = 146,
+ MX53_FEC_MDC = 147,
+ MX53_PATA_DIOW = 148,
+ MX53_PATA_DMACK = 149,
+ MX53_PATA_DMARQ = 150,
+ MX53_PATA_BUFFER_EN = 151,
+ MX53_PATA_INTRQ = 152,
+ MX53_PATA_DIOR = 153,
+ MX53_PATA_RESET_B = 154,
+ MX53_PATA_IORDY = 155,
+ MX53_PATA_DA_0 = 156,
+ MX53_PATA_DA_1 = 157,
+ MX53_PATA_DA_2 = 158,
+ MX53_PATA_CS_0 = 159,
+ MX53_PATA_CS_1 = 160,
+ MX53_PATA_DATA0 = 161,
+ MX53_PATA_DATA1 = 162,
+ MX53_PATA_DATA2 = 163,
+ MX53_PATA_DATA3 = 164,
+ MX53_PATA_DATA4 = 165,
+ MX53_PATA_DATA5 = 166,
+ MX53_PATA_DATA6 = 167,
+ MX53_PATA_DATA7 = 168,
+ MX53_PATA_DATA8 = 169,
+ MX53_PATA_DATA9 = 170,
+ MX53_PATA_DATA10 = 171,
+ MX53_PATA_DATA11 = 172,
+ MX53_PATA_DATA12 = 173,
+ MX53_PATA_DATA13 = 174,
+ MX53_PATA_DATA14 = 175,
+ MX53_PATA_DATA15 = 176,
+ MX53_SD1_DATA0 = 177,
+ MX53_SD1_DATA1 = 178,
+ MX53_SD1_CMD = 179,
+ MX53_SD1_DATA2 = 180,
+ MX53_SD1_CLK = 181,
+ MX53_SD1_DATA3 = 182,
+ MX53_SD2_CLK = 183,
+ MX53_SD2_CMD = 184,
+ MX53_SD2_DATA3 = 185,
+ MX53_SD2_DATA2 = 186,
+ MX53_SD2_DATA1 = 187,
+ MX53_SD2_DATA0 = 188,
+ MX53_GPIO_0 = 189,
+ MX53_GPIO_1 = 190,
+ MX53_GPIO_9 = 191,
+ MX53_GPIO_3 = 192,
+ MX53_GPIO_6 = 193,
+ MX53_GPIO_2 = 194,
+ MX53_GPIO_4 = 195,
+ MX53_GPIO_5 = 196,
+ MX53_GPIO_7 = 197,
+ MX53_GPIO_8 = 198,
+ MX53_GPIO_16 = 199,
+ MX53_GPIO_17 = 200,
+ MX53_GPIO_18 = 201,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx53_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX53_GPIO_19),
+ IMX_PINCTRL_PIN(MX53_KEY_COL0),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX53_KEY_COL1),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX53_KEY_COL2),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX53_KEY_COL3),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX53_KEY_COL4),
+ IMX_PINCTRL_PIN(MX53_KEY_ROW4),
+ IMX_PINCTRL_PIN(MX53_DI0_DISP_CLK),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN15),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN2),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN3),
+ IMX_PINCTRL_PIN(MX53_DI0_PIN4),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT0),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT1),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT2),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT3),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT4),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT5),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT6),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT7),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT8),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT9),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT10),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT11),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT12),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT13),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT14),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT15),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT16),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT17),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT18),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT19),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT20),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT21),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT22),
+ IMX_PINCTRL_PIN(MX53_DISP0_DAT23),
+ IMX_PINCTRL_PIN(MX53_CSI0_PIXCLK),
+ IMX_PINCTRL_PIN(MX53_CSI0_MCLK),
+ IMX_PINCTRL_PIN(MX53_CSI0_DATA_EN),
+ IMX_PINCTRL_PIN(MX53_CSI0_VSYNC),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT4),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT5),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT6),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT7),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT8),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT9),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT10),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT11),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT12),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT13),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT14),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT15),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT16),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT17),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT18),
+ IMX_PINCTRL_PIN(MX53_CSI0_DAT19),
+ IMX_PINCTRL_PIN(MX53_EIM_A25),
+ IMX_PINCTRL_PIN(MX53_EIM_EB2),
+ IMX_PINCTRL_PIN(MX53_EIM_D16),
+ IMX_PINCTRL_PIN(MX53_EIM_D17),
+ IMX_PINCTRL_PIN(MX53_EIM_D18),
+ IMX_PINCTRL_PIN(MX53_EIM_D19),
+ IMX_PINCTRL_PIN(MX53_EIM_D20),
+ IMX_PINCTRL_PIN(MX53_EIM_D21),
+ IMX_PINCTRL_PIN(MX53_EIM_D22),
+ IMX_PINCTRL_PIN(MX53_EIM_D23),
+ IMX_PINCTRL_PIN(MX53_EIM_EB3),
+ IMX_PINCTRL_PIN(MX53_EIM_D24),
+ IMX_PINCTRL_PIN(MX53_EIM_D25),
+ IMX_PINCTRL_PIN(MX53_EIM_D26),
+ IMX_PINCTRL_PIN(MX53_EIM_D27),
+ IMX_PINCTRL_PIN(MX53_EIM_D28),
+ IMX_PINCTRL_PIN(MX53_EIM_D29),
+ IMX_PINCTRL_PIN(MX53_EIM_D30),
+ IMX_PINCTRL_PIN(MX53_EIM_D31),
+ IMX_PINCTRL_PIN(MX53_EIM_A24),
+ IMX_PINCTRL_PIN(MX53_EIM_A23),
+ IMX_PINCTRL_PIN(MX53_EIM_A22),
+ IMX_PINCTRL_PIN(MX53_EIM_A21),
+ IMX_PINCTRL_PIN(MX53_EIM_A20),
+ IMX_PINCTRL_PIN(MX53_EIM_A19),
+ IMX_PINCTRL_PIN(MX53_EIM_A18),
+ IMX_PINCTRL_PIN(MX53_EIM_A17),
+ IMX_PINCTRL_PIN(MX53_EIM_A16),
+ IMX_PINCTRL_PIN(MX53_EIM_CS0),
+ IMX_PINCTRL_PIN(MX53_EIM_CS1),
+ IMX_PINCTRL_PIN(MX53_EIM_OE),
+ IMX_PINCTRL_PIN(MX53_EIM_RW),
+ IMX_PINCTRL_PIN(MX53_EIM_LBA),
+ IMX_PINCTRL_PIN(MX53_EIM_EB0),
+ IMX_PINCTRL_PIN(MX53_EIM_EB1),
+ IMX_PINCTRL_PIN(MX53_EIM_DA0),
+ IMX_PINCTRL_PIN(MX53_EIM_DA1),
+ IMX_PINCTRL_PIN(MX53_EIM_DA2),
+ IMX_PINCTRL_PIN(MX53_EIM_DA3),
+ IMX_PINCTRL_PIN(MX53_EIM_DA4),
+ IMX_PINCTRL_PIN(MX53_EIM_DA5),
+ IMX_PINCTRL_PIN(MX53_EIM_DA6),
+ IMX_PINCTRL_PIN(MX53_EIM_DA7),
+ IMX_PINCTRL_PIN(MX53_EIM_DA8),
+ IMX_PINCTRL_PIN(MX53_EIM_DA9),
+ IMX_PINCTRL_PIN(MX53_EIM_DA10),
+ IMX_PINCTRL_PIN(MX53_EIM_DA11),
+ IMX_PINCTRL_PIN(MX53_EIM_DA12),
+ IMX_PINCTRL_PIN(MX53_EIM_DA13),
+ IMX_PINCTRL_PIN(MX53_EIM_DA14),
+ IMX_PINCTRL_PIN(MX53_EIM_DA15),
+ IMX_PINCTRL_PIN(MX53_NANDF_WE_B),
+ IMX_PINCTRL_PIN(MX53_NANDF_RE_B),
+ IMX_PINCTRL_PIN(MX53_EIM_WAIT),
+ IMX_PINCTRL_PIN(MX53_EIM_BCLK),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX3_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX2_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_CLK_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX1_P),
+ IMX_PINCTRL_PIN(MX53_LVDS1_TX0_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX3_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_CLK_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX2_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX1_P),
+ IMX_PINCTRL_PIN(MX53_LVDS0_TX0_P),
+ IMX_PINCTRL_PIN(MX53_GPIO_10),
+ IMX_PINCTRL_PIN(MX53_GPIO_11),
+ IMX_PINCTRL_PIN(MX53_GPIO_12),
+ IMX_PINCTRL_PIN(MX53_GPIO_13),
+ IMX_PINCTRL_PIN(MX53_GPIO_14),
+ IMX_PINCTRL_PIN(MX53_NANDF_CLE),
+ IMX_PINCTRL_PIN(MX53_NANDF_ALE),
+ IMX_PINCTRL_PIN(MX53_NANDF_WP_B),
+ IMX_PINCTRL_PIN(MX53_NANDF_RB0),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS0),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS1),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS2),
+ IMX_PINCTRL_PIN(MX53_NANDF_CS3),
+ IMX_PINCTRL_PIN(MX53_FEC_MDIO),
+ IMX_PINCTRL_PIN(MX53_FEC_REF_CLK),
+ IMX_PINCTRL_PIN(MX53_FEC_RX_ER),
+ IMX_PINCTRL_PIN(MX53_FEC_CRS_DV),
+ IMX_PINCTRL_PIN(MX53_FEC_RXD1),
+ IMX_PINCTRL_PIN(MX53_FEC_RXD0),
+ IMX_PINCTRL_PIN(MX53_FEC_TX_EN),
+ IMX_PINCTRL_PIN(MX53_FEC_TXD1),
+ IMX_PINCTRL_PIN(MX53_FEC_TXD0),
+ IMX_PINCTRL_PIN(MX53_FEC_MDC),
+ IMX_PINCTRL_PIN(MX53_PATA_DIOW),
+ IMX_PINCTRL_PIN(MX53_PATA_DMACK),
+ IMX_PINCTRL_PIN(MX53_PATA_DMARQ),
+ IMX_PINCTRL_PIN(MX53_PATA_BUFFER_EN),
+ IMX_PINCTRL_PIN(MX53_PATA_INTRQ),
+ IMX_PINCTRL_PIN(MX53_PATA_DIOR),
+ IMX_PINCTRL_PIN(MX53_PATA_RESET_B),
+ IMX_PINCTRL_PIN(MX53_PATA_IORDY),
+ IMX_PINCTRL_PIN(MX53_PATA_DA_0),
+ IMX_PINCTRL_PIN(MX53_PATA_DA_1),
+ IMX_PINCTRL_PIN(MX53_PATA_DA_2),
+ IMX_PINCTRL_PIN(MX53_PATA_CS_0),
+ IMX_PINCTRL_PIN(MX53_PATA_CS_1),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA0),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA1),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA2),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA3),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA4),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA5),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA6),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA7),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA8),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA9),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA10),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA11),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA12),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA13),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA14),
+ IMX_PINCTRL_PIN(MX53_PATA_DATA15),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX53_SD1_CMD),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX53_SD1_CLK),
+ IMX_PINCTRL_PIN(MX53_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX53_SD2_CLK),
+ IMX_PINCTRL_PIN(MX53_SD2_CMD),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX53_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX53_GPIO_0),
+ IMX_PINCTRL_PIN(MX53_GPIO_1),
+ IMX_PINCTRL_PIN(MX53_GPIO_9),
+ IMX_PINCTRL_PIN(MX53_GPIO_3),
+ IMX_PINCTRL_PIN(MX53_GPIO_6),
+ IMX_PINCTRL_PIN(MX53_GPIO_2),
+ IMX_PINCTRL_PIN(MX53_GPIO_4),
+ IMX_PINCTRL_PIN(MX53_GPIO_5),
+ IMX_PINCTRL_PIN(MX53_GPIO_7),
+ IMX_PINCTRL_PIN(MX53_GPIO_8),
+ IMX_PINCTRL_PIN(MX53_GPIO_16),
+ IMX_PINCTRL_PIN(MX53_GPIO_17),
+ IMX_PINCTRL_PIN(MX53_GPIO_18),
+};
+
+struct imx_pinctrl_info imx53_pinctrl_info = {
+ .type = IMX53_PINCTRL,
+ .pins = imx53_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx53_pinctrl_pads),
+ .maxpin = IMX53_IOMUXC_MAXPIN,
+ .mux_offset = IMX53_IOMUXC_MUX_OFFSET,
+};
diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/pinctrl-imx6q.c
new file mode 100644
index 0000000..4c0e29f
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx6q.c
@@ -0,0 +1,433 @@
+/*
+ * imx6q pinctrl driver based on imx pinmux core
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.a...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-imx-core.h"
+
+#define IMX6Q_IOMUXC_MUX_OFSSET 0x4c
+#define IMX6Q_IOMUXC_MAXPIN (25*25)
+
+enum imx6q_pads {
+ MX6Q_SD2_DAT1 = 0,
+ MX6Q_SD2_DAT2 = 1,
+ MX6Q_SD2_DAT0 = 2,
+ MX6Q_RGMII_TXC = 3,
+ MX6Q_RGMII_TD0 = 4,
+ MX6Q_RGMII_TD1 = 5,
+ MX6Q_RGMII_TD2 = 6,
+ MX6Q_RGMII_TD3 = 7,
+ MX6Q_RGMII_RX_CTL = 8,
+ MX6Q_RGMII_RD0 = 9,
+ MX6Q_RGMII_TX_CTL = 10,
+ MX6Q_RGMII_RD1 = 11,
+ MX6Q_RGMII_RD2 = 12,
+ MX6Q_RGMII_RD3 = 13,
+ MX6Q_RGMII_RXC = 14,
+ MX6Q_EIM_A25 = 15,
+ MX6Q_EIM_EB2 = 16,
+ MX6Q_EIM_D16 = 17,
+ MX6Q_EIM_D17 = 18,
+ MX6Q_EIM_D18 = 19,
+ MX6Q_EIM_D19 = 20,
+ MX6Q_EIM_D20 = 21,
+ MX6Q_EIM_D21 = 22,
+ MX6Q_EIM_D22 = 23,
+ MX6Q_EIM_D23 = 24,
+ MX6Q_EIM_EB3 = 25,
+ MX6Q_EIM_D24 = 26,
+ MX6Q_EIM_D25 = 27,
+ MX6Q_EIM_D26 = 28,
+ MX6Q_EIM_D27 = 29,
+ MX6Q_EIM_D28 = 30,
+ MX6Q_EIM_D29 = 31,
+ MX6Q_EIM_D30 = 32,
+ MX6Q_EIM_D31 = 33,
+ MX6Q_EIM_A24 = 34,
+ MX6Q_EIM_A23 = 35,
+ MX6Q_EIM_A22 = 36,
+ MX6Q_EIM_A21 = 37,
+ MX6Q_EIM_A20 = 38,
+ MX6Q_EIM_A19 = 39,
+ MX6Q_EIM_A18 = 40,
+ MX6Q_EIM_A17 = 41,
+ MX6Q_EIM_A16 = 42,
+ MX6Q_EIM_CS0 = 43,
+ MX6Q_EIM_CS1 = 44,
+ MX6Q_EIM_OE = 45,
+ MX6Q_EIM_RW = 46,
+ MX6Q_EIM_LBA = 47,
+ MX6Q_EIM_EB0 = 48,
+ MX6Q_EIM_EB1 = 49,
+ MX6Q_EIM_DA0 = 50,
+ MX6Q_EIM_DA1 = 51,
+ MX6Q_EIM_DA2 = 52,
+ MX6Q_EIM_DA3 = 53,
+ MX6Q_EIM_DA4 = 54,
+ MX6Q_EIM_DA5 = 55,
+ MX6Q_EIM_DA6 = 56,
+ MX6Q_EIM_DA7 = 57,
+ MX6Q_EIM_DA8 = 58,
+ MX6Q_EIM_DA9 = 59,
+ MX6Q_EIM_DA10 = 60,
+ MX6Q_EIM_DA11 = 61,
+ MX6Q_EIM_DA12 = 62,
+ MX6Q_EIM_DA13 = 63,
+ MX6Q_EIM_DA14 = 64,
+ MX6Q_EIM_DA15 = 65,
+ MX6Q_EIM_WAIT = 66,
+ MX6Q_EIM_BCLK = 67,
+ MX6Q_DI0_DISP_CLK = 68,
+ MX6Q_DI0_PIN15 = 69,
+ MX6Q_DI0_PIN2 = 70,
+ MX6Q_DI0_PIN3 = 71,
+ MX6Q_DI0_PIN4 = 72,
+ MX6Q_DISP0_DAT0 = 73,
+ MX6Q_DISP0_DAT1 = 74,
+ MX6Q_DISP0_DAT2 = 75,
+ MX6Q_DISP0_DAT3 = 76,
+ MX6Q_DISP0_DAT4 = 77,
+ MX6Q_DISP0_DAT5 = 78,
+ MX6Q_DISP0_DAT6 = 79,
+ MX6Q_DISP0_DAT7 = 80,
+ MX6Q_DISP0_DAT8 = 81,
+ MX6Q_DISP0_DAT9 = 82,
+ MX6Q_DISP0_DAT10 = 83,
+ MX6Q_DISP0_DAT11 = 84,
+ MX6Q_DISP0_DAT12 = 85,
+ MX6Q_DISP0_DAT13 = 86,
+ MX6Q_DISP0_DAT14 = 87,
+ MX6Q_DISP0_DAT15 = 88,
+ MX6Q_DISP0_DAT16 = 89,
+ MX6Q_DISP0_DAT17 = 90,
+ MX6Q_DISP0_DAT18 = 91,
+ MX6Q_DISP0_DAT19 = 92,
+ MX6Q_DISP0_DAT20 = 93,
+ MX6Q_DISP0_DAT21 = 94,
+ MX6Q_DISP0_DAT22 = 95,
+ MX6Q_DISP0_DAT23 = 96,
+ MX6Q_ENET_MDIO = 97,
+ MX6Q_ENET_REF_CLK = 98,
+ MX6Q_ENET_RX_ER = 99,
+ MX6Q_ENET_CRS_DV = 100,
+ MX6Q_ENET_RXD1 = 101,
+ MX6Q_ENET_RXD0 = 102,
+ MX6Q_ENET_TX_EN = 103,
+ MX6Q_ENET_TXD1 = 104,
+ MX6Q_ENET_TXD0 = 105,
+ MX6Q_ENET_MDC = 106,
+ MX6Q_KEY_COL0 = 107,
+ MX6Q_KEY_ROW0 = 108,
+ MX6Q_KEY_COL1 = 109,
+ MX6Q_KEY_ROW1 = 110,
+ MX6Q_KEY_COL2 = 111,
+ MX6Q_KEY_ROW2 = 112,
+ MX6Q_KEY_COL3 = 113,
+ MX6Q_KEY_ROW3 = 114,
+ MX6Q_KEY_COL4 = 115,
+ MX6Q_KEY_ROW4 = 116,
+ MX6Q_GPIO_0 = 117,
+ MX6Q_GPIO_1 = 118,
+ MX6Q_GPIO_9 = 119,
+ MX6Q_GPIO_3 = 120,
+ MX6Q_GPIO_6 = 121,
+ MX6Q_GPIO_2 = 122,
+ MX6Q_GPIO_4 = 123,
+ MX6Q_GPIO_5 = 124,
+ MX6Q_GPIO_7 = 125,
+ MX6Q_GPIO_8 = 126,
+ MX6Q_GPIO_16 = 127,
+ MX6Q_GPIO_17 = 128,
+ MX6Q_GPIO_18 = 129,
+ MX6Q_GPIO_19 = 130,
+ MX6Q_CSI0_PIXCLK = 131,
+ MX6Q_CSI0_MCLK = 132,
+ MX6Q_CSI0_DATA_EN = 133,
+ MX6Q_CSI0_VSYNC = 134,
+ MX6Q_CSI0_DAT4 = 135,
+ MX6Q_CSI0_DAT5 = 136,
+ MX6Q_CSI0_DAT6 = 137,
+ MX6Q_CSI0_DAT7 = 138,
+ MX6Q_CSI0_DAT8 = 139,
+ MX6Q_CSI0_DAT9 = 140,
+ MX6Q_CSI0_DAT10 = 141,
+ MX6Q_CSI0_DAT11 = 142,
+ MX6Q_CSI0_DAT12 = 143,
+ MX6Q_CSI0_DAT13 = 144,
+ MX6Q_CSI0_DAT14 = 145,
+ MX6Q_CSI0_DAT15 = 146,
+ MX6Q_CSI0_DAT16 = 147,
+ MX6Q_CSI0_DAT17 = 148,
+ MX6Q_CSI0_DAT18 = 149,
+ MX6Q_CSI0_DAT19 = 150,
+ MX6Q_SD3_DAT7 = 151,
+ MX6Q_SD3_DAT6 = 152,
+ MX6Q_SD3_DAT5 = 153,
+ MX6Q_SD3_DAT4 = 154,
+ MX6Q_SD3_CMD = 155,
+ MX6Q_SD3_CLK = 156,
+ MX6Q_SD3_DAT0 = 157,
+ MX6Q_SD3_DAT1 = 158,
+ MX6Q_SD3_DAT2 = 159,
+ MX6Q_SD3_DAT3 = 160,
+ MX6Q_SD3_RST = 161,
+ MX6Q_NANDF_CLE = 162,
+ MX6Q_NANDF_ALE = 163,
+ MX6Q_NANDF_WP_B = 164,
+ MX6Q_NANDF_RB0 = 165,
+ MX6Q_NANDF_CS0 = 166,
+ MX6Q_NANDF_CS1 = 167,
+ MX6Q_NANDF_CS2 = 168,
+ MX6Q_NANDF_CS3 = 169,
+ MX6Q_SD4_CMD = 170,
+ MX6Q_SD4_CLK = 171,
+ MX6Q_NANDF_D0 = 172,
+ MX6Q_NANDF_D1 = 173,
+ MX6Q_NANDF_D2 = 174,
+ MX6Q_NANDF_D3 = 175,
+ MX6Q_NANDF_D4 = 176,
+ MX6Q_NANDF_D5 = 177,
+ MX6Q_NANDF_D6 = 178,
+ MX6Q_NANDF_D7 = 179,
+ MX6Q_SD4_DAT0 = 180,
+ MX6Q_SD4_DAT1 = 181,
+ MX6Q_SD4_DAT2 = 182,
+ MX6Q_SD4_DAT3 = 183,
+ MX6Q_SD4_DAT4 = 184,
+ MX6Q_SD4_DAT5 = 185,
+ MX6Q_SD4_DAT6 = 186,
+ MX6Q_SD4_DAT7 = 187,
+ MX6Q_SD1_DAT1 = 188,
+ MX6Q_SD1_DAT0 = 189,
+ MX6Q_SD1_DAT3 = 190,
+ MX6Q_SD1_CMD = 191,
+ MX6Q_SD1_DAT2 = 192,
+ MX6Q_SD1_CLK = 193,
+ MX6Q_SD2_CLK = 194,
+ MX6Q_SD2_CMD = 195,
+ MX6Q_SD2_DAT3 = 196
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx6q_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TXC),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD0),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD1),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD2),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TD3),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RX_CTL),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD0),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_TX_CTL),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD1),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD2),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RD3),
+ IMX_PINCTRL_PIN(MX6Q_RGMII_RXC),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A25),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB2),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D16),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D17),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D18),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D19),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D20),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D21),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D22),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D23),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB3),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D24),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D25),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D26),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D27),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D28),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D29),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D30),
+ IMX_PINCTRL_PIN(MX6Q_EIM_D31),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A24),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A23),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A22),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A21),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A20),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A19),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A18),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A17),
+ IMX_PINCTRL_PIN(MX6Q_EIM_A16),
+ IMX_PINCTRL_PIN(MX6Q_EIM_CS0),
+ IMX_PINCTRL_PIN(MX6Q_EIM_CS1),
+ IMX_PINCTRL_PIN(MX6Q_EIM_OE),
+ IMX_PINCTRL_PIN(MX6Q_EIM_RW),
+ IMX_PINCTRL_PIN(MX6Q_EIM_LBA),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB0),
+ IMX_PINCTRL_PIN(MX6Q_EIM_EB1),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA0),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA1),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA2),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA3),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA4),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA5),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA6),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA7),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA8),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA9),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA10),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA11),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA12),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA13),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA14),
+ IMX_PINCTRL_PIN(MX6Q_EIM_DA15),
+ IMX_PINCTRL_PIN(MX6Q_EIM_WAIT),
+ IMX_PINCTRL_PIN(MX6Q_EIM_BCLK),
+ IMX_PINCTRL_PIN(MX6Q_DI0_DISP_CLK),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN15),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN2),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN3),
+ IMX_PINCTRL_PIN(MX6Q_DI0_PIN4),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT8),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT9),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT10),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT11),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT12),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT13),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT14),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT15),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT16),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT17),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT18),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT19),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT20),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT21),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT22),
+ IMX_PINCTRL_PIN(MX6Q_DISP0_DAT23),
+ IMX_PINCTRL_PIN(MX6Q_ENET_MDIO),
+ IMX_PINCTRL_PIN(MX6Q_ENET_REF_CLK),
+ IMX_PINCTRL_PIN(MX6Q_ENET_RX_ER),
+ IMX_PINCTRL_PIN(MX6Q_ENET_CRS_DV),
+ IMX_PINCTRL_PIN(MX6Q_ENET_RXD1),
+ IMX_PINCTRL_PIN(MX6Q_ENET_RXD0),
+ IMX_PINCTRL_PIN(MX6Q_ENET_TX_EN),
+ IMX_PINCTRL_PIN(MX6Q_ENET_TXD1),
+ IMX_PINCTRL_PIN(MX6Q_ENET_TXD0),
+ IMX_PINCTRL_PIN(MX6Q_ENET_MDC),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL0),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL1),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL2),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL3),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX6Q_KEY_COL4),
+ IMX_PINCTRL_PIN(MX6Q_KEY_ROW4),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_0),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_1),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_9),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_3),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_6),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_2),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_4),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_5),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_7),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_8),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_16),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_17),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_18),
+ IMX_PINCTRL_PIN(MX6Q_GPIO_19),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_PIXCLK),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_MCLK),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DATA_EN),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_VSYNC),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT8),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT9),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT10),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT11),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT12),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT13),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT14),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT15),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT16),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT17),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT18),
+ IMX_PINCTRL_PIN(MX6Q_CSI0_DAT19),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_SD3_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD3_CLK),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD3_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_SD3_RST),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CLE),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_ALE),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_WP_B),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_RB0),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS0),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS1),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS2),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_CS3),
+ IMX_PINCTRL_PIN(MX6Q_SD4_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD4_CLK),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D0),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D1),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D2),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D3),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D4),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D5),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D6),
+ IMX_PINCTRL_PIN(MX6Q_NANDF_D7),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_SD4_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_SD1_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD1_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_SD1_CLK),
+ IMX_PINCTRL_PIN(MX6Q_SD2_CLK),
+ IMX_PINCTRL_PIN(MX6Q_SD2_CMD),
+ IMX_PINCTRL_PIN(MX6Q_SD2_DAT3),
+};
+
+struct imx_pinctrl_info imx6q_pinctrl_info = {
+ .type = IMX6Q_PINCTRL,
+ .pins = imx6q_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx6q_pinctrl_pads),
+ .maxpin = IMX6Q_IOMUXC_MAXPIN,
+ .mux_offset = IMX6Q_IOMUXC_MUX_OFSSET,
+};
--
1.7.0.4
Signed-off-by: Shawn Guo <shaw...@linaro.org>
Signed-off-by: Dong Aisheng <dong.a...@linaro.org>
Cc: Linus Walleij <linus....@linaro.org>
Cc: Chris Ball <c...@laptop.org>
Cc: Sascha Hauer <s.h...@pengutronix.de>
Cc: Wolfram Sang <w.s...@pengutronix.de>
---
drivers/mmc/host/sdhci-esdhc-imx.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 4b976f0..4504136 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -24,6 +24,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/pinmux.h>
#include <mach/esdhc.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -68,6 +69,7 @@ struct pltfm_imx_data {
int flags;
u32 scratchpad;
enum imx_esdhc_type devtype;
+ struct pinmux *pmx;
struct esdhc_platform_data boarddata;
};
@@ -439,6 +441,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
struct clk *clk;
int err;
struct pltfm_imx_data *imx_data;
+ struct pinmux *pmx;
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
if (IS_ERR(host))
@@ -466,6 +469,16 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
clk_enable(clk);
pltfm_host->clk = clk;
+ pmx = pinmux_get(&pdev->dev, NULL);
+ if (IS_ERR(pmx)) {
+ err = PTR_ERR(pmx);
+ goto err_pmx_get;
+ }
+ err = pinmux_enable(pmx);
+ if (err)
+ goto err_pmx_enable;
+ imx_data->pmx = pmx;
+
if (!is_imx25_esdhc(imx_data))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -558,6 +571,10 @@ no_card_detect_irq:
gpio_free(boarddata->wp_gpio);
no_card_detect_pin:
no_board_data:
+ pinmux_disable(imx_data->pmx);
+err_pmx_enable:
+ pinmux_put(imx_data->pmx);
+err_pmx_get:
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
err_clk_get:
@@ -585,6 +602,9 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
gpio_free(boarddata->cd_gpio);
}
+ pinmux_disable(imx_data->pmx);
+ pinmux_put(imx_data->pmx);
+
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
kfree(imx_data);
--
1.7.0.4
I assume you want this to go in with the rest of the series? If not, let
me know.
Acked-by: Rob Herring <rob.h...@calxeda.com>
Rob
The assignment in this condition really looks eerie, maybe just rewrite it to do
{ } while () ? Also, aren't the parenthesis unnecessary?
M
> + num++;
> +
> + return num;
> +}
> +
> extern struct device_node *of_find_node_with_property(
> struct device_node *from, const char *prop_name);
> #define for_each_node_with_property(dn, prop_name) \
> @@ -262,6 +273,11 @@ static inline bool of_have_populated_dt(void)
> #define for_each_child_of_node(parent, child) \
> while (0)
>
> +static inline int of_get_child_count(const struct device_node *np)
> +{
> + return -ENOSYS;
> +}
> +
> static inline int of_device_is_compatible(const struct device_node
> *device, const char *name)
> {
--
Line too long maybe?
Is this imx or mx6q/mx53 ?
M
> diff --git a/include/linux/of.h b/include/linux/of.h
> +static inline int of_get_child_count(const struct device_node *np)
> +{
> + return -ENOSYS;
> +}
Wouldn't it be better to return 0 here? -ENOSYS would be fine if the
function returned an error code, but it's really returning a count, and
other "dummy" functions that return data return 0/NULL already. This
would also allow you to just use the value directly in all cases rather
than having to check for a < 0 error case.
--
nvpublic
Dong,
Thanks for providing a concrete binding to get discussion started. I had
intended to do this myself, but got side-tracked on other things.
I'll comment exclusively on the documentation in this patch, since any
changes there will require the code to be changed.
> diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl.txt
> +The pin control subsystem
> +
> +The pin control subsystem provides a common API to support parsing pinmux
> +mappings data from device tree. Each board dts file should provide a device
> +node of which all the child nodes are the corresponding pinmux mappings.
So, the binding you propose seems very reasonable from the point-of-view
of the Linux pinctrl subsystem. However, it violates basic device tree
philosophy in a few ways. Some background:
Device tree is supposed to be a pure representation of hardware, not the
software that runs on it. This means a couple of things: (a) the nodes
in the DT generally match 1:1 with specific HW on the board (b) the
design of the bindings should be justifiable given HW datasheets without
any reference to specific operating systems or software driver design
(c) the DT should be useful to all operating systems that run on the HW;
there should be no "DT for Linux", "DT for FreeBSD", "DT for Windows".
Hence, I see a few problems with this binding:
a) The binding is documented as being for the pinctrl subsystem, rather
than for pinmux hardware.
b) The top-level node ("imx6q-sabreauto-map" below) is not tied to any
particular piece of hardware (no compatible flag, not reg property etc.)
c) The design of the binding is very much derived from the design of the
pinctrl subsystem's internal data structures. This isn't necessarily bad,
since in general SW data structures might be very closely related to how
HW is put together. In this case though, the binding seems very SW oriented.
> +The required properties for pinmux mapping are:
> +- map-name: the name of this specific map entry
> +- clk-dev-name: the name of the device controlling this specific mapping
> +- funcion: a function in the driver to use for this mapping
> +
> +Optional properties:
> +- group: a certain specific pin group to activate for the function
> +- dev-name: the name of the device using this specific mapping
> +- hog-on-boot: indicate wether hog the mappings(do not need to specify value)
> +
> +Examples:
> +
> +pinmux: imx6q-sabreauto-map {
Here we have an all-encompassing standalone "pinctrl mapping table" node.
If we continue to have such an all-encompassing table, it should really
be part of (a child of) the pinmux HW's node in order to tie it directly
to the HW, rather than standing out as a HW concept. So, perhaps something
more like:
iomuxc@020e0000 {
compatible = "fsl,imx6-pinmux";
usage { // I can't think of a good name for the table right now
sd4 {
};
sd3 {
};
...
};
};
Others have suggested that having this all-encompassing table isn't the
correct approach, and instead, it should be split into chunks that are
co-located with the devices that use the pinmux:
sdhci@1000 {
compatible = "...";
regs = <...>;
pinmux = <&pmx>;
pinmux-usage = {
// Some representation of the pins/groups/functions used
// by just this HW block.
};
};
sdhci@2000 {
compatible = "...";
regs = <...>;
pinmux = <&pmx>;
pinmux-usage = {
// Some representation of the pins/groups/functions used
// by just this HW block.
};
};
The latter probably is a little more idiomatic, although I haven't seen
or thought through any details on what goes inside such a "pinmux-usage"
node yet.
> + map-sd4 {
> + map-name = "usdhc4";
I don't think that field is needed; I'd suggest just using the name of
the DT node containing the entry (which could be renamed to your desired
names)
> + ctrl-dev-name = "20e0000.iomuxc";
...
> + dev-name = "219c000.usdhc";
That name is Linux-specific. Instead of using device names, we should
use phandle references, e.g. see the "dev" property below:
sdhci1: sdhci@1000 {
...
};
sdhci2: sdhci@1000 {
...
};
iomuxc@020e0000 {
compatible = "fsl,imx6-pinmux";
usage {
sd4 {
dev = <&sdhci1>;
};
sd3 {
dev = <&sdhci2>;
};
...
};
};
(in the above, your ctrl-dev-name would be implied to be iomuxc@020e0000
since the table is part of that pinctrl device's node)
> + function = "sd4";
Here it would be nice to use an integer instead. However, putting lots
of opaque integers in the device tree is going to be ripe for mistakes.
It's a real pity that dtc doesn't have a way of doing named integer
constants, so this could be re-written as e.g.:
SoC .dtsi file:
/define/ TEGRA_MUX_FUNC_SD4 234
Board .dts file:
function = <TEGRA_MUX_FUNC_SD4>;
Without that feature, using strings here seems the only reasonable thing
to do.
We also need to consider compatibility and extensibility. A DT binding
is an ABI between the kernel and whatever is providing it, and so we
need to be able to maintain and extend it in a compatible fashion, just
like the user-space syscall ABI. Now it's true that the .dts files are
currently part of the kernel source tree and can be rev'd in sync with
kernel changes, but that may not always be the case moving forward.
In other words, taking a board with an old device tree embedded into
Flash and running a new kernel using that device tree should work just
like running the original kernel did.
There are a couple of current active areas of change in the pinctrl
subsystem that impact this:
* Pin configuration is being added. We probably need to add the data to
configure pin config into the mapping table in the kernel, or some
parallel table.
* Support for pins being in multiple states (active, suspend, unused,
...) is being added to pinctrl. We need to be able to represent this in
DT too.
(and yes I know I wrote that from a Linux pinctrl SW perspective, but
the concepts apply to HW!)
To support this, we may just be able to add more fields to any mapping
table entries e.g. to describe pin config setup alongside mux setup.
It'd probably be a good idea to add some kind of "type" field to the
table entries though, so that we can transparently add new types in
the future, much like compatible does for HW nodes.
iomuxc@020e0000 {
compatible = "fsl,imx6-pinmux";
usage {
sd4 {
type = <0>; // 0 == mux setting
dev = <&sdhci1>;
};
sd3 {
type = <0>; // 0 == mux setting
dev = <&sdhci2>;
};
foo {
type = <1>; // 1 == pin config?
dev = <&sdhci2>;
pull-up;
tri-state;
...
};
...
};
};
--
nvpublic
Regards
Dong Aisheng
> > ---
> > include/linux/of.h | 16 ++++++++++++++++
> > 1 files changed, 16 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/linux/of.h b/include/linux/of.h index
> > 4948552..d0d91a1 100644
> > --- a/include/linux/of.h
> > +++ b/include/linux/of.h
> > @@ -189,6 +189,17 @@ extern struct device_node *of_get_next_child(const struct
> device_node *node,
> > for (child = of_get_next_child(parent, NULL); child != NULL; \
> > child = of_get_next_child(parent, child))
> >
> > +static inline int of_get_child_count(const struct device_node *np) {
> > + struct device_node *child = NULL;
> > + int num = 0;
> > +
> > + while ((child = of_get_next_child(np, child)))
> > + num++;
> > +
> > + return num;
> > +}
> > +
> > extern struct device_node *of_find_node_with_property(
> > struct device_node *from, const char *prop_name); #define
> > for_each_node_with_property(dn, prop_name) \ @@ -262,6 +273,11 @@
> > static inline bool of_have_populated_dt(void) #define
> > for_each_child_of_node(parent, child) \
> > while (0)
> >
> > +static inline int of_get_child_count(const struct device_node *np) {
> > +IC to share one PAD to several functional blocks. The sharing is done
> > +by multiplexing the PAD input/output signals. For each PAD there are
> > +up to
> > +8 muxing options (called ALT modes). Since different modules require
> > +different PAD settings (like pull up, keeper, etc) the IOMUXC
> > +controls also the PAD settings parameters.
> > +
> > +Required properties:
> > +- compatible : Should be "fsl,<chip>-iomuxc"
> > +- reg : Should contain IOMUXC registers location and length
> > +- fsl,pinmux-map: phandle of pinmux mappings. Refer to pinctrl.txt
> > +for
> > +modify
> > + * it under the terms of the GNU General Public License as published
> > +by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +#include <linux/io.h>
> > +#include <linux/err.h>
> > +#include <linux/pinctrl/pinctrl.h>
> > +#include <linux/pinctrl/pinmux.h>
> > +#include <linux/pinctrl/machine.h>
> > +#include <linux/slab.h>
> > +
> > +#include "pinctrl-imx-core.h"
> > +
> > +#define DRIVER_NAME "pinmux-imx"
> > +
> > +/**
> > + * @dev: a pointer back to containing device
> > + * @virtbase: the offset to the controller in virtual memory */
> > +struct imx_pmx {
> > + struct device *dev;
> > + struct pinctrl_dev *pctl;
> > + void __iomem *virtbase;
> > + struct imx_pinctrl_info *info;
> > +};
> > +
> > +#define IMX_PINCTRL_REG_SIZE 4
> > +#define IMX_PINCTRL_MAX_FUNC 7
> > +
> > +static int imx_list_groups(struct pinctrl_dev *pctldev, unsigned
> > +selector) {
> > +seq_file
> > +static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned
> > selector, + const char * const **groups,
> > + unsigned * const num_groups) {
> > +sizeof(unsigned
> > + pmx_desc->pins = info->pins;
> > + pmx_desc->npins = info->npins;
> > + pmx_desc->maxpin = info->maxpin;
> > +}
> > +
> > +static const struct of_device_id imx_pmx_dt_ids[] = { #ifdef
> > +CONFIG_PINMUX_IMX6Q
> > + { .compatible = "fsl,imx6q-iomuxc", .data = (void *)
> &imx6q_pinctrl_info,
> > }, +#endif
> > +#ifdef CONFIG_PINMUX_IMX53
> > + { .compatible = "fsl,imx53-iomuxc", .data = (void *)
> &imx53_pinctrl_info,
> > }, +#endif
> > + { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, imx_pmx_dt_ids);
> > +
> > +static int __init imx_pmx_probe(struct platform_device *pdev) {
> > + struct imx_pmx *ipmx = platform_get_drvdata(pdev);
> > +
> > + pinctrl_unregister(ipmx->pctl);
> > + platform_set_drvdata(pdev, NULL);
> > +
> > + return 0;
> > +}
> > +
> > +static struct platform_driver imx_pmx_driver = {
> > + .driver = {
> > + .name = DRIVER_NAME,
> > + .owner = THIS_MODULE,
> > + .of_match_table = imx_pmx_dt_ids,
> > + },
> > + .remove = __exit_p(imx_pmx_remove),
> > +};
> > +
> > +static int __init imx_pmx_init(void)
> > +{
> > + return platform_driver_probe(&imx_pmx_driver, imx_pmx_probe); }
> > +arch_initcall(imx_pmx_init);
> > +
> > +static void __exit imx_pmx_exit(void) {
> > + platform_driver_unregister(&imx_pmx_driver);
> > +}
> > +module_exit(imx_pmx_exit);
> > +
> > +MODULE_AUTHOR("Dong Aisheng <dong.a...@linaro.org>");
> > +MODULE_DESCRIPTION("IMX Pin Control Driver"); MODULE_LICENSE("GPL
> > +v2");
> > diff --git a/drivers/pinctrl/pinctrl-imx-core.h
> > b/drivers/pinctrl/pinctrl-imx-core.h new file mode 100644 index
> > 0000000..df69cd0
> > --- /dev/null
> > +++ b/drivers/pinctrl/pinctrl-imx-core.h
> > @@ -0,0 +1,86 @@
> > +/*
> > + * IMX pinmux core definitions
> > + *
> > + * Copyright (C) 2011 Freescale Semiconductor, Inc.
> > + * Copyright (C) 2011 Linaro Ltd.
> > + *
> > + * Author: Dong Aisheng <dong.a...@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > +modify
> > + * it under the terms of the GNU General Public License as published
> > +by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
> > +
> > +#ifndef __DRIVERS_PINCTRL_PINMUX_IMX_H #define
> > +__DRIVERS_PINCTRL_PINMUX_IMX_H
> > +extern struct imx_pinctrl_info imx53_pinctrl_info; extern struct
> > +imx_pinctrl_info imx6q_pinctrl_info; #endif /*
> > +__DRIVERS_PINCTRL_PINMUX_IMX_H */
> > diff --git a/drivers/pinctrl/pinctrl-imx53.c
> > b/drivers/pinctrl/pinctrl-imx53.c new file mode 100644 index
> > 0000000..079b25e
> > --- /dev/null
> > +++ b/drivers/pinctrl/pinctrl-imx53.c
> > @@ -0,0 +1,443 @@
> > +/*
> > + * imx53 pinctrl driver based on imx pinmux core
> > + *
> > + * Copyright (C) 2011 Freescale Semiconductor, Inc.
> > + * Copyright (C) 2011 Linaro, Inc.
> > + *
> > + * Author: Dong Aisheng <dong.a...@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > +modify
> > + * it under the terms of the GNU General Public License as published
> > +by
> > +/* Pad names for the pinmux subsystem */ static const struct
> > +pinctrl_pin_desc imx53_pinctrl_pads[] = {
> > + .mux_offset = IMX53_IOMUXC_MUX_OFFSET, };
> > diff --git a/drivers/pinctrl/pinctrl-imx6q.c
> > b/drivers/pinctrl/pinctrl-imx6q.c new file mode 100644 index
> > 0000000..4c0e29f
> > --- /dev/null
> > +++ b/drivers/pinctrl/pinctrl-imx6q.c
> > @@ -0,0 +1,433 @@
> > +/*
> > + * imx6q pinctrl driver based on imx pinmux core
> > + *
> > + * Copyright (C) 2011 Freescale Semiconductor, Inc.
> > + * Copyright (C) 2011 Linaro, Inc.
> > + *
> > + * Author: Dong Aisheng <dong.a...@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > +modify
> > + * it under the terms of the GNU General Public License as published
> > +by
> > +/* Pad names for the pinmux subsystem */ static const struct
> > +pinctrl_pin_desc imx6q_pinctrl_pads[] = {
> > + .mux_offset = IMX6Q_IOMUXC_MUX_OFSSET, };
Regards
Dong Aisheng
Regards
Dong Aisheng
It's a bad habit to use an assignment as an expression. It always
looks like someone used '=' instead of '=='.
You should make it clear that that's not the case like:
| while ((child = of_get_next_child(np, child)) != NULL)
Lothar Waßmann
--
___________________________________________________________
Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
www.karo-electronics.de | in...@karo-electronics.de
___________________________________________________________
> -----Original Message-----
> From: Stephen Warren [mailto:swa...@nvidia.com]
> Sent: Wednesday, December 21, 2011 8:39 AM
> To: Dong Aisheng-B29396; linux-...@vger.kernel.org
> Cc: linus....@stericsson.com; s.h...@pengutronix.de;
> rob.h...@calxeda.com; linux-ar...@lists.infradead.org;
> ker...@pengutronix.de; c...@laptop.org; devicetre...@lists.ozlabs.org
> Subject: RE: [RFC PATCH v3 2/5] pinctrl: add dt binding support for pinmux
> mappings
> Importance: High
>
> Dong Aisheng wrote at Tuesday, December 20, 2011 10:41 AM:
> > This patch provies a common API for driver to use to register pinmux
> > mappings from dts file. It is needed for dt support.
>
> Dong,
>
> Thanks for providing a concrete binding to get discussion started. I had
> intended to do this myself, but got side-tracked on other things.
>
> I'll comment exclusively on the documentation in this patch, since any changes
> there will require the code to be changed.
>
First, thanks for such a long and detailed comments.
I spent some time to read and understood.
> > diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl.txt
> > +The pin control subsystem
> > +
> > +The pin control subsystem provides a common API to support parsing
> > +pinmux mappings data from device tree. Each board dts file should
> > +provide a device node of which all the child nodes are the corresponding
> pinmux mappings.
>
> So, the binding you propose seems very reasonable from the point-of-view of the
> Linux pinctrl subsystem. However, it violates basic device tree philosophy in a
> few ways. Some background:
>
> Device tree is supposed to be a pure representation of hardware, not the
> software that runs on it. This means a couple of things: (a) the nodes in the DT
> generally match 1:1 with specific HW on the board (b) the design of the bindings
> should be justifiable given HW datasheets without any reference to specific
> operating systems or software driver design
> (c) the DT should be useful to all operating systems that run on the HW; there
> should be no "DT for Linux", "DT for FreeBSD", "DT for Windows".
>
I'm not DT expert, but it looks reasonable and correct.
> Hence, I see a few problems with this binding:
>
> a) The binding is documented as being for the pinctrl subsystem, rather than for
> pinmux hardware.
>
Seems yes.
> b) The top-level node ("imx6q-sabreauto-map" below) is not tied to any
> particular piece of hardware (no compatible flag, not reg property etc.)
>
My original purpose was that it was not a hw device node, it was just created for
containing pin map information and referenced by a phandle in iomuxc deivce node
like:
iomuxc@020e0000 {
compatible = "fsl,imx6q-iomuxc";
reg = <0x020e0000 0x4000>;
fsl,pinmux-map = <&pinmux>;
...
}
I could also make it as a sub node of iomuxc, but original design is that sub nodes of
Ioxmuc are already representing each pinmux functions.
To avoid conflict, I put the imx6q-sabreauto-map node out of iomuxc since a phandle
(fsl,pinmux-map ) does the same work well.
For it's not a real hw device node, I was not aware of that DT has such restriction
Before. So I may use it wrongly.
But I have question that I did some research that it seemed not all the nodes in
dts file are pure hw device node
Like:
Sound in arch/arm/boot/dts/tegra-harmony.dts.
sound {
compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
spkr-en-gpios = <&codec 2 0>;
hp-det-gpios = <&gpio 178 0>;
int-mic-en-gpios = <&gpio 184 0>;
ext-mic-en-gpios = <&gpio 185 0>;
};
I did not know how asoc to handle differenct devices binding like soc dai, pcm and machines,
But machine device seems not a real hw device.
Or even the chosen node:
chosen {
bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk0p2 rw rootwait";
};
And I guess chosen is also Linux specific, right?
I don't know how DT define such restrictions or if there's an exception?
> c) The design of the binding is very much derived from the design of the pinctrl
> subsystem's internal data structures. This isn't necessarily bad, since in
> general SW data structures might be very closely related to how HW is put
> together. In this case though, the binding seems very SW oriented.
>
I have the same doubt that some properties of a device node are not pure hw properties
and they're a little depending on the driver design.
Like atmel,use-dma-rx in arch/arm/boot/dts/at91sam9g20.dtsi
usart0: serial@fffb0000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffb0000 0x200>;
interrupts = <6>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
};
And flash for partitions binding in arch/powerpc/boot/dts/mpc8378_mds.dts,
flash@0,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0 0x0 0x2000000>;
bank-width = <2>;
device-width = <1>;
u-boot@0 {
reg = <0x0 0x100000>;
read-only;
};
fs@100000 {
reg = <0x100000 0x800000>;
};
kernel@1d00000 {
reg = <0x1d00000 0x200000>;
};
dtb@1f00000 {
reg = <0x1f00000 0x100000>;
};
};
It depends on driver to implement it.
It loos like a historical issue since we have platform data in old way
to tell the driver what features to be enabled or not like pio or dma.
And the platform data is easily to be driver specific.
> > +The required properties for pinmux mapping are:
> > +- map-name: the name of this specific map entry
> > +- clk-dev-name: the name of the device controlling this specific
> > +mapping
> > +- funcion: a function in the driver to use for this mapping
> > +
> > +Optional properties:
> > +- group: a certain specific pin group to activate for the function
> > +- dev-name: the name of the device using this specific mapping
> > +- hog-on-boot: indicate wether hog the mappings(do not need to
> > +specify value)
> > +
> > +Examples:
> > +
> > +pinmux: imx6q-sabreauto-map {
>
> Here we have an all-encompassing standalone "pinctrl mapping table" node.
> If we continue to have such an all-encompassing table, it should really be part
> of (a child of) the pinmux HW's node in order to tie it directly to the HW,
> rather than standing out as a HW concept. So, perhaps something more like:
>
> iomuxc@020e0000 {
> compatible = "fsl,imx6-pinmux";
> usage { // I can't think of a good name for the table right now
> sd4 {
> };
> sd3 {
> };
> ...
> };
> };
>
I already define pinmux functions like this:
iomuxc@020e0000 {
fsl,pinmux-map = <&pinmux>;
pinmux-uart4 {
func-name = "uart4";
grp-name = "uart4grp";
grp-pins = <107 108>;
num-pins = <2>;
grp-mux = <4 4>;
num-mux = <2>;
};
pinmux-sd4 {
func-name = "sd4";
grp-name = "sd4grp";
grp-pins = <170 171 180 181 182 183 184 185 186 187>;
num-pins = <10>;
grp-mux = <0 0 1 1 1 1 1 1 1 1>;
num-mux = <10>;
};
};
So I move the pinmux mapping node out as I said above.
Yes, I agree, could remove it.
> > + ctrl-dev-name = "20e0000.iomuxc";
> ...
> > + dev-name = "219c000.usdhc";
>
> That name is Linux-specific. Instead of using device names, we should use
> phandle references, e.g. see the "dev" property below:
>
Yes, I agree, will consider to change it.
> sdhci1: sdhci@1000 {
> ...
> };
> sdhci2: sdhci@1000 {
> ...
> };
> iomuxc@020e0000 {
> compatible = "fsl,imx6-pinmux";
> usage {
> sd4 {
> dev = <&sdhci1>;
> };
> sd3 {
> dev = <&sdhci2>;
> };
> ...
> };
> };
>
> (in the above, your ctrl-dev-name would be implied to be iomuxc@020e0000 since
> the table is part of that pinctrl device's node)
>
> > + function = "sd4";
>
> Here it would be nice to use an integer instead. However, putting lots of opaque
The question is that pinctrl is using string to address the functions.
struct pinmux_map {
const char *name;
struct device *ctrl_dev;
const char *ctrl_dev_name;
const char *function;
const char *group;
struct device *dev;
const char *dev_name;
bool hog_on_boot;
};
I wonder if using integer, we may still need to convert it to string to construct
a pinmux map.
> integers in the device tree is going to be ripe for mistakes.
> It's a real pity that dtc doesn't have a way of doing named integer constants,
> so this could be re-written as e.g.:
>
> SoC .dtsi file:
>
> /define/ TEGRA_MUX_FUNC_SD4 234
>
Actually I was also thinking if we could use macro in dts file, that could make
life much Easier.
> Board .dts file:
>
> function = <TEGRA_MUX_FUNC_SD4>;
>
> Without that feature, using strings here seems the only reasonable thing to do.
>
Up to here I understand that your propose is co-locate pinmux Resource within device
Node definitions and define pinmux maps in the iomuxc device node.
(If I understand wrongly, please let me know)
It's just like:
Sdhci1: sdhci@1000 {
compatible = "...";
regs = <...>;
pinmux = <&pmx>;
pinmux-usage = {
// Some representation of the pins/groups/functions used
// by just this HW block.
};
};
iomuxc@020e0000 {
compatible = "fsl,imx6-pinmux";
usage {
sd4 {
dev = <&sdhci1>;
};
sd3 {
dev = <&sdhci2>;
};
...
};
};
My concern is that would pass the effort to each driver to handle pinmux-usage.
Take mx6q as an example, it may be:
Usdhc4: usdhc@0219c000 { /* uSDHC4 */
compatible = "fsl,imx6q-usdhc";
reg = <0x0219c000 0x4000>;
interrupts = <0 25 0x04>;
status = "disabled";
pinmux-sd4 : sd4{
func-name = "sd4";
grp-name = "sd4grp";
grp-pins = <170 171 180 181 182 183 184 185 186 187>;
num-pins = <10>;
grp-mux = <0 0 1 1 1 1 1 1 1 1>;
num-mux = <10>;
};
};
iomuxc@020e0000 {
compatible = "fsl,imx6-pinmux";
usage {
sd4 {
dev = <&usdhc4>;
function = <&pinmux-sd4>;
};
sd3 {
dev = <&usdhc3>;
};
...
};
};
And I don't think it follows original design purpose: tell me how you are
and I will handle you everything.
The same question applies to clock and regulator: does each device need
Define its clock and regulator properties?
> We also need to consider compatibility and extensibility. A DT binding is an ABI
> between the kernel and whatever is providing it, and so we need to be able to
> maintain and extend it in a compatible fashion, just like the user-space syscall
> ABI. Now it's true that the .dts files are currently part of the kernel source
> tree and can be rev'd in sync with kernel changes, but that may not always be
> the case moving forward.
>
Great, i agree and it's an idea state.
Basically this is a good idea, it's very easy to understand and to use.
The key problem is where we define the pin groups its related functions
I only see pin mappings and configs here.
Since we need to pass these data to pinctrl subsystem, i don't think
it would be good to let the device driver to handle that things.
As well as pinmux, for pin config, I would also split it into two parts,
whether it shoud be handled by each pinctrl driver or pinctrl core.
If it should be handled by pinctrl driver, then ok, let it handled by
Driver and it's driver owner's responsibility to define those properties
in dt since each soc iomux controller may have different properties and
pinctrl core does not need to be aware of such dt things.
If it should be handled by pinctrl core, we may need to define some common
Properties as it needs to be parsed by pinctrl core like pin mappings.
Based on your idea, for pinconfig, one simple approach I could think is that
for pinctrl driver to handle it.
The properties could be:
iomuxc@020e0000 {
fsl,pinmux-map = <&pinmux>;
pinmux-uart4 {
func-name = "uart4";
grp-name = "uart4grp";
grp-pins = <107 108>;
num-pins = <2>;
grp-mux = <4 4>;
num-mux = <2>;
pull-up; /* for group setting */
tri-state; /* for group setting */
};
pinmux-sd4 {
func-name = "sd4";
grp-name = "sd4grp";
grp-pins = <170 171 180 181 182 183 184 185 186 187>;
num-pins = <10>;
grp-mux = <0 0 1 1 1 1 1 1 1 1>;
num-mux = <10>;
/* individual setting for each pin; 0: pull-up 1: tri-state */
conf = <0, 1, 2 ...>;
};
};
Maybe finally remove the name properties would be better, like:
pinmux-uart4 {
grp-pins = <107 108>;
num-pins = <2>;
grp-mux = <4 4>;
num-mux = <2>;
pull-up; /* for group setting */
tri-state; /* for group setting */
};
Regards
Dong Aisheng
I'm not sure if you're saying that the original binding seems reasonable
or my comments seem reasonable.
> > Hence, I see a few problems with this binding:
> >
> > a) The binding is documented as being for the pinctrl subsystem, rather than for
> > pinmux hardware.
>
> Seems yes.
>
> > b) The top-level node ("imx6q-sabreauto-map" below) is not tied to any
> > particular piece of hardware (no compatible flag, not reg property etc.)
>
> My original purpose was that it was not a hw device node, it was just created for
> containing pin map information and referenced by a phandle in iomuxc deivce node
> like:
>
> iomuxc@020e0000 {
> compatible = "fsl,imx6q-iomuxc";
> reg = <0x020e0000 0x4000>;
> fsl,pinmux-map = <&pinmux>;
> ...
> }
>
> I could also make it as a sub node of iomuxc, but original design is that sub nodes of
> Ioxmuc are already representing each pinmux functions.
> To avoid conflict, I put the imx6q-sabreauto-map node out of iomuxc since a phandle
> (fsl,pinmux-map ) does the same work well.
You could have nested sub-nodes, say something like:
iomuxc@020e0000 {
compatible = "fsl,imx6q-iomuxc";
reg = <0x020e0000 0x4000>;
fsl,pins {
... // fsl-specific pin properties
};
fsl,groups {
... // fsl-specific group properties
};
fsl,functions {
... // fsl-specific mux function properties
};
pinmux-usage {
// standardized pinmux "table" properties
sd4 { // pin group name
function = "sdio4"; // this function active on it
...
};
...
}
...
}
> For it's not a real hw device node, I was not aware of that DT has such restriction
> Before. So I may use it wrongly.
> But I have question that I did some research that it seemed not all the nodes in
> dts file are pure hw device node
Certainly there are exceptions; "describe only HW" is more of a general
principle rather than a completely unbreakable rule I think.
I think that pinmux usage is a concept that's very HW oriented and can
hopefully have a pure HW binding, rather than something too influenced
by the pinctrl SW.
> Like:
> Sound in arch/arm/boot/dts/tegra-harmony.dts.
> sound {
> compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
>
> spkr-en-gpios = <&codec 2 0>;
> hp-det-gpios = <&gpio 178 0>;
> int-mic-en-gpios = <&gpio 184 0>;
> ext-mic-en-gpios = <&gpio 185 0>;
> };
> I did not know how asoc to handle differenct devices binding like soc dai, pcm and machines,
> But machine device seems not a real hw device.
I'd still classify this as a pure HW description. While there certainly
isn't a single thing you can point at in the SoC or board that is the
sound card, a description of the components and wiring that makes up the
sound system certainly is a HW description. Note that the binding above
also isn't finished, and has been reworked a bit since then, although
the new one is conceptually very similar.
> Or even the chosen node:
> chosen {
> bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk0p2 rw rootwait";
> };
> And I guess chosen is also Linux specific, right?
Yes, that's certainly SW-specific and an exception, and as you pointed
out below, there are some other exceptions.
My main point is that when we can design bindings that are purely HW
oriented we should, and when we can't, we should get as close as we can.
...
> Up to here I understand that your propose is co-locate pinmux Resource within device
> Node definitions and define pinmux maps in the iomuxc device node.
> (If I understand wrongly, please let me know)
> It's just like:
> Sdhci1: sdhci@1000 {
> compatible = "...";
> regs = <...>;
> pinmux = <&pmx>;
> pinmux-usage = {
> // Some representation of the pins/groups/functions used
> // by just this HW block.
> };
> };
>
> iomuxc@020e0000 {
> compatible = "fsl,imx6-pinmux";
> usage {
> sd4 {
> dev = <&sdhci1>;
> };
> sd3 {
> dev = <&sdhci2>;
> };
> ...
> };
> };
> My concern is that would pass the effort to each driver to handle pinmux-usage.
See a little above for what I was thinking.
That said, we could probably handle a standardized pinmux-usage property
in each driver without impacting each driver too much; it's just that the
core driver code, or the pinctrl code, would have to scan all device nodes
for this property and act on it, rather than the drivers for each node,
rather like regs/interrupts are handled by core code and converted to
device resources.
...
> The same question applies to clock and regulator: does each device need
> Define its clock and regulator properties?
Yes, in those cases I believe each device does contain a phandle to the
resources it uses.
--
nvpublic
Yes, I could do that.
The extra effort is that we have to manually exclude one pinmux-usage
node in pinmux driver since originally i take the child node count of
iomuxc as the function count since all child nodes are functions,
that why I firstly took the mapping node out of iomuxc, in addition
the old way i used seems to be more brief and clear.
I tried adding pinmux-usage as a sub node of iomuxc and got two issues:
Taking imx6q as an example:
iomuxc@020e0000 {
uart4 {
func-name = "uart4";
grp-name = "uart4grp";
grp-pins = <107 108>;
num-pins = <2>;
grp-mux = <4 4>;
num-mux = <2>;
};
sd4 {
func-name = "sd4";
grp-name = "sd4grp";
grp-pins = <170 171 180 181 182 183 184 185 186 187>;
num-pins = <10>;
grp-mux = <0 0 1 1 1 1 1 1 1 1>;
num-mux = <10>;
};
pinmux-mapping {
uart4 {
function = "uart4";
dev = <&uart4>;
};
usdhc4 {
/* ctrl-dev-name = "20e0000.iomuxc"; */
function = "sd4";
dev = <&usdhc4>;
};
};
};
If we remove ctrl-dev-name and get it from its parent node in drivers as
you suggested,
first, since this work will be done in the common API (pinmux_of_register_mappings
Requires pass the pinmux mapping node to it for construct the mapping table)
It will introduce a restriction that all platforms should define this node
under their pinctrl device node.
Second, it seems we cannot get its parent node device or device name in driver
(can only get node Name which is not sufficient for construct the pin map table
required by pinctrl core) and current device tree subsystem seems do not support
get its associated device from a device node.
We may not be able to construct ctrl-dev-name or ctrl-dev for struct pinmux_map.
I'm not sure if I missed something, if missed please let me know.
To support it, we may need to add support for converting device node
to device. Not sure it's applicable since I still have not tried it.
The same issue applies to dev using a phandle.
I agree from that point of view.
I was ever thought putting a phandle of pinmux function in each device,
Then pinmux mapping table seems not need anymore. Like:
usdhc4: usdhc@0219c000 { /* uSDHC4 */
compatible = "fsl,imx6q-usdhc";
....
pinmux = <&pinmux-sd4>;
};
iomuxc@020e0000 {
pinmux-sd4 : sd4 {
func-name = "sd4";
grp-name = "sd4grp";
grp-pins = <170 171 180 181 182 183 184 185 186 187>;
num-pins = <10>;
grp-mux = <0 0 1 1 1 1 1 1 1 1>;
num-mux = <10>;
};
It is a pure hw point of view to define node.
And it may need to implement a of_pinmux_get.
But what about the pin maps without device associated?
Regards
Dong Aisheng
But we do not bother with it, if we do not have pinmux-usage at all.
See below ...
We do not bother with it, if we do not have pinmux-usage at all.
See below ...
[...]
> I was ever thought putting a phandle of pinmux function in each device,
> Then pinmux mapping table seems not need anymore. Like:
>
> usdhc4: usdhc@0219c000 { /* uSDHC4 */
> compatible = "fsl,imx6q-usdhc";
> ....
> pinmux = <&pinmux-sd4>;
> };
>
> iomuxc@020e0000 {
> pinmux-sd4 : sd4 {
> func-name = "sd4";
> grp-name = "sd4grp";
> grp-pins = <170 171 180 181 182 183 184 185 186 187>;
> num-pins = <10>;
> grp-mux = <0 0 1 1 1 1 1 1 1 1>;
> num-mux = <10>;
> };
>
> It is a pure hw point of view to define node.
That's the way we should go for. This is exactly the same thing that
clk and regulator DT support is doing. And right, in that way, we do
not need pinmux mapping for DT at all.
> And it may need to implement a of_pinmux_get.
To make the pinmux api generic for both dt and non-dt users, the pinmux
client driver should still see/call pinmux_get, something like
of_pinmux_get should be sorted out behind pinmux_get.
> But what about the pin maps without device associated?
>
Do we have such cases?
--
Regards,
Shawn
> From: Dong Aisheng <dong.a...@linaro.org>
Looks idiomatically ideal from a pinctrl point of view, so
Acked-by: Linus Walleij <linus....@linaro.org>
Yours,
Linus Walleij
Does that mean the entire shebang needs to be merged through the
pinctrl subsystem?
If this patch stands on it's own, I think it's proper to merge it into
the DT for-next tree now, since we don't know if this entire series
will make it into the next merge window.
If the patch would anyway happen to end up in two trees,
no big deal.
Rob, can you merge it?
Thanks,
Linus Walleij
> From: Dong Aisheng <dong.a...@linaro.org>
>
> The driver contains the initial support for imx53 and
> imx6q.
Looks real good from a pinctrl point of view.
Acked-by: Linus Walleij <linus....@linaro.org>
Now I guess it's that patch 2/5 that is at the heart of how we proceed
with this. I guess this patch depends on 2/5?
Yours,
Linus Walleij
> From: Dong Aisheng <dong.a...@linaro.org>
>
> This patch provies a common API for driver to use to register pinmux
> mappings from dts file. It is needed for dt support.
Overall I feel lost in this discussion due to limited exposure to
device tree concepts. If I get Stephen Warrens and one of the
DT people's (Rob, Grant) ACK on this I'll be happy to merge it.
Until then, I guess it will need to be refined for the next kernel
cycle.
Yours,
Linus Walleij
Yes. As Stephen has commented, this still needs a bit of work on the
binding.
Rob
>> And it may need to implement a of_pinmux_get.
>
> To make the pinmux api generic for both dt and non-dt users, the pinmux
> client driver should still see/call pinmux_get, something like
> of_pinmux_get should be sorted out behind pinmux_get.
>
>> But what about the pin maps without device associated?
>>
> Do we have such cases?
>
It's hog_on_boot function.
Regards
Dong Aisheng
I tried this way that each device node contains a phandle named
'pinmux' pointing
to a specific pinmux function. When the device calling pinmux_get we will
find the pinmux function and its pinctrl device via this phandle, then
we can construct
a pinmux map to use for this device.
Then we do not need define pinmux map table in dts file any more.
This looks better than before from hw point of vew in define device nodes.
I paste the initial patch here for your review to see if it's ok.
However there're still two issues:
1) since we still do not have a standardized pinmux function
definition(it looks not easy to define since it varies on different
platforms and pinctrl core also does not require a standardized
function, not sure if we should define one)
we can not get pin group info via dt in a standardized way for
construct pinmux map.
That means we do not support parsing multi pin groups for one function from dt.
However it will not affect the function in most case since board dts
file usually know which pin group for which function and usually one
pin group are defined.
I still do not see if any requirement of multi pin groups are needed via dt.
2) we still do not support hog_on_boot due to we do not have pinmux
map tables in dt and it varies a bit
on the using from non-dt platform,
I'm still trying to figuring out a way to cover this issue.
If you have any good suggestion please let me know.
From 651113ff5909cd054396e97f25f386f846046a55 Mon Sep 17 00:00:00 2001
From: Dong Aisheng <b29...@freescale.com>
Date: Thu, 5 Jan 2012 21:11:08 +0800
Subject: [PATCH 1/1] pinctrl: add dt binding support for pinmux mappings
Since dt already has the pinmux map information in dts file, it does
not have a pinmux maps table registered in machine code as non-dt
platfrom does. Instead, it will create a pinmux map for each device
dynamically by parsing the device node when calling pinmux_get.
To support this, each device wanting to use a pinmux function should
define a phandle named 'pinmux' pointing to a specific pinmux function
under its device node. And the pinmux function nodes should be defined
under the pinctrl device it belongs to.
The pinmux core will use this phandle to find the pinmux function
name and the pinctrl device this function belongs to to construct
a pinmux map for this device to use.
The constraints are that we still do not support parsing multi groups
for a function via dt, that means only first group will be used.
Usually this does not affect the pinmux to work well via dt since the
board dts file knows which pin group for which function and we do not
need to define more than one useless groups for that function.
Another constraint is that we still do not support hog_on_boot via dt
since dt does not have a pinmux map table and we need to create it
dynamically. We still need to find a good way to cover this issue.
Signed-off-by: Dong Aisheng <b29...@freescale.com>
---
.../devicetree/bindings/pinctrl/pinctrl.txt | 49 ++++++++++++++
arch/arm/boot/dts/imx6q-sabreauto.dts | 24 +++++++
drivers/pinctrl/core.c | 69 ++++++++++++++++++++
drivers/pinctrl/core.h | 2 +
drivers/pinctrl/pinmux.c | 27 +++++++-
5 files changed, 169 insertions(+), 2 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl.txt
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl.txt
b/Documentation/devicetree/bindings/pinctrl/pinctrl.txt
new file mode 100644
index 0000000..013e733
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl.txt
@@ -0,0 +1,49 @@
+The pin control subsystem
+
+The pin control subsystem supports parsing pinmux map from device tree.
+To support this, each device wanting to use a pinmux function should
+define a phandle named 'pinmux' pointing to a specific pinmux function
+under its device node. And the pinmux function nodes should be defined
+under the pinctrl device it belongs to.
+
+The pinmux core will use this phandle to find the pinmux function
+name and the pinctrl device this function belongs to to construct
+a pinmux map for this device to use.
+
+Examples:
+soc {
+ aips-bus@02000000 { /* AIPS1 */
+ iomuxc@020e0000 {
+ pinctrl_uart4: uart4 {
+ func-name = "uart4";
+ grp-name = "uart4grp";
+ grp-pins = <107 108>;
+ num-pins = <2>;
+ grp-mux = <4 4>;
+ num-mux = <2>;
+ };
+
+ pinctrl_sd4: sd4 {
+ func-name = "sd4";
+ grp-name = "sd4grp";
+ grp-pins = <170 171 180 181 182 183 184 185 186 187>;
+ num-pins = <10>;
+ grp-mux = <0 0 1 1 1 1 1 1 1 1>;
+ num-mux = <10>;
+ };
+ };
+ };
+
+ aips-bus@02100000 { /* AIPS2 */
+ usdhc@0219c000 { /* uSDHC4 */
+ fsl,card-wired;
+ status = "okay";
+ pinmux = <&pinctrl_sd4>;
+ };
+
+ uart3: uart@021f0000 { /* UART4 */
+ status = "okay";
+ pinmux = <&pinctrl_uart4>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q-sabreauto.dts
b/arch/arm/boot/dts/imx6q-sabreauto.dts
index 072974e..0863b1d 100644
--- a/arch/arm/boot/dts/imx6q-sabreauto.dts
+++ b/arch/arm/boot/dts/imx6q-sabreauto.dts
@@ -26,6 +26,28 @@
};
soc {
+ aips-bus@02000000 { /* AIPS1 */
+ iomuxc@020e0000 {
+ pinctrl_uart4: uart4 {
+ func-name = "uart4";
+ grp-name = "uart4grp";
+ grp-pins = <107 108>;
+ num-pins = <2>;
+ grp-mux = <4 4>;
+ num-mux = <2>;
+ };
+
+ pinctrl_sd4: sd4 {
+ func-name = "sd4";
+ grp-name = "sd4grp";
+ grp-pins = <170 171 180 181 182 183 184 185 186 187>;
+ num-pins = <10>;
+ grp-mux = <0 0 1 1 1 1 1 1 1 1>;
+ num-mux = <10>;
+ };
+ };
+ };
+
aips-bus@02100000 { /* AIPS2 */
enet@02188000 {
phy-mode = "rgmii";
@@ -42,10 +64,12 @@
usdhc@0219c000 { /* uSDHC4 */
fsl,card-wired;
status = "okay";
+ pinmux = <&pinctrl_sd4>;
};
uart3: uart@021f0000 { /* UART4 */
status = "okay";
+ pinmux = <&pinctrl_uart4>;
};
};
};
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 39f393b..09de5fa 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <linux/debugfs.h>
@@ -48,6 +49,74 @@ void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev)
EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
/**
+ * of_get_pinctrl_dev_from_dev() - look up pin controller device via dt
+ * @dev: a device pointer
+ * @map: the pinmux map returned
+ *
+ * Looks up a pin control device matching a certain device name and return
+ * a pinmux map constructed from dt info.
+ */
+struct pinctrl_dev *of_get_pinctrl_dev_from_dev(struct device *dev,
+ struct pinmux_map **map)
+{
+ struct pinctrl_dev *pctldev = NULL;
+ struct device_node *pinmux_np;
+ struct device_node *pinctrl_np;
+ struct pinmux_map *p;
+ bool found = false;
+ char str[16];
+
+ if (!dev || !dev->of_node)
+ return NULL;
+
+ dev_dbg(dev, "find pinctrl dev and pinmux map from device tree\n");
+
+ pinmux_np = of_parse_phandle(dev->of_node, "pinmux", 0);
+ if (!pinmux_np) {
+ dev_err(dev, "unable to get the phandle pinmux\n");
+ return NULL;
+ }
+
+ /* pinmux function nodes should be subnodes of pinctrl device */
+ pinctrl_np = of_get_parent(pinmux_np);
+ if (!pinctrl_np)
+ return NULL;
+
+ mutex_lock(&pinctrldev_list_mutex);
+ list_for_each_entry(pctldev, &pinctrldev_list, node) {
+ if (pctldev->dev->of_node == pinctrl_np) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&pinctrldev_list_mutex);
+
+ if (found) {
+ /*
+ * construct a pinmux map from device tree for this device
+ * Note: for dt we do not specify the pin group, instead we
+ * use the first group as default.
+ */
+ p = devm_kzalloc(dev, sizeof(struct pinmux_map), GFP_KERNEL);
+ if (!p)
+ return NULL;
+ *map = p;
+ snprintf(str, 15, "map_%s", pinmux_np->name);
+ p->name = kstrdup(str, GFP_KERNEL);
+ if (!p->name)
+ return NULL;
+ p->function = pinmux_np->name;
+ p->ctrl_dev = pctldev->dev;
+ p->dev = dev;
+ dev_dbg(dev, "found pinctrl: %s map: %s function %s dev %s\n",
+ dev_name(p->ctrl_dev), p->name,
+ p->function, dev_name(dev));
+ }
+
+ return found ? pctldev : NULL;
+}
+
+/**
* get_pinctrl_dev_from_dev() - look up pin controller device
* @dev: a device pointer, this may be NULL but then devname needs to be
* defined instead
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 5375582..6077508 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -69,6 +69,8 @@ struct pin_desc {
struct pinctrl_dev *get_pinctrl_dev_from_dev(struct device *dev,
const char *dev_name);
+struct pinctrl_dev *of_get_pinctrl_dev_from_dev(struct device *dev,
+ struct pinmux_map **map);
struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, unsigned int pin);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
int pinctrl_get_device_gpio_range(unsigned gpio,
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 432feb6..cc1b32a 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/sysfs.h>
@@ -696,7 +697,7 @@ static void pinmux_free_groups(struct pinmux *pmx)
struct pinmux *pinmux_get(struct device *dev, const char *name)
{
- struct pinmux_map const *map = NULL;
+ struct pinmux_map *map = NULL;
struct pinctrl_dev *pctldev = NULL;
const char *devname = NULL;
struct pinmux *pmx;
@@ -727,7 +728,29 @@ struct pinmux *pinmux_get(struct device *dev,
const char *name)
pmx->func_selector = UINT_MAX;
INIT_LIST_HEAD(&pmx->groups);
- /* Iterate over the pinmux maps to locate the right ones */
+ /*
+ * do a dt based lookup first to see if we can find a pinctrl device
+ * and a pinmux map for a specific device. If not found fallback
+ * to search the pinmux_maps as before.
+ */
+ pctldev = of_get_pinctrl_dev_from_dev(dev, &map);
+ if (pctldev) {
+ ret = pinmux_enable_muxmap(pctldev, pmx, dev,
+ devname, map);
+ if (ret) {
+ pinmux_free_groups(pmx);
+ kfree(pmx);
+ return ERR_PTR(ret);
+ }
+ num_maps++;
+ }
+
+ /*
+ * Iterate over the pinmux maps to locate the right ones
+ * Note: if we're using dt binding, we do not have a predefined pinmux
+ * maps table registered in machine code as non-dt platfrom does.
+ * Then, pinmux_maps_num is 0 by default.
+ */
for (i = 0; i < pinmux_maps_num; i++) {
map = &pinmux_maps[i];
found_map = false;
--
1.7.0.4
Regards
Dong Aisheng
Regards
Dong Aisheng
This seems reasonable to me; the pinmux controller would be defining the
mux options/... that it's providing to the rest of the DT.
> Second, it seems we cannot get its parent node device or device name in driver
> (can only get node Name which is not sufficient for construct the pin map table
> required by pinctrl core) and current device tree subsystem seems do not support
> get its associated device from a device node.
> We may not be able to construct ctrl-dev-name or ctrl-dev for struct pinmux_map.
> I'm not sure if I missed something, if missed please let me know.
> To support it, we may need to add support for converting device node
> to device. Not sure it's applicable since I still have not tried it.
That functionality is pretty easy to implement; it already exists for
other subsystems that refer to parent/controller/... nodes using phandles.
for example, take a look at the implementation of of_node_to_gpiochip()
in drivers/of/gpio.c, which calls gpiochip_find() with a custom match
function that simply compares the gpio_chip's of_node field. Once you
have the chip, you have the device, and can store that in the constructed
mapping table, or call dev_name() on it. I assume there's something similar
for interrupts.
...
> > > The same question applies to clock and regulator: does each device
> > > need Define its clock and regulator properties?
> >
> > Yes, in those cases I believe each device does contain a phandle to the
> > resources it uses.
>
> I was ever thought putting a phandle of pinmux function in each device,
> Then pinmux mapping table seems not need anymore. Like:
>
> usdhc4: usdhc@0219c000 { /* uSDHC4 */
> compatible = "fsl,imx6q-usdhc";
> ....
> pinmux = <&pinmux-sd4>;
> };
>
> iomuxc@020e0000 {
> pinmux-sd4 : sd4 {
> func-name = "sd4";
> grp-name = "sd4grp";
> grp-pins = <170 171 180 181 182 183 184 185 186 187>;
> num-pins = <10>;
> grp-mux = <0 0 1 1 1 1 1 1 1 1>;
> num-mux = <10>;
> };
>
> It is a pure hw point of view to define node.
> And it may need to implement a of_pinmux_get.
> But what about the pin maps without device associated?
Indeed; that's why I'd tend towards defining a table of pinmux usage in
the pinmux node, and having other devices refer to that table.
Still, if the pinmux definitions are in the device nodes, we could simply
make the pinmux controller have such a definition itself too, for the
"system hog" case.
--
nvpublic
Well, we'd probably want to have at least a semi-standardized notion of
how the per-device "pinmux" property worked, much like interrupts and
GPIOs work in the same way everywhere, albeit perhaps with different
property names (for GPIOs) and controller-specific flags arguments etc.
One other thing to note: The per-device data can't be a single phandle
reference, unless the referenced node is some kind of table, and then
we do need a pinmux mapping for DT to define the format of that table.
Reasons being:
* Devices most likely need to configure more than one pin or group of
pins, and may need to configure them to different functions, so we at
least need an array of (pin_group, selected_function) values somewhere.
* We need to represent both mux function selection and arbitrary other
per-pin/group configuration parameters.
* We need to represent pinmux configuration for multiple device/driver
states; suspend, active, idle, ...?
...
> To make the pinmux api generic for both dt and non-dt users, the pinmux
> client driver should still see/call pinmux_get, something like
> of_pinmux_get should be sorted out behind pinmux_get.
>
> > But what about the pin maps without device associated?
>
> Do we have such cases?
I think so.
At least early on, not all drivers will be pinmux-aware, and we'll still
need to set up the pinmux for them. A system wide "pinmux initial
configuration table" or similar would be needed to do this, I think.
This may be transitional.
I can easily see cases where we don't have an explicit driver for HW,
but still need to set up random pinmux configuration as part of basic
system initialization. Perhaps ideally we'd always tie pinmux usage to
some specific device, but the flexibility of not having to do so seems
useful.
--
nvpublic
Before I get too far into reviewing this path, could you explain the
above node in a little more detail; what it is and what the properties
define?
I'm confused because the node has properties for function name and
group name which make sense to define the mux setting for that group.
However, I'm not sure what the grp-pins/num-pins/grp-mux/num-mux
properties are for; if those properties define the available mux options
and for the group and set of pins included in the group, I think the node
is representing too many things in one place. I'd expect to see:
a) Either data in the pinctrl driver or separate DT nodes to define each
available pin group, mux function, etc.; the definition of what the SoC
itself can do.
b) The configuration of each pin group that's used by the particular board.
All that's relevant here is the mux selection for each pin groups; things
like which pins are included in each group are defined by the SoC not the
board and hence wouldn't be included in a per-board node.
Thanks for enlightening me!
--
nvpublic
For imx, I'm against this.
> or separate DT nodes to define each
> available pin group, mux function, etc.; the definition of what the SoC
> itself can do.
This works for me. But we do not necessarily need to enumerate all
the possible groups from the beginning. Instead, we can add the groups
incrementally.
Regards,
Shawn
>
> b) The configuration of each pin group that's used by the particular board.
> All that's relevant here is the mux selection for each pin groups; things
> like which pins are included in each group are defined by the SoC not the
> board and hence wouldn't be included in a per-board node.
> One other thing to note: The per-device data can't be a single phandle
> reference, unless the referenced node is some kind of table,
Just like gpio and clock, it could reasonably be a phandle array
instead of a single phandle for some cases.
> and then
> we do need a pinmux mapping for DT to define the format of that table.
> Reasons being:
>
> * Devices most likely need to configure more than one pin or group of
> pins, and may need to configure them to different functions, so we at
> least need an array of (pin_group, selected_function) values somewhere.
>
> * We need to represent both mux function selection and arbitrary other
> per-pin/group configuration parameters.
>
> * We need to represent pinmux configuration for multiple device/driver
> states; suspend, active, idle, ...?
>
> ...
> > To make the pinmux api generic for both dt and non-dt users, the pinmux
> > client driver should still see/call pinmux_get, something like
> > of_pinmux_get should be sorted out behind pinmux_get.
> >
> > > But what about the pin maps without device associated?
> >
> > Do we have such cases?
>
> I think so.
>
> At least early on, not all drivers will be pinmux-aware, and we'll still
> need to set up the pinmux for them. A system wide "pinmux initial
> configuration table" or similar would be needed to do this, I think.
> This may be transitional.
Ok. But on imx, we usually have those early pinmux setting done in
bootloader.
Regards,
Shawn
>
> I can easily see cases where we don't have an explicit driver for HW,
> but still need to set up random pinmux configuration as part of basic
> system initialization. Perhaps ideally we'd always tie pinmux usage to
> some specific device, but the flexibility of not having to do so seems
> useful.
>
--
> ...
> > > > The same question applies to clock and regulator: does each device
> > > > need Define its clock and regulator properties?
> > >
> > > Yes, in those cases I believe each device does contain a phandle to
> > > the resources it uses.
> >
> > I was ever thought putting a phandle of pinmux function in each
> > device, Then pinmux mapping table seems not need anymore. Like:
> >
> > usdhc4: usdhc@0219c000 { /* uSDHC4 */
> > compatible = "fsl,imx6q-usdhc";
> > ....
> > pinmux = <&pinmux-sd4>;
> > };
> >
> > iomuxc@020e0000 {
> > pinmux-sd4 : sd4 {
> > func-name = "sd4";
> > grp-name = "sd4grp";
> > grp-pins = <170 171 180 181 182 183 184 185 186 187>;
> > num-pins = <10>;
> > grp-mux = <0 0 1 1 1 1 1 1 1 1>;
> > num-mux = <10>;
> > };
> >
> > It is a pure hw point of view to define node.
> > And it may need to implement a of_pinmux_get.
>
> > But what about the pin maps without device associated?
>
> Indeed; that's why I'd tend towards defining a table of pinmux usage in the
> pinmux node, and having other devices refer to that table.
>
Currently we still prefer to use device node relationship to reflect the pinmux
map if we can since as you said pinmux map is little depending on the pinctrl
subsystem implementation.
And I'm trying to do it now.
> Still, if the pinmux definitions are in the device nodes, we could simply make
> the pinmux controller have such a definition itself too, for the "system hog"
> case.
>
Yes, that way I think is like:
iomuxc@020e0000 {
pinctrl_uart4: uart4 {
grp-pins = <107 108>;
grp-mux = <4 4>;
hog_on_boot;
};
}
I'm still trying to find a way to support it in pinctrl core.
Maybe we could do it in the next step and we want to implement pinmux binding first.
Regards
Dong Aisheng
> I'm confused because the node has properties for function name and group name
> which make sense to define the mux setting for that group.
> However, I'm not sure what the grp-pins/num-pins/grp-mux/num-mux properties are
> for; if those properties define the available mux options and for the group and
> set of pins included in the group, I think the node is representing too many
> things in one place. I'd expect to see:
>
> a) Either data in the pinctrl driver or separate DT nodes to define each
> available pin group, mux function, etc.; the definition of what the SoC itself
> can do.
>
> b) The configuration of each pin group that's used by the particular board.
> All that's relevant here is the mux selection for each pin groups; things like
> which pins are included in each group are defined by the SoC not the board and
> hence wouldn't be included in a per-board node.
>
We still have not started pin config work.
For pinmux, one way we thought is trying to define pin groups
in soc dts file and reference that pin group by a phandle in board dts file.
It could be:
In the soc dts file arch/arm/boot/dts/imx6q.dtsi:
iomuxc@020e0000 {
reg = <0x020e0000 0x4000>;
pinmux-groups {
pingrp_uart4: uart4 {
grp-pins = <107 108>;
grp-mux = <4 4>;
};
pingrp_sd4: sd4 {
grp-pins = <170 171 180 181 182 183 184 185 186 187>;
grp-mux = <0 0 1 1 1 1 1 1 1 1>;
}
}
};
In board dts file:
usdhc@0219c000 { /* uSDHC4 */
fsl,card-wired;
status = "okay";
pinmux = <&pinctrl_sd4>;
};
uart3: uart@021f0000 { /* UART4 */
status = "okay";
pinmux = <&pinctrl_uart4>;
};
iomuxc@020e0000 {
pinctrl_uart4: uart4 {
group = <&pingrp_uart4>;
pinconfig = ....;
};
pinctrl_sd4: sd4 {
group = <&pingrp_sd4>;
pinconfig = ....;
};
};
Then we know the whole map information for a specific device without a pinmux map.
Do you think if it's ok?
BTW, for imx we won't define all possible groups since most are useless and
It's hard to cover all cases due to the issue raised by Sascha before.
We only define what we're most using firstly.
Regards
Dong Aisheng
Would it be more proper to have the phandle named as 'pinctrl' than
'pinmux'?
> };
--
Regards,
Shawn
If pinmux usage is defined in each individual device node, and the "hog"
setup is included in the pinmux controller's own device node, then there's
no need for a "hog_on_boot" property; any pinmux setup node that's inside
the pinmux controller node would automatically be a "hog" entry, and
could be activated as soon as the pinmux controller was probed and
registered with the pinctrl subsystem.
(as a minor nit, DT usually uses - not _ in property names, so that would
be "hog-on-boot").
--
nvpublic
I see now.
I'd definitely be inclined to drop the num-pins and num-mux properties;
The values are just len(grp-pins)/4. You can still check that
len(grp-pins)==len(grp-mux) if you want to catch typos etc.
So, this does appear to be conflating the two things: The definition of
what pins are in a pingroup, and the mux function for a particular
setting of that pingroup. I think you need separate nodes for this.
Without separate nodes, there will eventually be a lot of duplication.
A made-up example of the same uart4grp allowing either of two functions
uart3, uart4 to be muxed out onto it:
aips-bus@02000000 { /* AIPS1 */
iomuxc@020e0000 {
pinctrl_uart4_3: uart4@option_3 {
func-name = "uart3";
grp-name = "uart4grp";
grp-pins = <107 108>;
num-pins = <2>;
grp-mux = <3 3>;
num-mux = <2>;
};
pinctrl_uart4_4: uart4@option_4 {
func-name = "uart4";
grp-name = "uart4grp";
grp-pins = <107 108>;
num-pins = <2>;
grp-mux = <3 3>;
num-mux = <2>;
};
}
};
Now I understand that initially you aren't going to type out the complete
list of every available option into imx6q.dtsi because it's probably huge,
but the binding does need to allow you to do so without duplicating a lot
of data, because eventually you'll get boards that use a larger and larger
subset of all the options, so the number you need to represent at once in
imx6q.dtsi will grow.
So I think you need to model the IMX pinmux controller's bindings more on
how the pinctrl subsystem represents objects; separate definitions of pins,
groups of pins, functions, and board settings. Something more like:
imx6q.dtsi:
aips-bus@02000000 { /* AIPS1 */
iomuxc@020e0000 {
/* FIXME: Perhaps need pin nodes here to name them too */
/* A node per group of pins. Each lists the group name, and
* the list of pins in the group */
foogrp: group@100 {
grp-name = "foogrp";
grp-pins = <100 101>;
};
bargrp: group@102 {
grp-name = "bargrp";
grp-pins = <102 103>;
};
bazgrp: group@104 {
grp-name = "bargrp";
grp-pins = <104 105>;
};
/* A node per function that can be muxed onto pin groups,
* each listing the function name, the set of groups it can
* be muxed onto, and the mux selector value to program into
* the groups' mux control register to select it */
uart3func: func@0 {
func-name = "uart3";
/* Length of locations and mux-value must match */
locations = <&foogrp &bargrp>;
mux-value = <0 4>;
};
uart4func: func@1 {
func-name = "uart4";
locations = <&bargrp &bazgrp>;
mux-value = <6 3>;
};
}
};
Or, instead of separate locations and mux-value properties with matching
lengths, perhaps a node for each location:
uart3func: func@0 {
func-name = "uart3";
location@0 {
location = <&foogrp>;
mux-value = <0>;
};
location@1 {
location = <&bargrp>;
mux-value = <4>;
};
};
That's more long-winded, but might be more easily extensible if we need
to add more properties later.
Now in the board's .dts file, you need to specify for each device the
list of pinmux groups the device needs to use, and the function to
select for each group. Perhaps something like:
board.dts:
usdhc@0219c000 { /* uSDHC4 */
fsl,card-wired;
status = "okay";
pinmux = <&foogrp &uart3func &bazgrp &uart4func>;
};
I haven't convinced myself that's actually a good binding, but I think
it does represent the data required for muxing. Some potential issues
as before:
* Do we need to add flags to each entry in the list; GPIO/interrupt do?
* Should "pinmux" be a node, and the configuration of each group be a
separate sub-node, so we can add more properties to each "table" entry
in the future, e.g. pin config parameters?
* For Tegra, I elected to put the definitions of pins, groups, and
functions into the driver rather than in the device tree. This avoids
parsing a heck of a lot of data from device tree. That means there isn't
any per-function node that can be referred to by phandle. Does it make
sense to refer to groups and functions by string name or integer ID
instead of phandle? Perhaps:
usdhc@0219c000 { /* uSDHC4 */
fsl,card-wired;
status = "okay";
pinmux = {
group@0 {
group = "foo";
function = "uart3";
/* You could add pin config options here too */
};
group@1 {
group = "baz";
function = "uart4";
};
};
};
I guess referring to things by name isn't that idiomatic for device tree.
Using integers here would be fine too, so long as dtc gets support for
named constants:
imx6q.dtsi:
/define/ IMX_PINGRP_FOO 0
/define/ IMX_PINGRP_BAR 1
/define/ IMX_PINGRP_BAZ 2
/define/ IMX_PINFUNC_UART3 0
/define/ IMX_PINFUNC_UART4 1
...
board .dts:
usdhc@0219c000 { /* uSDHC4 */
fsl,card-wired;
status = "okay";
pinmux = {
group@0 {
group = <IMX_PINGRP_FOO>;
function = <IMX_PINFUNC_UART3>;
/* You could add pin config options here too */
};
group@1 {
group = <IMX_PINGRP_BAZ>;
function = <IMX_PINFUNC_UART4>;
};
};
};
--
nvpublic
> So, this does appear to be conflating the two things: The definition of
> what pins are in a pingroup, and the mux function for a particular
> setting of that pingroup. I think you need separate nodes for this.
>
At least for imx, we do not have mux function setting for pingroup.
Instead, it only applies to individual pin.
> Without separate nodes, there will eventually be a lot of duplication.
> A made-up example of the same uart4grp allowing either of two functions
> uart3, uart4 to be muxed out onto it:
>
> aips-bus@02000000 { /* AIPS1 */
> iomuxc@020e0000 {
> pinctrl_uart4_3: uart4@option_3 {
> func-name = "uart3";
> grp-name = "uart4grp";
With phandle in dts reflecting the mapping, neither func-name nor
grp-name should be needed, and both can just be dropped, IMO.
> grp-pins = <107 108>;
> num-pins = <2>;
> grp-mux = <3 3>;
> num-mux = <2>;
> };
> pinctrl_uart4_4: uart4@option_4 {
> func-name = "uart4";
> grp-name = "uart4grp";
> grp-pins = <107 108>;
> num-pins = <2>;
> grp-mux = <3 3>;
> num-mux = <2>;
> };
> }
> };
>
> Now I understand that initially you aren't going to type out the complete
> list of every available option into imx6q.dtsi because it's probably huge,
> but the binding does need to allow you to do so without duplicating a lot
> of data, because eventually you'll get boards that use a larger and larger
> subset of all the options, so the number you need to represent at once in
> imx6q.dtsi will grow.
>
> So I think you need to model the IMX pinmux controller's bindings more on
> how the pinctrl subsystem represents objects; separate definitions of pins,
> groups of pins, functions, and board settings. Something more like:
>
> imx6q.dtsi:
>
> aips-bus@02000000 { /* AIPS1 */
> iomuxc@020e0000 {
> /* FIXME: Perhaps need pin nodes here to name them too */
No, it's been listed in imx pinctrl driver.
>
> /* A node per group of pins. Each lists the group name, and
> * the list of pins in the group */
> foogrp: group@100 {
> grp-name = "foogrp";
> grp-pins = <100 101>;
> };
> bargrp: group@102 {
> grp-name = "bargrp";
> grp-pins = <102 103>;
> };
> bazgrp: group@104 {
> grp-name = "bargrp";
> grp-pins = <104 105>;
> };
I agree that we should define pingroups in <soc>.dtsi, but the mux
setting needs to be under the pingroup node too. See comment below ...
> /* A node per function that can be muxed onto pin groups,
> * each listing the function name, the set of groups it can
> * be muxed onto, and the mux selector value to program into
> * the groups' mux control register to select it */
> uart3func: func@0 {
> func-name = "uart3";
> /* Length of locations and mux-value must match */
> locations = <&foogrp &bargrp>;
> mux-value = <0 4>;
This can be easily broken for imx. As the mux setting applies to
individual pin rather than pingroup, it's very valid for foogrp to
have pin 100 muxed on mode 0 while pin 101 on mode 1. That said,
it's not necessarily true that we always have all the pins in
particular pingroup muxed on the same setting for given function.
> };
> uart4func: func@1 {
> func-name = "uart4";
> locations = <&bargrp &bazgrp>;
> mux-value = <6 3>;
> };
I prefer to have function node defined in <board>.dtsi, since it's
all about defining phandle to the correct pingroup, which should be
decided by board design.
> }
> };
>
> Or, instead of separate locations and mux-value properties with matching
> lengths, perhaps a node for each location:
>
> uart3func: func@0 {
> func-name = "uart3";
> location@0 {
> location = <&foogrp>;
> mux-value = <0>;
> };
> location@1 {
> location = <&bargrp>;
> mux-value = <4>;
> };
> };
>
> That's more long-winded, but might be more easily extensible if we need
> to add more properties later.
>
> Now in the board's .dts file, you need to specify for each device the
> list of pinmux groups the device needs to use, and the function to
> select for each group. Perhaps something like:
>
> board.dts:
>
> usdhc@0219c000 { /* uSDHC4 */
> fsl,card-wired;
> status = "okay";
> pinmux = <&foogrp &uart3func &bazgrp &uart4func>;
> };
>
> I haven't convinced myself that's actually a good binding, but I think
> it does represent the data required for muxing. Some potential issues
> as before:
>
> * Do we need to add flags to each entry in the list; GPIO/interrupt do?
>
What's that for right now? I guess we can add it later when we see
the need.
> * Should "pinmux" be a node, and the configuration of each group be a
> separate sub-node, so we can add more properties to each "table" entry
> in the future, e.g. pin config parameters?
>
I do not think it's necessary. 'pinctrl' phandle works perfectly fine
to me at least for now. How pinconf support should be added into
pinctrl subsystem is still up in the air to me.
> * For Tegra, I elected to put the definitions of pins, groups, and
> functions into the driver rather than in the device tree.
IMO, we do not want to do this for imx, as I'm scared of the size
of Tegra pinctrl patches. If we go this way for imx, we will have
even bigger patches.
Doing this does not change the fact that this is bound with Linux
driver details. That said, if the indexing of either pingrp array
or pinfunc array changes in the driver, the binding is broken.
--
Regards,
Shawn
Thanks
Richard
It should depend on particular imx soc pinmux design rather than
pinmux driver. If it's always one-to-one case, we do not need
pinmux at all. Aisheng's patch just did not enumerate all the groups
for given function. Instead, it puts a couple simple examples there
for demonstration.
...
> > > uart4func: func@1 {
> > > func-name = "uart4";
> > > locations = <&bargrp &bazgrp>;
> > > mux-value = <6 3>;
> > > };
> >
> > I prefer to have function node defined in <board>.dtsi, since it's
> > all about defining phandle to the correct pingroup, which should be
> > decided by board design.
> group and function are one-to-one mapped for imx.
Again, it's not the case.
> So if you put function
> in board dts, why not put pin group there too?
If we put pingroup data in <board>.dts, the data will be likely get
duplicated a lot in different board dts files. For example, if
imx6q-sabrelite chooses the same pingroup for usdhc3 and usdhc4 as
imx6q-arm2, the pingroup data will be duplicated between imx6q-arm2.dts
and imx6q-sabrelite.dts.
On the contrary, putting pingroup data in <soc>.dtsi and having function
node in <board>.dts with phandle pointing to the correct pingroup will
help avoid such data duplication.
--
Regards,
Shawn
Doing this will bloat the device tree dramatically. Actually I had
a patch doing so before the pinctrl subsystem was born, but it
concerned Grant a lot for that reason and thus died.
> it'll be easy to extend pad properties. You know
> the pad may set pull up/down, open drain, drive strenth, daisy chain etc.
> The features have to be supported, to make your model usefull.
>
As Aisheng mentioned, the pinconf support will be added later.
--
Regards,
Shawn
Thanks
Richard
>
> --
> Regards,
> Shawn
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-ar...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
--
[snip lots of discussion]
Someone copied me on this so I feel I can sneak in with a response. I
have read this entire thread and implemented Tegra pinmux in U-boot,
but not much else on the topic so have limited understanding,
particular of the kernel pinmux setup, unfortunately. Sorry if I have
the wrong end of the stick on some of this, but I hope my comments are
useful.
1. Symbolic names
> Stephen said:
> It's a real pity that dtc doesn't have a way of doing named integer
> constants, so this could be re-written as e.g.:
> SoC .dtsi file:
> /define/ TEGRA_MUX_FUNC_SD4 234
IMO this is essential for pinmux. Stephen has already done a patch
which implements this feature. The alternative is bindings with lots
of arbitrary numbers - lots of errors, lots of confusion, lots of
pain. He has asked a few times on the device-tree list for this
feature to be accepted. I believe it should be, and pinmux brough in
with that in mind. Turning symbols into numbers is the role of the
device tree compiler I think.
If Stephen's proposed grammar needs tweaking that is fine, but I think
we are pushing the limits of a pure numerical representation here.
2. Stephen also said:
> We also need to consider compatibility and extensibility. A DT binding
> is an ABI between the kernel and whatever is providing it, and so we
> need to be able to maintain and extend it in a compatible fashion, just
> like the user-space syscall ABI. Now it's true that the .dts files are
> currently part of the kernel source tree and can be rev'd in sync with
> kernel changes, but that may not always be the case moving forward.
>
> In other words, taking a board with an old device tree embedded into
> Flash and running a new kernel using that device tree should work just
> like running the original kernel did.
While this is true we should remember that SOCs will change and
evolve, and we don't actually need a device tree for a Tegra 2 (say)
to be able to boot a Tegra 3 kernel. So each time we create a new SOC
in a family, we have the opportunity to update the fdt, potentially in
an incompatible way, since we know that the old boot loader and new
kernel are incompatible anyway.
Anyway we are looking at pinmux from a 2012 view of how SOCs do
things. We can't predict what things will look like in the future. The
device tree format is great for making things extensible, but there is
an efficiency cost also.
Backwards compatibility can create a lot of problems with newer
designs, so I don't think we should be slaves to it. We are backwards
compatible because it aids understanding, is necessary for kernels to
run across different boards, etc., not just for its own sake. If in
the future we decide that the approach agreed now no longer servers
the purpose and has too much baggage, we can change it. Similar things
happen in the rest of the kernel.
Also IMO updating the kernel without the device tree doesn't make a
huge amount of sense. Why not just update both? Really to me the
device tree is almost like static data for the kernel. It is a worthy
goal to keep it as static as possible, but if it changes I don' t
think it is the end of civilisation.
3. Efficiency
There has been talk about using strings to link things. IMO this is
inefficient and slow compared to integers and device trees already
have phandles. Some platforms will care more than others, but if the
reason for using strings is that the device tree format does not
support symbolic representation of integers, then see 1 above.
4. Who bears the pain?
There is a lot of complexity in pinmux - if we continue to split the
device tree into an SOC file and a board file then we should think
about which one bears the brunt of the complexity. IMO it should be
the SOC file. The SOC file is written by very clever engineers working
for the SOC vendor. They are motivated to get their SOC working
properly and for it to be easy for customers to access the glorious
ground-breaking feature therein. On the other hand, the board file (to
the extent it is not just copied from the vendor's example) is put
together by people with little knowledge of the SOC, limited time to
do the work and minimal interest in the wonders of the device tree
structure.
With this in mind I think the pinmux complexity should mostly be in
the SOC file. This includes the selection of valid pinmux options.
After all, despite the many possible ways that functions could be
brought out of the chip, only a certain few ways typically make sense.
For example, an SDMMC peripheral needs clock and command pins - unless
these are connected then nothing with work. Similarly there is no
sense in having two data[0] pins brought out for the same SDMMC port.
In fact the SOC vendor generally has a good idea about the different
options and mostly there are a small number of useful ones. So why
don't we just enumerate these in the SOC file and let the board select
what it wants in a single setting?
5. Start at the top: function mux
I propose adding a new level at the top, a function mux. This
basically routes functions to one of 2-3 predefined options. So UART1
can come out on 3 different sets of pins, SDMMC2 on two sets, etc.
These are recommended from the vendor and in common use (e.g. on
reference designs), so should be easy to use.
Below the function mux is the group mux. Here we specify a list of pin
groups and which function each group is assigned to. Together these
2-3 groups join to give us the pins that the function mux needs.
Below the pin groups are the pins. Some SOCs will have only one pin
per group, some will have a group mux that really just moves entire
functions around.
IMO the top level belongs with the board file. If the board designer
wants to depart from common options they can suffer the pain of
dropping down to the group level.
So at the board level it would be nice to do something like this:
sdhci@c8000400 {
funcmux = <&sdmmc3-funcmux 0 0>; /* funcmux phandle, config option, flags */
};
which means that we want this SDMMC port to use configuration 0 (out
of perhaps 2-3 recommended options the SOC provides for bringing out
this SDMMC function) and that there are no special flags required. Or:
emmc: sdhci@c8000600 {
funcmux = <&sdmmc4-funcmux 1 OPT_SDMMC_8BIT>;
}
which means for this port we want to use configuration 1 with 8-bit wide data.
Something like this is easy for the board files to deal with. It fits
with the way reference designs are done (selecting from a few
options). It allows flags to specify different options like 4-bit or
8-bit wide SDMMC which can affect what pinmux groups are affected.
Some boot loaders might even implement things only at the funcmux
level, with hard-coded configuration of the actual pin groups in
static data in their code, without reference to the device tree. This
might allow them to operate with a vastly truncated device tree. They
might be very motivated to do this if the full device tree consists of
20KB of strings :-)
6. Groups
Already done in the discussion prior to this email:
uart4func: func@1 {
func-name = "uart4";
locations = <&bargrp &bazgrp>;
mux-value = <6 3>;
};
but how above adding a flag cell and putting the locations and values
into the same property, like:
uart4func: func@1 {
func-name = "uart4";
locations = <&bargrp 6 0>
<&bazgrp 3 SOME_FLAG>;
};
So the SDMMC example might have three options for SDMMC4: a 4-bit one,
and two 8-bit ones (changing 'locations' to 'groups'):
sdmmc4-funcmux : sdmmc4_funcmux@0 {
setting@0 {
config = <0>;
option = <OPT_SDMMC_8BIT>;
groups = <&pingrp-atc FUNC_SDIO4 0> /* clk, cmd, data 1, 3, 5, 7 */
<&pingrp-atd FUNC_SDIO4 0>; /* data 0, 2, 4, 6 */
};
setting@1 {
config = <1>;
option = <0>;
groups = <&pingrp-atb FUNC_SDIO4 0> /* clock, command */
<&pingrp-gma FUNC_SDIO4 0>; /* data[3:0] */
};
setting@2 {
config = <1>;
option = <OPT_SDMMC_8BIT>;
groups = <&pingrp-atb FUNC_SDIO4 0> /* clock, command */
<&pingrp-gma FUNC_SDIO4 0> /* data[3:0] */
<&pingrp-gme FUNC_SDIO4 0>; /* data [7:4] */
};
};
The 'config' property refers to the second cell of the reference in
the funcmux. The option property refers to the third cell. Essentially
the vendor is recommending three possible options for SDMMC4 and the
board can choose which one it likes.
The disadvantage is that the last two share the pingrp-atb setting,
and the last just adds an extra group, but no matter. It is easy to
understand.
A related problem is that the options must each be enumerated. Maybe
that doesn't matter either for the moment.
Then for the groups, again already done above, but I am less clear on
the exact binding that is arrived at above. Something like this?
pingrp-atb: pingrp_atb@0 {
locations = <&pin-i02 &pin-t07>;
control = <&pinmux 0>;
/* 4 options available, numbered 0 to 3 */
functions = <FUNC_IDE FUNC_NAND FUNC_GMI FUNC_SDIO4>;
/* do we want to specify what the flags do here? I assume they are
globally understood by the pinmux system rather than specific to
each group */
};
pingrp-atd: pingrp_atd@0 {
locations = <&pin-h01 &pin-h02 &pin-h03 &pin-h04>;
control = <&pinmux 3>; /* 3 is the pinmux controller's ID for the atd group */
/* 4 options available, numbered 0 to 3 */
functions = <FUNC_IDE FUNC_NAND FUNC_GMI FUNC_SDIO4>;
};
(It is probably obvious, but FUNC_SDIO4 is not just the value 3. It
might be 21 - the pinmux code searches the list of 4 options for
FUNC_SDIO4. The position it finds it in this case is 3, so that is the
value written to &pinmux)
7. Pins
At this level I'm not sure if a device tree representation adds much.
Maybe connect the GPIOs?
pin-i02: pin_i02@0 {
name = "i02";
gpio = <&gpio 66>;
};
pin-t07: pin_t07@0 {
name = "t07";
gpio = <&gpio 167>;
};
8. Flexibility
Someone asked how to deal with an LCD output with 16 bits each of
which can be on two pins. Know you of such an SOC? If so, then it is
still possible that the SOC would provide a few basic 'common' options
at the funcmux level. But board designers may have to steel themselves
and dive into the the pingroup level.
Where an SOC has no groups but only pins, then perhaps the funcmux can
still be provided, but uses a 'pins' property instead of 'groups':
sdmmc4-funcmux : sdmmc4_funcmux@0 {
...
setting@2 {
config = <1>;
option = <OPT_SDMMC_8BIT>;
pins = <&pin-i02 FUNC_SDIO4 0> /* clock */
<&pin-t07 FUNC_SDIO4 0> /* command */
<&pin-a00 FUNC_SDIO4 0> /* data[0] */
<&pin-a01 FUNC_SDIO4 0> /* data[1] */
<&pin-a02 FUNC_SDIO4 0> /* data[2] */
<&pin-a03 FUNC_SDIO4 0>; /* data[3] */
<&pin-a04 FUNC_SDIO4 0>; /* data[4] */
<&pin-a05 FUNC_SDIO4 0>; /* data[5] */
<&pin-a06 FUNC_SDIO4 0>; /* data[6] */
<&pin-a07 FUNC_SDIO4 0>; /* data[7] */
};
};
IMO this sort of thing makes it even more desirable to have a
high-level pinmux feature in the device tree. Again, the board
designer can dive into pins by defining his own custom funcmux-level
things, so no flexibility is lost.
Regards,
Simon
I definitely want to describe pinconf in device tree, though what's
the best interface for pinctrl client driver to talk to pinconf is
still vague to me.
> >
> > > it'll be easy to extend pad properties. You know
> > > the pad may set pull up/down, open drain, drive strenth, daisy chain etc.
> > > The features have to be supported, to make your model usefull.
> > >
> > As Aisheng mentioned, the pinconf support will be added later.
> I expect pinconf come together, and get a ready-to-use patch series.
>
As I was educated by Linus.W, we can not drink ocean and we need to
split big chunk of work into pieces and achieve it step by step.
--
Regards,
Shawn
> and the "hog"
> setup is included in the pinmux controller's own device node, then there's no
> need for a "hog_on_boot" property; any pinmux setup node that's inside the
> pinmux controller node would automatically be a "hog" entry, and could be
> activated as soon as the pinmux controller was probed and registered with the
> pinctrl subsystem.
>
+1
I think this is a right solution for dt without a pinmux map.
> So, this does appear to be conflating the two things: The definition of what
> pins are in a pingroup, and the mux function for a particular setting of that
> pingroup. I think you need separate nodes for this.
>
As shawn said, here the mux for IMX is tightly for each individuals pins rather
than groups.
Since the pins are grouped in functions, the mux for each pin is also fixed for
That function, We prefer to put mux together with pins of group.
You're right.
To keep consistency with the current design of pinctrl subsystem,
I think we should do like that.
> imx6q.dtsi:
>
> aips-bus@02000000 { /* AIPS1 */
> iomuxc@020e0000 {
> /* FIXME: Perhaps need pin nodes here to name them too */
>
We did it in pinctrl driver.
I have not seen any strong reason up till now that we should put pin defines
In dts file.
Your example are right for us and also meet our ideas.
And I'm going to do like that.
> Now in the board's .dts file, you need to specify for each device the list of
> pinmux groups the device needs to use, and the function to select for each group.
> Perhaps something like:
>
> board.dts:
>
> usdhc@0219c000 { /* uSDHC4 */
> fsl,card-wired;
> status = "okay";
> pinmux = <&foogrp &uart3func &bazgrp &uart4func>; };
>
> I haven't convinced myself that's actually a good binding, but I think it does
> represent the data required for muxing. Some potential issues as before:
>
Here is what we should discuss exactly.
Since 'pinmux' phandle will be parsed in pinctrl core, we should try to find and
define a common and standardized pinmux property for all platforms.
From the pinctrl subsystem point of view, specifying the function name and group
name is sufficient for construct a pinmux map for this device.
We can get the two info from the phandle.
So what you describe here seems correct for me.
Pinctrl core can get the function name from the phandle.
Here what I wonder is that do we need to allow the platform to use a func-name
property in their pinmux func node or pinmux group node to specify the name.
If it is allowed, then it could be flexible for soc to define their names.
If not there may be limitations on their node names since we can only get it from
the node name.
Another option is that we could assume each platform may have a func-name property
in their each pinmux function node. If it exists we get the name from func-name
property, if not, we get the name from the pinmux function node name.
For group name it could be in the same way.
Without the func name and group name, pinctrl do not have other special requirements
to for the func node and group node (just like what the pinctrl subsystem does now
in non-dt). It's very flexible and up to each SoC.
To keep consistency as the currently design of pinctrl subsystem and also meet
the dt design philosophy, we still do not introduce a pinmux map in dt.
Instead, we choose to scan all the device node with a 'pinmux' phandle to construct
a pinmux map table before register the pin controller device(here we may also scan
the hog_on_boot node) and I guess it's easy to do that.
After that, we have pinmux map, plus the pinmux function list and group list
(we already have function list and group list defined in the way as Stephen described).
So everything is here and it then can work exacty as the same way as non-dt pinctrl
subsystem works.
Another important thing is that we can still use the sysfs interface exported to user
space for pinctrl subsystem used via dt.
(Without scan the device node to construct the pinmux map table, we can only get the map
Information when we run the pinmux_get.
See: https://lkml.org/lkml/2012/1/5/153
So no pinmux map table exists and we surely do not want to see that the sysfs exporting
pinmux map information works in dt but unwork in non-dt)
BTW it seems you want to support multi pin groups(foogrp and bazgrp) for one device,
do we have such using case?
I guess usually one pin group already contains all the pins of device.
Anyway, just from flexibility view, it's good for me.
> * Do we need to add flags to each entry in the list; GPIO/interrupt do?
>
We can add it when we have the real needs.
> * Should "pinmux" be a node, and the configuration of each group be a separate
> sub-node, so we can add more properties to each "table" entry in the future, e.g.
> pin config parameters?
>
Currently no drivers are using pinctrl subsystem via dt.
So I think we can easy to make changes to improve the design if we really want to.
But before that we should get it running first.
Regards
Dong Aisheng
Thanks
Richard
If you prefer to do a big upfront design of the entire driver then please
by all means do that.
What we need to know right now is what you need from the pin
controller core to do that. We have a (custom) pinconf API now,
does it fit the bill?
I have spent some time on generic pin config, it was not much
commented so if it helps you please ACK the patches.
Next from discussions with Stpehen I've sort of figured out that
we need a config mapping table of sorts and then a means to activate
entries of that table at runtime. I'm trying to come up with something
for this.
Yours,
Regards
Dong Aisheng
Correct for us! :)
>
> 5. Start at the top: function mux
>
> I propose adding a new level at the top, a function mux. This basically routes
> functions to one of 2-3 predefined options. So UART1 can come out on 3 different
> sets of pins, SDMMC2 on two sets, etc.
Yes, that's like what current pinctrl subsystem does.
And I agreed with Stephen we could define it in soc dts file.
> These are recommended from the vendor and in common use (e.g. on reference
> designs), so should be easy to use.
>
Yes, we really do not need to define all possible ones and most of them may not
Useful.
> Below the function mux is the group mux. Here we specify a list of pin groups
> and which function each group is assigned to. Together these
> 2-3 groups join to give us the pins that the function mux needs.
>
> Below the pin groups are the pins. Some SOCs will have only one pin per group,
> some will have a group mux that really just moves entire functions around.
>
> IMO the top level belongs with the board file. If the board designer wants to
> depart from common options they can suffer the pain of dropping down to the
> group level.
>
> So at the board level it would be nice to do something like this:
>
> sdhci@c8000400 {
> funcmux = <&sdmmc3-funcmux 0 0>; /* funcmux phandle, config option, flags
> */ };
>
> which means that we want this SDMMC port to use configuration 0 (out of perhaps
> 2-3 recommended options the SOC provides for bringing out this SDMMC function)
> and that there are no special flags required. Or:
>
> emmc: sdhci@c8000600 {
> funcmux = <&sdmmc4-funcmux 1 OPT_SDMMC_8BIT>; }
>
> which means for this port we want to use configuration 1 with 8-bit wide data.
>
In my understanding a phandle to the 8bit sdmmc pingroup already works.
Why we really need this flag?
If it's sub node of pin controller device, we may not need this.
> /* 4 options available, numbered 0 to 3 */
> functions = <FUNC_IDE FUNC_NAND FUNC_GMI FUNC_SDIO4>;
This does not apply for IMX since the functions here are for each pin rather than
the group.
For IMX, it looks like:
iomuxc@020e0000 {
reg = <0x020e0000 0x4000>;
pinmux-groups {
uart4grp: group@0 {
grp-name = "uart4grp";
grp-pins = <107 108>;
grp-mux = <4 4>;
};
sd4grp: group@1 {
grp-name = "sd4grp";
grp-pins = <170 171 180 181 182 183 184 185 186 187>;
grp-mux = <0 0 1 1 1 1 1 1 1 1>;
}
}
pinmux-functions {
uart4func: func@0 {
func-name = "uart4";
groups = <&uart4grp ..>;
}
sd4func: func@1 {
func-name = "sd4";
groups = <&sd4grp ..>;
}
}
};
And not the pins in 'locations' can support all functions in 'functions' Property.
It may be less flexible.
For IMX different pins in same group may support different type of functions.
> /* do we want to specify what the flags do here? I assume they are
> globally understood by the pinmux system rather than specific to
> each group */
> };
>
>
> pingrp-atd: pingrp_atd@0 {
> locations = <&pin-h01 &pin-h02 &pin-h03 &pin-h04>;
> control = <&pinmux 3>; /* 3 is the pinmux controller's ID for the atd
> group */
> /* 4 options available, numbered 0 to 3 */
> functions = <FUNC_IDE FUNC_NAND FUNC_GMI FUNC_SDIO4>;
> };
>
>
> (It is probably obvious, but FUNC_SDIO4 is not just the value 3. It might be 21
> - the pinmux code searches the list of 4 options for FUNC_SDIO4. The position it
> finds it in this case is 3, so that is the value written to &pinmux)
>
>
> 7. Pins
>
> At this level I'm not sure if a device tree representation adds much.
> Maybe connect the GPIOs?
>
I'm not sure if it's suitable since not all the pins of IMX are gpio pins.
I do not see the necessity.
> If it is allowed, then it could be flexible for soc to define their names.
> If not there may be limitations on their node names since we can only get it from
> the node name.
To me, the node name is perfectly fine to be used for that purpose.
--
Regards,
Shawn
> I have spent some time on generic pin config, it was not much
> commented so if it helps you please ACK the patches.
>
Since the ARM community is the one who is most interested in pinctrl
subsystem so far, I guess copying LAKML will help collect more comments
and various tags. (For example, I'm interested in pinctrl, but I do
not track LKML as close as I do for LAKML).
> Next from discussions with Stpehen I've sort of figured out that
> we need a config mapping table of sorts and then a means to activate
> entries of that table at runtime. I'm trying to come up with something
> for this.
>
That's something we are waiting for pinconf being usable for imx.
--
Regards,
Shawn
OK that's more or less what Stephen said too so I'm cooking a
config table ala pinmux with string identifiers.
>> I have spent some time on generic pin config, it was not much
>> commented so if it helps you please ACK the patches.
>>
> Since the ARM community is the one who is most interested in pinctrl
> subsystem so far, I guess copying LAKML will help collect more comments
> and various tags. �(For example, I'm interested in pinctrl, but I do
> not track LKML as close as I do for LAKML).
True. I'll fix that.
>> Next from discussions with Stpehen I've sort of figured out that
>> we need a config mapping table of sorts and then a means to activate
>> entries of that table at runtime. I'm trying to come up with something
>> for this.
>>
> That's something we are waiting for pinconf being usable for imx.
I'll fix something, please review when it appears!
Thanks,
Linus Walleij
Ah. There's a slight disconnect between my understanding of your HW and
how it really is then! I saw pingroup definitions on Dong's patch, and
hence I assume that your HW was like Tegra, namely that pins were grouped
together for mux control, i.e. muxing isn't a per-pin option. Given that,
some of my responses may not entirely have made sense for your HW...
Just to confirm my understanding:
IMX:
* HW has a set of pins.
* Each pin has a register/field that defines its mux function.
And contrast this to Tegra for reference:
* HW has a set of pins.
* Each pin is a member of a single mux group..
* Each mux group has a register/field that defines its mux function.
This affects all the pins in the group at once, which are all set to
the same logical function (e.g. UART). For that logical function, each
pin has some specific signal muxed onto it. For example, a pin group
"X" may have pins P1 and P2, and when function "UART" is muxed onto "X",
P1 will be UART.RX and P2 UART.TX.
* Note that there also exist other properties that can be configured for
each of these mux groups (e.g. pullup/down, tristate). There also exist
other types of groups that don't align with the mux groups, and each of
those allows various other properties (e.g. drive strength) to be
configured. However, this bullet isn't relevant for the pin mux
discussion, just pin config.
So, my position is that:
* Something (either the pinctrl driver, or the SoC .dtsi file) should
enumerate all available muxable entities that exist in the SoC (pins for
IMX, groups for Tegra).
* Something (either the pinctrl driver, or the SoC .dtsi file) should
enumerate all the available functions that can be assigned to a muxable
entity.
* The enumerations above should be purely at the level the HW exposes,
i.e. if a UART uses 4 signals (RX, TX, CTS, RTS), and the SoC configures
muxing at a per-pin level, and 6 pins exist which can have various UART
signals mux'd on to them, there should be a "muxable entity" enumeration
for each of the 6 pins, not an enumeration for each possible combination
of assignments of signals to pins, since in general that number could be
extremely large as Richard Zao points out in his email that was sent right
after yours.
* pinmux properties in device drivers should list the muxable entities
that they use, and the mux function for each of them.
This is the minimal data model to represent the pure HW functionality,
and is what the pinctrl subsystem uses too.
> > Without separate nodes, there will eventually be a lot of duplication.
> > A made-up example of the same uart4grp allowing either of two functions
> > uart3, uart4 to be muxed out onto it:
> >
> > aips-bus@02000000 { /* AIPS1 */
> > iomuxc@020e0000 {
> > pinctrl_uart4_3: uart4@option_3 {
> > func-name = "uart3";
> > grp-name = "uart4grp";
>
> With phandle in dts reflecting the mapping, neither func-name nor
> grp-name should be needed, and both can just be dropped, IMO.
I'd now argue that these nodes shouldn't even exist in the device tree;
rather the "combination" of which muxable entities are used and their
used mux function should be something in the board .dts files, since its
board-specific.
OK, that's fine too. I just recalled there being such a node in one of
Dong's patches.
> > /* A node per group of pins. Each lists the group name, and
> > * the list of pins in the group */
> > foogrp: group@100 {
> > grp-name = "foogrp";
> > grp-pins = <100 101>;
> > };
> > bargrp: group@102 {
> > grp-name = "bargrp";
> > grp-pins = <102 103>;
> > };
> > bazgrp: group@104 {
> > grp-name = "bargrp";
> > grp-pins = <104 105>;
> > };
>
> I agree that we should define pingroups in <soc>.dtsi, but the mux
> setting needs to be under the pingroup node too. See comment below ...
As I mention above, I'd assert we shouldn't have any group nodes in
the .dtsi file for SoCs that don't mux pins in groups at the raw HW level.
> > /* A node per function that can be muxed onto pin groups,
> > * each listing the function name, the set of groups it can
> > * be muxed onto, and the mux selector value to program into
> > * the groups' mux control register to select it */
> > uart3func: func@0 {
> > func-name = "uart3";
> > /* Length of locations and mux-value must match */
> > locations = <&foogrp &bargrp>;
> > mux-value = <0 4>;
>
> This can be easily broken for imx. As the mux setting applies to
> individual pin rather than pingroup, it's very valid for foogrp to
> have pin 100 muxed on mode 0 while pin 101 on mode 1. That said,
> it's not necessarily true that we always have all the pins in
> particular pingroup muxed on the same setting for given function.
OK, that node doesn't make sense for IMX, since muxing is at a per-pin
level. If Tegra were to enumerate the available functions in the .dtsi
file instead of in the pinctrl driver, this node would make sense for
Tegra since it does mux on a per-group basis.
> > };
> > uart4func: func@1 {
> > func-name = "uart4";
> > locations = <&bargrp &bazgrp>;
> > mux-value = <6 3>;
> > };
>
> I prefer to have function node defined in <board>.dtsi, since it's
> all about defining phandle to the correct pingroup, which should be
> decided by board design.
Just to explicitly re-iterate, if there are no groups in HW, I don't
think the .dtsi file should attempt to represent any groups.
(I think I'll talk a little more about this in a response to Richard
Zhao's email later)
I guess as long as we have a #pinmux-cells in the pinmux controller's
node, we could write the driver to accept 2 now (phandle of muxable
entity and mux function value) but also accept 3 in the future (adding
a flags field), and hence have an upgrade path. So, yes, flags aren't
needed now.
> > * Should "pinmux" be a node, and the configuration of each group be a
> > separate sub-node, so we can add more properties to each "table" entry
> > in the future, e.g. pin config parameters?
>
> I do not think it's necessary. 'pinctrl' phandle works perfectly fine
> to me at least for now. How pinconf support should be added into
> pinctrl subsystem is still up in the air to me.
Well, I think we definitely need to have a rough idea how to support pin
config in the future; representing the current pin mux as a node rather
than a property seems like a pretty easy way to allow this future
flexibility.
> > * For Tegra, I elected to put the definitions of pins, groups, and
> > functions into the driver rather than in the device tree.
>
> IMO, we do not want to do this for imx, as I'm scared of the size
> of Tegra pinctrl patches. If we go this way for imx, we will have
> even bigger patches.
Now you're confusing me! In one of your answers above, you said:
> > /* FIXME: Perhaps need pin nodes here to name them too */
> No, it's been listed in imx pinctrl driver.
So it sounds like the raw HW capabilities /are/ being enumerated by the
pinctrl driver and not device tree, which is exactly what I was saying
I'd chosen for Tegra. Well, with the exception that IMX's pinctrl driver
doesn't define groups, since the HW doesn't mux in groups.
Perhaps you're talking about enumerating groups of pins, which don't
really exist in HW. I wasn't.
So given that IMX muxes per pin not per group of pins, that "group"
property above should really be named "pin", and the IMX_PINGRP_* values
renamed IMX_PIN_* instead.
In general, it'd be nice to come up with a binding for the users of
pinmux (i.e. the device nodes like usdhc above) that allowed them to
refer to what I've been calling "muxable entity". perhaps instead of
"pin" or "group" the property should be called "mux-point", and it's
up to the pinctrl driver to interpret that as a pin or group ID based
on what its muxable entities are.
> Doing this does not change the fact that this is bound with Linux
> driver details. That said, if the indexing of either pingrp array
> or pinfunc array changes in the driver, the binding is broken.
I don't agree here.
Having a driver state that it wants "pin P" or "group G" to be programmed
to "mux function F" is very purely HW oriented.
The fact this so closely aligns with the data model that the pinctrl
subsystem uses is simply because I pushed for the same pure HW oriented
data model in the pinctrl subsystem; both models were derived from how
the HW works, rather than the binding being derived from the driver.
Equally, the binding for the individual pin mux HW will define what the
integer values for pin/group/function are. In practice, we will choose
the values that the Linux pinctrl driver uses to remove the need for
conversion when parsing the device tree. However, we should be very aware
that the binding is what specifies the values, not the driver, so if the
driver changes its internal representation, it must add conversion code
when parsing the device tree, not require the device tree to change.
That said, I don't see why the pinctrl driver would change its pin, group,
or mux function numbering scheme for a given SoC; the HW is fixed, right?
(Well, for shipping HW, and designs-in-progress can presumably handle some
churn in the device tree binding specification during RTL development
or layout)
If there's a bug in the list of pins/groups/functions, that's probably
also a bug in the device tree binding too, not an arbitrary change, so
it seems fine to fix that, hopefully in as backwards-compatible way as
possible though, i.e. adding missing entries to the end of the list so
there's no renumbering etc. this is unlikely to happen late in the game.
--
nvpublic
I originally misunderstood IMX HW; I though the HW muxed at a group-of-
pins level (as Tegra does), but actually it's muxing at a per-pin level,
hence some of what I wrote may have been confusing to people familiar
with how IMX HW really works.
So yes, I definitely agree that representing all possible mux combinations
(combinations of pins in use and the mux function selected for them) could
be extremely large and we don't want to enumerate /that/ list anywhere; in
.dts files or in the pinctrl driver.
So, as a result of that, and as I mentioned in my immediately previous
email, I don't think those two nodes "uart4@option_3", "uart4@option_4"
should be in the SoC .dtsi file.
Later you wrote:
> group and function are one-to-one mapped for imx. So if you put function
> in board dts, why not put pin group there too?
I agree, I think: Everything that defines the board-specific usage of
the pinmux should be part of the board's .dtsi file, not the SoC's .dtsi
file.
--
nvpublic
Oh, when I wrote in my first mail today that I'd expand on one of my
points when responding to Richard Zhao's email, I actually meant when
responding to this email. Sorry for the confusion!
So, I don't agree with putting the "combinations" in the SoC .dtsi file,
since that could grow it into a huge file that contains a lot of nodes
that are used on some board somewhere, but typically not the "current"
board that's including it.
However, I do see that there are probably lots of common combinations
that get re-used across multiple boards, and you might want a common
place to put those definitions so they don't need to be cut/paste
everywhere.
So, why not create specific include files (.dtsi files) for each of those
combinations? Each include could define one particular common combination
of pin mux usage, or perhaps even a set of them if they're commonly used
together. Each board file would include the SoC .dtsi file, the relevant
set of "pinmux config" .dtsi files, and then include anything custom to
that board. Remember, that include files simply get merged into the device
tree, so you can easily add based definitions (like) regs for e.g. an
SDHCI controller in a SoC .dtsi file, the pinmux properties in a .dtsi
file specific to SHDCI controller 3, and then e.g. CD/WP/power GPIOs in
the final board .dts file.
Following this model, we can initially just put the pinmux config into
each board file, then factor it out into new .dtsi files as/when we see
duplication. We get to start off simple, then clean up by refactoring as
we go.
--
nvpublic
Depending on the context, I both agree and disagree.
Take some random HW module in the SoC. If the HW changes enough to
warrant a new binding between SoC v1 and SoC v2, we can certainly revise
the binding in a non-compatible way, and hence not be shackled by
compatibility issues forever.
However, where SoC v2's HW is the same as or very similar to SoC v1's
hardware, we don't want to arbitrarily introduce a new binding if we
can instead keep it identical, or extend it in a compatible fashion.
The more we keep binding definitions stable, the easier it'll be for
people to create .dts files for the new SoC version. They can simply
copy/rename the existing SoC .dtsi file, not need to learn too much
new stuff, etc.
Finally, in the context of pinmux, we're talking about at least some
kind of common infra-structure for pinmux bindings, just like there's
a common infra-structure for registers, interrupts, GPIOs, etc. Such a
binding will hopefully apply across all SoCs, all boards, etc. Hence,
we have to be much more careful about future extensibility, and having
the binding be general enough for future scenarios.
...
> Also IMO updating the kernel without the device tree doesn't make a
> huge amount of sense. Why not just update both? Really to me the
> device tree is almost like static data for the kernel. It is a worthy
> goal to keep it as static as possible, but if it changes I don' t
> think it is the end of civilisation.
One of the goals of device tree is to have the kernel and DT file be
independent. I know this has been discussed a bit before, but can't
find it right now; previous discussions probably explain things better
than I will!
I think the main use-case here is:
* Vendor ships a system the boots with DT
* User wants to update to a newer kernel, so they build it and install
it.
* The kernel doesn't contain the .dts file for this random board the
mainline community hasn't even heard of, or the vendor placed the
DT onto the device somewhere that's difficult to update. So, the user
needs to use the old DT with the new kernel.
> 4. Who bears the pain?
>
> There is a lot of complexity in pinmux - if we continue to split the
> device tree into an SOC file and a board file then we should think
> about which one bears the brunt of the complexity. IMO it should be
> the SOC file. The SOC file is written by very clever engineers working
> for the SOC vendor. They are motivated to get their SOC working
> properly and for it to be easy for customers to access the glorious
> ground-breaking feature therein. On the other hand, the board file (to
> the extent it is not just copied from the vendor's example) is put
> together by people with little knowledge of the SOC, limited time to
> do the work and minimal interest in the wonders of the device tree
> structure.
Yes, the board file should be as simple as is reasonable.
> With this in mind I think the pinmux complexity should mostly be in
> the SOC file. This includes the selection of valid pinmux options.
Well, either the pinctrl driver /or/ the SoC .dtsi file can enumerate
the legal set of mux options. So, I think the SoC .dtsi file could end
up without having any pinmux data if the driver contains the static
tables.
> After all, despite the many possible ways that functions could be
> brought out of the chip, only a certain few ways typically make sense.
> For example, an SDMMC peripheral needs clock and command pins - unless
> these are connected then nothing with work. Similarly there is no
> sense in having two data[0] pins brought out for the same SDMMC port.
>
> In fact the SOC vendor generally has a good idea about the different
> options and mostly there are a small number of useful ones. So why
> don't we just enumerate these in the SOC file and let the board select
> what it wants in a single setting?
Yes, but the set of legal *combinations* of which function is selected
for each pin/group is much much larger than the individual lists of just
pins/groups and functions. Representing the entire list of combinations
often isn't practical. Instead, see my earlier response where I propose:
* All board-specific configuration go into the board .dts file.
* Where we observe there is commonality between boards, we create another
.dtsi file just for that common part. That allows sharing between board
files, solving the duplication problem, yet doesn't require the SoC.dtsi
file to define a large number of combinations, most of which won't be
useful for an individual board. The SoC vendor could supply the set of
these pinmux .dtsi files if they want.
That said, this seems to add more complexity to me; you have to think a
little about code-sharing, search through all the definitions of the
available options to find the correct pinmux .dtsi file to use etc. I
suspect a large number of FAEs are going to find it a lot easier to just
explicitly enumerate their required pinmux settings in their one board
file and ignore any other board files. But, we can certainly do better
for boards that go upstream, and share as much as we can in the pinmux
.dtsi files.
> 5. Start at the top: function mux
>
> I propose adding a new level at the top, a function mux. This
> basically routes functions to one of 2-3 predefined options. So UART1
As I mentioned above, the set of "predefined options" is large, and not
something we want to enumerate. Requiring enumeration of that set as a
base part of the binding is a non-starter in my opinion (and others have
mentioned this in earlier emails in this thread, and previous discussions
of the pinctrl subsystem).
> can come out on 3 different sets of pins, SDMMC2 on two sets, etc.
> These are recommended from the vendor and in common use (e.g. on
> reference designs), so should be easy to use.
>
> Below the function mux is the group mux. Here we specify a list of pin
> groups and which function each group is assigned to. Together these
> 2-3 groups join to give us the pins that the function mux needs.
That model seems very different to how the HW works. I think the device
tree should represent the HW as closely as possible. Defining which pins
exist, and which mux option to select on a per-pin basis (or per-group
basis where the HW works that way) seems simplest and most direct, and
most familiar to board engineers and readers of the SoC documentation,
which doesn't enumerate all these "possible combinations", but instead
typically talks about which pins/groups exist, and which functions are
legal on those pins/groups.
> Below the pin groups are the pins. Some SOCs will have only one pin
> per group, some will have a group mux that really just moves entire
> functions around.
>
> IMO the top level belongs with the board file. If the board designer
> wants to depart from common options they can suffer the pain of
> dropping down to the group level.
>
> So at the board level it would be nice to do something like this:
>
> sdhci@c8000400 {
> funcmux = <&sdmmc3-funcmux 0 0>; /* funcmux phandle, config option, flags */
> };
>
> which means that we want this SDMMC port to use configuration 0 (out
> of perhaps 2-3 recommended options the SOC provides for bringing out
> this SDMMC function) and that there are no special flags required. Or:
>
> emmc: sdhci@c8000600 {
> funcmux = <&sdmmc4-funcmux 1 OPT_SDMMC_8BIT>;
> }
>
> which means for this port we want to use configuration 1 with 8-bit wide data.
As I mentioned in my response to the U-Boot funcmux discussions to add
this "option" flag, it doesn't really make sense w.r.t to how the HW is
works.
If the HW has an 8-bit bus, you set up the pinmux for that 8-bit bus.
If the HW has a 4-bit bus, you set up the pinmux for that 4-bit bus.
There isn't a case where you select an "8 bit SD bus" option, for a board
where you want to use it in 4-bit mode; you'd just select a 4-bit config
instead.
Note that run-time bus width switching is orthogonal to this and subject
to negotiation between the controller and the SD card; the pinmux should
be setting up the HW for the actual bus width that's present on the board
in all cases.
> Something like this is easy for the board files to deal with. It fits
> with the way reference designs are done (selecting from a few
> options). It allows flags to specify different options like 4-bit or
> 8-bit wide SDMMC which can affect what pinmux groups are affected.
I disagree about reference designs or ease of use here. AFAIK, none of
the Tegra documentation at least talks about any set of supported sets
of pin mux usage for a given controller, but simply documents the set
of pins, groups, and legal functions for each pin/group. The documentation
I've seen for other chips is the same way. And as I mention above, I
believe FAEs and OEMs will find it easier to simply enumerate their
complete pinmux layout at a per-pin/group level, to match the docs.
> Some boot loaders might even implement things only at the funcmux
> level, with hard-coded configuration of the actual pin groups in
> static data in their code, without reference to the device tree. This
> might allow them to operate with a vastly truncated device tree. They
> might be very motivated to do this if the full device tree consists of
> 20KB of strings :-)
Uggh.
We shouldn't burden the device tree binding due to internal implementation
details of any particular software.
That said, yes, we really should avoid strings for pin/group/function/...
names in the DT if at all possible.
If U-Boot isn't going to use the device tree for some random subset of
its configuration, I'm unsure why it'd use DT at all; why not do everything
through board files?
> ...
I didn't respond to individual points in the rest of your email, since
I've basically already answered them in this and immediately previous
emails.
--
nvpublic