pinctrl: imx1 core driver
authorMarkus Pargmann <mpa@pengutronix.de>
Mon, 28 Oct 2013 09:00:36 +0000 (10:00 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 29 Oct 2013 13:54:37 +0000 (06:54 -0700)
Core driver for register formats of imx1/imx21/imx27 processors.

The pins of those processors are grouped into ports. Each port has 32
pins. The pins mux configuration is controlled by registers with 1 or 2
bit per pin, depending on the specific control register.

Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-imx1-core.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-imx1.h [new file with mode: 0644]

index e283c4970d1d4c822b83d86584f63c1b7fdbef47..fcc748f68f4a7881e3b3f77f8e9eb76e32ba9360 100644 (file)
@@ -109,6 +109,11 @@ config PINCTRL_IMX
        select PINMUX
        select PINCONF
 
+config PINCTRL_IMX1_CORE
+       bool
+       select PINMUX
+       select PINCONF
+
 config PINCTRL_IMX35
        bool "IMX35 pinctrl driver"
        depends on OF
index 8476cd9020692c621cc539550aa2db453fd8dc8b..8b334e30553752656e0f64d21a83def96487423f 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_PINCTRL_AT91)    += pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)  += pinctrl-bcm2835.o
 obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
 obj-$(CONFIG_PINCTRL_IMX)      += pinctrl-imx.o
+obj-$(CONFIG_PINCTRL_IMX1_CORE)        += pinctrl-imx1-core.o
 obj-$(CONFIG_PINCTRL_IMX35)    += pinctrl-imx35.o
 obj-$(CONFIG_PINCTRL_IMX51)    += pinctrl-imx51.o
 obj-$(CONFIG_PINCTRL_IMX53)    += pinctrl-imx53.o
diff --git a/drivers/pinctrl/pinctrl-imx1-core.c b/drivers/pinctrl/pinctrl-imx1-core.c
new file mode 100644 (file)
index 0000000..4d5a9e7
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * Core driver for the imx pin controller in imx1/21/27
+ *
+ * Copyright (C) 2013 Pengutronix
+ * Author: Markus Pargmann <mpa@pengutronix.de>
+ *
+ * Based on pinctrl-imx.c:
+ *     Author: Dong Aisheng <dong.aisheng@linaro.org>
+ *     Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *     Copyright (C) 2012 Linaro Ltd.
+ *
+ * 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/bitops.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinctrl-imx1.h"
+
+struct imx1_pinctrl {
+       struct device *dev;
+       struct pinctrl_dev *pctl;
+       void __iomem *base;
+       const struct imx1_pinctrl_soc_info *info;
+};
+
+/*
+ * MX1 register offsets
+ */
+
+#define MX1_DDIR 0x00
+#define MX1_OCR 0x04
+#define MX1_ICONFA 0x0c
+#define MX1_ICONFB 0x10
+#define MX1_GIUS 0x20
+#define MX1_GPR 0x38
+#define MX1_PUEN 0x40
+
+#define MX1_PORT_STRIDE 0x100
+
+
+/*
+ * MUX_ID format defines
+ */
+#define MX1_MUX_FUNCTION(val) (BIT(0) & val)
+#define MX1_MUX_GPIO(val) ((BIT(1) & val) >> 1)
+#define MX1_MUX_DIR(val) ((BIT(2) & val) >> 2)
+#define MX1_MUX_OCONF(val) (((BIT(4) | BIT(5)) & val) >> 4)
+#define MX1_MUX_ICONFA(val) (((BIT(8) | BIT(9)) & val) >> 8)
+#define MX1_MUX_ICONFB(val) (((BIT(10) | BIT(11)) & val) >> 10)
+
+
+/*
+ * IMX1 IOMUXC manages the pins based on ports. Each port has 32 pins. IOMUX
+ * control register are seperated into function, output configuration, input
+ * configuration A, input configuration B, GPIO in use and data direction.
+ *
+ * Those controls that are represented by 1 bit have a direct mapping between
+ * bit position and pin id. If they are represented by 2 bit, the lower 16 pins
+ * are in the first register and the upper 16 pins in the second (next)
+ * register. pin_id is stored in bit (pin_id%16)*2 and the bit above.
+ */
+
+/*
+ * Calculates the register offset from a pin_id
+ */
+static void __iomem *imx1_mem(struct imx1_pinctrl *ipctl, unsigned int pin_id)
+{
+       unsigned int port = pin_id / 32;
+       return ipctl->base + port * MX1_PORT_STRIDE;
+}
+
+/*
+ * Write to a register with 2 bits per pin. The function will automatically
+ * use the next register if the pin is managed in the second register.
+ */
+static void imx1_write_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
+               u32 value, u32 reg_offset)
+{
+       void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
+       int offset = (pin_id % 16) * 2; /* offset, regardless of register used */
+       int mask = ~(0x3 << offset); /* Mask for 2 bits at offset */
+       u32 old_val;
+       u32 new_val;
+
+       dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n",
+                       reg, offset, value);
+
+       /* Use the next register if the pin's port pin number is >=16 */
+       if (pin_id % 32 >= 16)
+               reg += 0x04;
+
+       /* Get current state of pins */
+       old_val = readl(reg);
+       old_val &= mask;
+
+       new_val = value & 0x3; /* Make sure value is really 2 bit */
+       new_val <<= offset;
+       new_val |= old_val;/* Set new state for pin_id */
+
+       writel(new_val, reg);
+}
+
+static void imx1_write_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
+               u32 value, u32 reg_offset)
+{
+       void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
+       int offset = pin_id % 32;
+       int mask = ~BIT_MASK(offset);
+       u32 old_val;
+       u32 new_val;
+
+       /* Get current state of pins */
+       old_val = readl(reg);
+       old_val &= mask;
+
+       new_val = value & 0x1; /* Make sure value is really 1 bit */
+       new_val <<= offset;
+       new_val |= old_val;/* Set new state for pin_id */
+
+       writel(new_val, reg);
+}
+
+static int imx1_read_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
+               u32 reg_offset)
+{
+       void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
+       int offset = pin_id % 16;
+
+       /* Use the next register if the pin's port pin number is >=16 */
+       if (pin_id % 32 >= 16)
+               reg += 0x04;
+
+       return (readl(reg) & (BIT(offset) | BIT(offset+1))) >> offset;
+}
+
+static int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
+               u32 reg_offset)
+{
+       void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
+       int offset = pin_id % 32;
+
+       return !!(readl(reg) & BIT(offset));
+}
+
+static const inline struct imx1_pin_group *imx1_pinctrl_find_group_by_name(
+                               const struct imx1_pinctrl_soc_info *info,
+                               const char *name)
+{
+       const struct imx1_pin_group *grp = NULL;
+       int i;
+
+       for (i = 0; i < info->ngroups; i++) {
+               if (!strcmp(info->groups[i].name, name)) {
+                       grp = &info->groups[i];
+                       break;
+               }
+       }
+
+       return grp;
+}
+
+static int imx1_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+
+       return info->ngroups;
+}
+
+static const char *imx1_get_group_name(struct pinctrl_dev *pctldev,
+                                      unsigned selector)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+
+       return info->groups[selector].name;
+}
+
+static int imx1_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+                              const unsigned int **pins,
+                              unsigned *npins)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+
+       if (selector >= info->ngroups)
+               return -EINVAL;
+
+       *pins = info->groups[selector].pin_ids;
+       *npins = info->groups[selector].npins;
+
+       return 0;
+}
+
+static void imx1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+                  unsigned offset)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+       seq_printf(s, "GPIO %d, function %d, direction %d, oconf %d, iconfa %d, iconfb %d",
+                       imx1_read_bit(ipctl, offset, MX1_GIUS),
+                       imx1_read_bit(ipctl, offset, MX1_GPR),
+                       imx1_read_bit(ipctl, offset, MX1_DDIR),
+                       imx1_read_2bit(ipctl, offset, MX1_OCR),
+                       imx1_read_2bit(ipctl, offset, MX1_ICONFA),
+                       imx1_read_2bit(ipctl, offset, MX1_ICONFB));
+}
+
+static int imx1_dt_node_to_map(struct pinctrl_dev *pctldev,
+                       struct device_node *np,
+                       struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+       const struct imx1_pin_group *grp;
+       struct pinctrl_map *new_map;
+       struct device_node *parent;
+       int map_num = 1;
+       int i, j;
+
+       /*
+        * first find the group of this node and check if we need create
+        * config maps for pins
+        */
+       grp = imx1_pinctrl_find_group_by_name(info, np->name);
+       if (!grp) {
+               dev_err(info->dev, "unable to find group for node %s\n",
+                       np->name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < grp->npins; i++)
+               map_num++;
+
+       new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+
+       *map = new_map;
+       *num_maps = map_num;
+
+       /* create mux map */
+       parent = of_get_parent(np);
+       if (!parent) {
+               kfree(new_map);
+               return -EINVAL;
+       }
+       new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+       new_map[0].data.mux.function = parent->name;
+       new_map[0].data.mux.group = np->name;
+       of_node_put(parent);
+
+       /* create config map */
+       new_map++;
+       for (i = j = 0; i < grp->npins; i++) {
+               new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
+               new_map[j].data.configs.group_or_pin =
+                               pin_get_name(pctldev, grp->pins[i].pin_id);
+               new_map[j].data.configs.configs = &grp->pins[i].config;
+               new_map[j].data.configs.num_configs = 1;
+               j++;
+       }
+
+       dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+               (*map)->data.mux.function, (*map)->data.mux.group, map_num);
+
+       return 0;
+}
+
+static void imx1_dt_free_map(struct pinctrl_dev *pctldev,
+                               struct pinctrl_map *map, unsigned num_maps)
+{
+       kfree(map);
+}
+
+static const struct pinctrl_ops imx1_pctrl_ops = {
+       .get_groups_count = imx1_get_groups_count,
+       .get_group_name = imx1_get_group_name,
+       .get_group_pins = imx1_get_group_pins,
+       .pin_dbg_show = imx1_pin_dbg_show,
+       .dt_node_to_map = imx1_dt_node_to_map,
+       .dt_free_map = imx1_dt_free_map,
+
+};
+
+static int imx1_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+                          unsigned group)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+       const struct imx1_pin *pins;
+       unsigned int npins;
+       int i;
+
+       /*
+        * Configure the mux mode for each pin in the group for a specific
+        * function.
+        */
+       pins = info->groups[group].pins;
+       npins = info->groups[group].npins;
+
+       WARN_ON(!pins || !npins);
+
+       dev_dbg(ipctl->dev, "enable function %s group %s\n",
+               info->functions[selector].name, info->groups[group].name);
+
+       for (i = 0; i < npins; i++) {
+               unsigned int mux = pins[i].mux_id;
+               unsigned int pin_id = pins[i].pin_id;
+               unsigned int afunction = MX1_MUX_FUNCTION(mux);
+               unsigned int gpio_in_use = MX1_MUX_GPIO(mux);
+               unsigned int direction = MX1_MUX_DIR(mux);
+               unsigned int gpio_oconf = MX1_MUX_OCONF(mux);
+               unsigned int gpio_iconfa = MX1_MUX_ICONFA(mux);
+               unsigned int gpio_iconfb = MX1_MUX_ICONFB(mux);
+
+               dev_dbg(pctldev->dev, "%s, pin 0x%x, function %d, gpio %d, direction %d, oconf %d, iconfa %d, iconfb %d\n",
+                               __func__, pin_id, afunction, gpio_in_use,
+                               direction, gpio_oconf, gpio_iconfa,
+                               gpio_iconfb);
+
+               imx1_write_bit(ipctl, pin_id, gpio_in_use, MX1_GIUS);
+               imx1_write_bit(ipctl, pin_id, direction, MX1_DDIR);
+
+               if (gpio_in_use) {
+                       imx1_write_2bit(ipctl, pin_id, gpio_oconf, MX1_OCR);
+                       imx1_write_2bit(ipctl, pin_id, gpio_iconfa,
+                                       MX1_ICONFA);
+                       imx1_write_2bit(ipctl, pin_id, gpio_iconfb,
+                                       MX1_ICONFB);
+               } else {
+                       imx1_write_bit(ipctl, pin_id, afunction, MX1_GPR);
+               }
+       }
+
+       return 0;
+}
+
+static int imx1_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+
+       return info->nfunctions;
+}
+
+static const char *imx1_pmx_get_func_name(struct pinctrl_dev *pctldev,
+                                         unsigned selector)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+
+       return info->functions[selector].name;
+}
+
+static int imx1_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+                              const char * const **groups,
+                              unsigned * const num_groups)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+
+       *groups = info->functions[selector].groups;
+       *num_groups = info->functions[selector].num_groups;
+
+       return 0;
+}
+
+static const struct pinmux_ops imx1_pmx_ops = {
+       .get_functions_count = imx1_pmx_get_funcs_count,
+       .get_function_name = imx1_pmx_get_func_name,
+       .get_function_groups = imx1_pmx_get_groups,
+       .enable = imx1_pmx_enable,
+};
+
+static int imx1_pinconf_get(struct pinctrl_dev *pctldev,
+                            unsigned pin_id, unsigned long *config)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+       *config = imx1_read_bit(ipctl, pin_id, MX1_PUEN);
+
+       return 0;
+}
+
+static int imx1_pinconf_set(struct pinctrl_dev *pctldev,
+                            unsigned pin_id, unsigned long *configs,
+                            unsigned num_configs)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+       int i;
+
+       for (i = 0; i != num_configs; ++i) {
+               imx1_write_bit(ipctl, pin_id, configs[i] & 0x01, MX1_PUEN);
+
+               dev_dbg(ipctl->dev, "pinconf set pullup pin %s\n",
+                       info->pins[pin_id].name);
+       }
+
+       return 0;
+}
+
+static void imx1_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+                                  struct seq_file *s, unsigned pin_id)
+{
+       unsigned long config;
+
+       imx1_pinconf_get(pctldev, pin_id, &config);
+       seq_printf(s, "0x%lx", config);
+}
+
+static void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+                                        struct seq_file *s, unsigned group)
+{
+       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+       const struct imx1_pinctrl_soc_info *info = ipctl->info;
+       struct imx1_pin_group *grp;
+       unsigned long config;
+       const char *name;
+       int i, ret;
+
+       if (group > info->ngroups)
+               return;
+
+       seq_puts(s, "\n");
+       grp = &info->groups[group];
+       for (i = 0; i < grp->npins; i++) {
+               name = pin_get_name(pctldev, grp->pins[i].pin_id);
+               ret = imx1_pinconf_get(pctldev, grp->pins[i].pin_id, &config);
+               if (ret)
+                       return;
+               seq_printf(s, "%s: 0x%lx", name, config);
+       }
+}
+
+static const struct pinconf_ops imx1_pinconf_ops = {
+       .pin_config_get = imx1_pinconf_get,
+       .pin_config_set = imx1_pinconf_set,
+       .pin_config_dbg_show = imx1_pinconf_dbg_show,
+       .pin_config_group_dbg_show = imx1_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc imx1_pinctrl_desc = {
+       .pctlops = &imx1_pctrl_ops,
+       .pmxops = &imx1_pmx_ops,
+       .confops = &imx1_pinconf_ops,
+       .owner = THIS_MODULE,
+};
+
+static int imx1_pinctrl_parse_groups(struct device_node *np,
+                                   struct imx1_pin_group *grp,
+                                   struct imx1_pinctrl_soc_info *info,
+                                   u32 index)
+{
+       int size;
+       const __be32 *list;
+       int i;
+
+       dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+       /* Initialise group */
+       grp->name = np->name;
+
+       /*
+        * the binding format is fsl,pins = <PIN MUX_ID CONFIG>
+        */
+       list = of_get_property(np, "fsl,pins", &size);
+       /* we do not check return since it's safe node passed down */
+       if (!size || size % 12) {
+               dev_notice(info->dev, "Not a valid fsl,pins property (%s)\n",
+                               np->name);
+               return -EINVAL;
+       }
+
+       grp->npins = size / 12;
+       grp->pins = devm_kzalloc(info->dev,
+                       grp->npins * sizeof(struct imx1_pin), GFP_KERNEL);
+       grp->pin_ids = devm_kzalloc(info->dev,
+                       grp->npins * sizeof(unsigned int), GFP_KERNEL);
+
+       if (!grp->pins || !grp->pin_ids)
+               return -ENOMEM;
+
+       for (i = 0; i < grp->npins; i++) {
+               grp->pins[i].pin_id = be32_to_cpu(*list++);
+               grp->pins[i].mux_id = be32_to_cpu(*list++);
+               grp->pins[i].config = be32_to_cpu(*list++);
+
+               grp->pin_ids[i] = grp->pins[i].pin_id;
+       }
+
+       return 0;
+}
+
+static int imx1_pinctrl_parse_functions(struct device_node *np,
+                                      struct imx1_pinctrl_soc_info *info,
+                                      u32 index)
+{
+       struct device_node *child;
+       struct imx1_pmx_func *func;
+       struct imx1_pin_group *grp;
+       int ret;
+       static u32 grp_index;
+       u32 i = 0;
+
+       dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+       func = &info->functions[index];
+
+       /* Initialise function */
+       func->name = np->name;
+       func->num_groups = of_get_child_count(np);
+       if (func->num_groups <= 0)
+               return -EINVAL;
+
+       func->groups = devm_kzalloc(info->dev,
+                       func->num_groups * sizeof(char *), GFP_KERNEL);
+
+       if (!func->groups)
+               return -ENOMEM;
+
+       for_each_child_of_node(np, child) {
+               func->groups[i] = child->name;
+               grp = &info->groups[grp_index++];
+               ret = imx1_pinctrl_parse_groups(child, grp, info, i++);
+               if (ret == -ENOMEM)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int imx1_pinctrl_parse_dt(struct platform_device *pdev,
+               struct imx1_pinctrl *pctl, struct imx1_pinctrl_soc_info *info)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *child;
+       int ret;
+       u32 nfuncs = 0;
+       u32 ngroups = 0;
+       u32 ifunc = 0;
+
+       if (!np)
+               return -ENODEV;
+
+       for_each_child_of_node(np, child) {
+               ++nfuncs;
+               ngroups += of_get_child_count(child);
+       }
+
+       if (!nfuncs) {
+               dev_err(&pdev->dev, "No pin functions defined\n");
+               return -EINVAL;
+       }
+
+       info->nfunctions = nfuncs;
+       info->functions = devm_kzalloc(&pdev->dev,
+                       nfuncs * sizeof(struct imx1_pmx_func), GFP_KERNEL);
+
+       info->ngroups = ngroups;
+       info->groups = devm_kzalloc(&pdev->dev,
+                       ngroups * sizeof(struct imx1_pin_group), GFP_KERNEL);
+
+
+       if (!info->functions || !info->groups)
+               return -ENOMEM;
+
+       for_each_child_of_node(np, child) {
+               ret = imx1_pinctrl_parse_functions(child, info, ifunc++);
+               if (ret == -ENOMEM)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+int imx1_pinctrl_core_probe(struct platform_device *pdev,
+                     struct imx1_pinctrl_soc_info *info)
+{
+       struct imx1_pinctrl *ipctl;
+       struct resource *res;
+       struct pinctrl_desc *pctl_desc;
+       int ret;
+
+       if (!info || !info->pins || !info->npins) {
+               dev_err(&pdev->dev, "wrong pinctrl info\n");
+               return -EINVAL;
+       }
+       info->dev = &pdev->dev;
+
+       /* Create state holders etc for this driver */
+       ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
+       if (!ipctl)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENOENT;
+
+       ipctl->base = devm_ioremap_nocache(&pdev->dev, res->start,
+                       resource_size(res));
+       if (IS_ERR(ipctl->base))
+               return PTR_ERR(ipctl->base);
+
+       pctl_desc = &imx1_pinctrl_desc;
+       pctl_desc->name = dev_name(&pdev->dev);
+       pctl_desc->pins = info->pins;
+       pctl_desc->npins = info->npins;
+
+       ret = imx1_pinctrl_parse_dt(pdev, ipctl, info);
+       if (ret) {
+               dev_err(&pdev->dev, "fail to probe dt properties\n");
+               return ret;
+       }
+
+       ipctl->info = info;
+       ipctl->dev = info->dev;
+       platform_set_drvdata(pdev, ipctl);
+       ipctl->pctl = pinctrl_register(pctl_desc, &pdev->dev, ipctl);
+       if (!ipctl->pctl) {
+               dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
+               return -EINVAL;
+       }
+
+       dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");
+
+       return 0;
+}
+
+int imx1_pinctrl_core_remove(struct platform_device *pdev)
+{
+       struct imx1_pinctrl *ipctl = platform_get_drvdata(pdev);
+
+       pinctrl_unregister(ipctl->pctl);
+
+       return 0;
+}
diff --git a/drivers/pinctrl/pinctrl-imx1.h b/drivers/pinctrl/pinctrl-imx1.h
new file mode 100644 (file)
index 0000000..692a54c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * IMX pinmux core definitions
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <dong.aisheng@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_IMX1_H
+#define __DRIVERS_PINCTRL_IMX1_H
+
+struct platform_device;
+
+/**
+ * struct imx1_pin - describes an IMX1/21/27 pin.
+ * @pin_id: ID of the described pin.
+ * @mux_id: ID of the mux setup.
+ * @config: Configuration of the pin (currently only pullup-enable).
+ */
+struct imx1_pin {
+       unsigned int pin_id;
+       unsigned int mux_id;
+       unsigned long config;
+};
+
+/**
+ * struct imx1_pin_group - describes an IMX pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of imx1_pin structs used in this group
+ * @npins: the number of pins in this group array, i.e. the number of
+ *     elements in .pins so we can iterate over that array
+ */
+struct imx1_pin_group {
+       const char *name;
+       unsigned int *pin_ids;
+       struct imx1_pin *pins;
+       unsigned npins;
+};
+
+/**
+ * struct imx1_pmx_func - describes IMX pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @num_groups: the number of groups
+ */
+struct imx1_pmx_func {
+       const char *name;
+       const char **groups;
+       unsigned num_groups;
+};
+
+struct imx1_pinctrl_soc_info {
+       struct device *dev;
+       const struct pinctrl_pin_desc *pins;
+       unsigned int npins;
+       struct imx1_pin_group *groups;
+       unsigned int ngroups;
+       struct imx1_pmx_func *functions;
+       unsigned int nfunctions;
+};
+
+#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
+
+int imx1_pinctrl_core_probe(struct platform_device *pdev,
+                       struct imx1_pinctrl_soc_info *info);
+int imx1_pinctrl_core_remove(struct platform_device *pdev);
+#endif /* __DRIVERS_PINCTRL_IMX1_H */