source "drivers/pcmcia/Kconfig"
 
+source "drivers/pinctrl/Kconfig"
+
 source "drivers/power/Kconfig"
 
 source "drivers/ram/Kconfig"
 
 obj-$(CONFIG_$(SPL_)DM)                += core/
 obj-$(CONFIG_$(SPL_)CLK)       += clk/
 obj-$(CONFIG_$(SPL_)LED)       += led/
+obj-$(CONFIG_$(SPL_)PINCTRL)   += pinctrl/
 obj-$(CONFIG_$(SPL_)RAM)       += ram/
 
 ifdef CONFIG_SPL_BUILD
 
 #include <dm/device.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
+#include <dm/pinctrl.h>
 #include <dm/platdata.h>
 #include <dm/uclass.h>
 #include <dm/uclass-internal.h>
 
        dev->flags |= DM_FLAG_ACTIVATED;
 
+       /* continue regardless of the result of pinctrl */
+       pinctrl_select_state(dev, "default");
+
        ret = uclass_pre_probe_device(dev);
        if (ret)
                goto fail;
 
--- /dev/null
+#
+# PINCTRL infrastructure and drivers
+#
+
+menu "Pin controllers"
+
+config PINCTRL
+       bool "Support pin controllers"
+       depends on DM
+       help
+         This enables the basic support for pinctrl framework.  You may want
+         to enable some more options depending on what you want to do.
+
+config PINCTRL_FULL
+       bool "Support full pin controllers"
+       depends on PINCTRL && OF_CONTROL
+       default y
+       help
+         This provides Linux-compatible device tree interface for the pinctrl
+         subsystem.  This feature depends on device tree configuration because
+         it parses a device tree to look for the pinctrl device which the
+         peripheral device is associated with.
+
+         If this option is disabled (it is the only possible choice for non-DT
+         boards), the pinctrl core provides no systematic mechanism for
+         identifying peripheral devices, applying needed pinctrl settings.
+         It is totally up to the implementation of each low-level driver.
+         You can save memory footprint in return for some limitations.
+
+config PINCTRL_GENERIC
+       bool "Support generic pin controllers"
+       depends on PINCTRL_FULL
+       default y
+       help
+         Say Y here if you want to use the pinctrl subsystem through the
+         generic DT interface.  If enabled, some functions become available
+         to parse common properties such as "pins", "groups", "functions" and
+         some pin configuration parameters.  It would be easier if you only
+         need the generic DT interface for pin muxing and pin configuration.
+         If you need to handle vendor-specific DT properties, you can disable
+         this option and implement your own set_state callback in the pinctrl
+         operations.
+
+config PINMUX
+       bool "Support pin multiplexing controllers"
+       depends on PINCTRL_GENERIC
+       default y
+       help
+         This option enables pin multiplexing through the generic pinctrl
+         framework.
+
+config PINCONF
+       bool "Support pin configuration controllers"
+       depends on PINCTRL_GENERIC
+       help
+         This option enables pin configuration through the generic pinctrl
+         framework.
+
+config SPL_PINCTRL
+       bool "Support pin controlloers in SPL"
+       depends on SPL && SPL_DM
+       help
+         This option is an SPL-variant of the PINCTRL option.
+         See the help of PINCTRL for details.
+
+config SPL_PINCTRL_FULL
+       bool "Support full pin controllers in SPL"
+       depends on SPL_PINCTRL && SPL_OF_CONTROL
+       default y
+       help
+         This option is an SPL-variant of the PINCTRL_FULL option.
+         See the help of PINCTRL_FULL for details.
+
+config SPL_PINCTRL_GENERIC
+       bool "Support generic pin controllers in SPL"
+       depends on SPL_PINCTRL_FULL
+       default y
+       help
+         This option is an SPL-variant of the PINCTRL_GENERIC option.
+         See the help of PINCTRL_GENERIC for details.
+
+config SPL_PINMUX
+       bool "Support pin multiplexing controllers in SPL"
+       depends on SPL_PINCTRL_GENERIC
+       default y
+       help
+         This option is an SPL-variant of the PINMUX option.
+         See the help of PINMUX for details.
+
+config SPL_PINCONF
+       bool "Support pin configuration controllers in SPL"
+       depends on SPL_PINCTRL_GENERIC
+       help
+         This option is an SPL-variant of the PINCONF option.
+         See the help of PINCONF for details.
+
+if PINCTRL || SPL_PINCTRL
+
+endif
+
+endmenu
 
--- /dev/null
+obj-y                                  += pinctrl-uclass.o
+obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC)   += pinctrl-generic.o
 
--- /dev/null
+/*
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <dm/device.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * pinctrl_pin_name_to_selector() - return the pin selector for a pin
+ *
+ * @dev: pin controller device
+ * @pin: the pin name to look up
+ * @return: pin selector, or negative error code on failure
+ */
+static int pinctrl_pin_name_to_selector(struct udevice *dev, const char *pin)
+{
+       const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+       unsigned npins, selector;
+
+       if (!ops->get_pins_count || !ops->get_pin_name) {
+               dev_dbg(dev, "get_pins_count or get_pin_name missing\n");
+               return -ENOSYS;
+       }
+
+       npins = ops->get_pins_count(dev);
+
+       /* See if this pctldev has this pin */
+       for (selector = 0; selector < npins; selector++) {
+               const char *pname = ops->get_pin_name(dev, selector);
+
+               if (!strcmp(pin, pname))
+                       return selector;
+       }
+
+       return -ENOSYS;
+}
+
+/**
+ * pinctrl_group_name_to_selector() - return the group selector for a group
+ *
+ * @dev: pin controller device
+ * @group: the pin group name to look up
+ * @return: pin group selector, or negative error code on failure
+ */
+static int pinctrl_group_name_to_selector(struct udevice *dev,
+                                         const char *group)
+{
+       const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+       unsigned ngroups, selector;
+
+       if (!ops->get_groups_count || !ops->get_group_name) {
+               dev_dbg(dev, "get_groups_count or get_group_name missing\n");
+               return -ENOSYS;
+       }
+
+       ngroups = ops->get_groups_count(dev);
+
+       /* See if this pctldev has this group */
+       for (selector = 0; selector < ngroups; selector++) {
+               const char *gname = ops->get_group_name(dev, selector);
+
+               if (!strcmp(group, gname))
+                       return selector;
+       }
+
+       return -ENOSYS;
+}
+
+#if CONFIG_IS_ENABLED(PINMUX)
+/**
+ * pinmux_func_name_to_selector() - return the function selector for a function
+ *
+ * @dev: pin controller device
+ * @function: the function name to look up
+ * @return: function selector, or negative error code on failure
+ */
+static int pinmux_func_name_to_selector(struct udevice *dev,
+                                       const char *function)
+{
+       const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+       unsigned nfuncs, selector = 0;
+
+       if (!ops->get_functions_count || !ops->get_function_name) {
+               dev_dbg(dev,
+                       "get_functions_count or get_function_name missing\n");
+               return -ENOSYS;
+       }
+
+       nfuncs = ops->get_functions_count(dev);
+
+       /* See if this pctldev has this function */
+       for (selector = 0; selector < nfuncs; selector++) {
+               const char *fname = ops->get_function_name(dev, selector);
+
+               if (!strcmp(function, fname))
+                       return selector;
+       }
+
+       return -ENOSYS;
+}
+
+/**
+ * pinmux_enable_setting() - enable pin-mux setting for a certain pin/group
+ *
+ * @dev: pin controller device
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @func_selector: function selector
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinmux_enable_setting(struct udevice *dev, bool is_group,
+                                unsigned selector, unsigned func_selector)
+{
+       const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+       if (is_group) {
+               if (!ops->pinmux_group_set) {
+                       dev_dbg(dev, "pinmux_group_set op missing\n");
+                       return -ENOSYS;
+               }
+
+               return ops->pinmux_group_set(dev, selector, func_selector);
+       } else {
+               if (!ops->pinmux_set) {
+                       dev_dbg(dev, "pinmux_set op missing\n");
+                       return -ENOSYS;
+               }
+               return ops->pinmux_set(dev, selector, func_selector);
+       }
+}
+#else
+static int pinmux_func_name_to_selector(struct udevice *dev,
+                                       const char *function)
+{
+       return 0;
+}
+
+static int pinmux_enable_setting(struct udevice *dev, bool is_group,
+                                unsigned selector, unsigned func_selector)
+{
+       return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(PINCONF)
+/**
+ * pinconf_prop_name_to_param() - return parameter ID for a property name
+ *
+ * @dev: pin controller device
+ * @property: property name in DTS, such as "bias-pull-up", "slew-rate", etc.
+ * @default_value: return default value in case no value is specified in DTS
+ * @return: return pamater ID, or negative error code on failure
+ */
+static int pinconf_prop_name_to_param(struct udevice *dev,
+                                     const char *property, u32 *default_value)
+{
+       const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+       const struct pinconf_param *p, *end;
+
+       if (!ops->pinconf_num_params || !ops->pinconf_params) {
+               dev_dbg(dev, "pinconf_num_params or pinconf_params missing\n");
+               return -ENOSYS;
+       }
+
+       p = ops->pinconf_params;
+       end = p + ops->pinconf_num_params;
+
+       /* See if this pctldev supports this parameter */
+       for (; p < end; p++) {
+               if (!strcmp(property, p->property)) {
+                       *default_value = p->default_value;
+                       return p->param;
+               }
+       }
+
+       return -ENOSYS;
+}
+
+/**
+ * pinconf_enable_setting() - apply pin configuration for a certain pin/group
+ *
+ * @dev: pin controller device
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @param: configuration paramter
+ * @argument: argument taken by some configuration parameters
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinconf_enable_setting(struct udevice *dev, bool is_group,
+                                 unsigned selector, unsigned param,
+                                 u32 argument)
+{
+       const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+       if (is_group) {
+               if (!ops->pinconf_group_set) {
+                       dev_dbg(dev, "pinconf_group_set op missing\n");
+                       return -ENOSYS;
+               }
+
+               return ops->pinconf_group_set(dev, selector, param,
+                                             argument);
+       } else {
+               if (!ops->pinconf_set) {
+                       dev_dbg(dev, "pinconf_set op missing\n");
+                       return -ENOSYS;
+               }
+               return ops->pinconf_set(dev, selector, param, argument);
+       }
+}
+#else
+static int pinconf_prop_name_to_param(struct udevice *dev,
+                                     const char *property, u32 *default_value)
+{
+       return -ENOSYS;
+}
+
+static int pinconf_enable_setting(struct udevice *dev, bool is_group,
+                                 unsigned selector, unsigned param,
+                                 u32 argument)
+{
+       return 0;
+}
+#endif
+
+/**
+ * pinctrl_generic_set_state_one() - set state for a certain pin/group
+ * Apply all pin multiplexing and pin configurations specified by @config
+ * for a given pin or pin group.
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_generic_set_state_one(struct udevice *dev,
+                                        struct udevice *config,
+                                        bool is_group, unsigned selector)
+{
+       const void *fdt = gd->fdt_blob;
+       int node_offset = config->of_offset;
+       const char *propname;
+       const void *value;
+       int prop_offset, len, func_selector, param, ret;
+       u32 arg, default_val;
+
+       for (prop_offset = fdt_first_property_offset(fdt, node_offset);
+            prop_offset > 0;
+            prop_offset = fdt_next_property_offset(fdt, prop_offset)) {
+               value = fdt_getprop_by_offset(fdt, prop_offset,
+                                             &propname, &len);
+               if (!value)
+                       return -EINVAL;
+
+               if (!strcmp(propname, "function")) {
+                       func_selector = pinmux_func_name_to_selector(dev,
+                                                                    value);
+                       if (func_selector < 0)
+                               return func_selector;
+                       ret = pinmux_enable_setting(dev, is_group,
+                                                   selector,
+                                                   func_selector);
+               } else {
+                       param = pinconf_prop_name_to_param(dev, propname,
+                                                          &default_val);
+                       if (param < 0)
+                               continue; /* just skip unknown properties */
+
+                       if (len >= sizeof(fdt32_t))
+                               arg = fdt32_to_cpu(*(fdt32_t *)value);
+                       else
+                               arg = default_val;
+
+                       ret = pinconf_enable_setting(dev, is_group,
+                                                    selector, param, arg);
+               }
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * pinctrl_generic_set_state_subnode() - apply all settings in config node
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_generic_set_state_subnode(struct udevice *dev,
+                                            struct udevice *config)
+{
+       const void *fdt = gd->fdt_blob;
+       int node = config->of_offset;
+       const char *subnode_target_type = "pins";
+       bool is_group = false;
+       const char *name;
+       int strings_count, selector, i, ret;
+
+       strings_count = fdt_count_strings(fdt, node, subnode_target_type);
+       if (strings_count < 0) {
+               subnode_target_type = "groups";
+               is_group = true;
+               strings_count = fdt_count_strings(fdt, node,
+                                                 subnode_target_type);
+               if (strings_count < 0)
+                       return -EINVAL;
+       }
+
+       for (i = 0; i < strings_count; i++) {
+               ret = fdt_get_string_index(fdt, node, subnode_target_type,
+                                          i, &name);
+               if (ret < 0)
+                       return -EINVAL;
+
+               if (is_group)
+                       selector = pinctrl_group_name_to_selector(dev, name);
+               else
+                       selector = pinctrl_pin_name_to_selector(dev, name);
+               if (selector < 0)
+                       return selector;
+
+               ret = pinctrl_generic_set_state_one(dev, config,
+                                                   is_group, selector);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
+{
+       struct udevice *child;
+       int ret;
+
+       ret = pinctrl_generic_set_state_subnode(dev, config);
+       if (ret)
+               return ret;
+
+       for (device_find_first_child(config, &child);
+            child;
+            device_find_next_child(&child)) {
+               ret = pinctrl_generic_set_state_subnode(dev, child);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
 
--- /dev/null
+/*
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <dm/device.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/uclass.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(PINCTRL_FULL)
+/**
+ * pinctrl_config_one() - apply pinctrl settings for a single node
+ *
+ * @config: pin configuration node
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_config_one(struct udevice *config)
+{
+       struct udevice *pctldev;
+       const struct pinctrl_ops *ops;
+
+       pctldev = config;
+       for (;;) {
+               pctldev = dev_get_parent(pctldev);
+               if (!pctldev) {
+                       dev_err(config, "could not find pctldev\n");
+                       return -EINVAL;
+               }
+               if (pctldev->uclass->uc_drv->id == UCLASS_PINCTRL)
+                       break;
+       }
+
+       ops = pinctrl_get_ops(pctldev);
+       return ops->set_state(pctldev, config);
+}
+
+/**
+ * pinctrl_select_state_full() - full implementation of pinctrl_select_state
+ *
+ * @dev: peripheral device
+ * @statename: state name, like "default"
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
+{
+       const void *fdt = gd->fdt_blob;
+       int node = dev->of_offset;
+       char propname[32]; /* long enough */
+       const fdt32_t *list;
+       uint32_t phandle;
+       int config_node;
+       struct udevice *config;
+       int state, size, i, ret;
+
+       state = fdt_find_string(fdt, node, "pinctrl-names", statename);
+       if (state < 0) {
+               char *end;
+               /*
+                * If statename is not found in "pinctrl-names",
+                * assume statename is just the integer state ID.
+                */
+               state = simple_strtoul(statename, &end, 10);
+               if (*end)
+                       return -EINVAL;
+       }
+
+       snprintf(propname, sizeof(propname), "pinctrl-%d", state);
+       list = fdt_getprop(fdt, node, propname, &size);
+       if (!list)
+               return -EINVAL;
+
+       size /= sizeof(*list);
+       for (i = 0; i < size; i++) {
+               phandle = fdt32_to_cpu(*list++);
+
+               config_node = fdt_node_offset_by_phandle(fdt, phandle);
+               if (config_node < 0) {
+                       dev_err(dev, "prop %s index %d invalid phandle\n",
+                               propname, i);
+                       return -EINVAL;
+               }
+               ret = uclass_get_device_by_of_offset(UCLASS_PINCONFIG,
+                                                    config_node, &config);
+               if (ret)
+                       return ret;
+
+               ret = pinctrl_config_one(config);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * pinconfig_post-bind() - post binding for PINCONFIG uclass
+ * Recursively bind its children as pinconfig devices.
+ *
+ * @dev: pinconfig device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinconfig_post_bind(struct udevice *dev)
+{
+       const void *fdt = gd->fdt_blob;
+       int offset = dev->of_offset;
+       const char *name;
+       int ret;
+
+       for (offset = fdt_first_subnode(fdt, offset);
+            offset > 0;
+            offset = fdt_next_subnode(fdt, offset)) {
+               /*
+                * If this node has "compatible" property, this is not
+                * a pin configuration node, but a normal device. skip.
+                */
+               fdt_get_property(fdt, offset, "compatible", &ret);
+               if (ret >= 0)
+                       continue;
+
+               if (ret != -FDT_ERR_NOTFOUND)
+                       return ret;
+
+               name = fdt_get_name(fdt, offset, NULL);
+               if (!name)
+                       return -EINVAL;
+               ret = device_bind_driver_to_node(dev, "pinconfig", name,
+                                                offset, NULL);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+UCLASS_DRIVER(pinconfig) = {
+       .id = UCLASS_PINCONFIG,
+       .post_bind = pinconfig_post_bind,
+       .name = "pinconfig",
+};
+
+U_BOOT_DRIVER(pinconfig_generic) = {
+       .name = "pinconfig",
+       .id = UCLASS_PINCONFIG,
+};
+
+#else
+static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
+{
+       return -ENODEV;
+}
+
+static int pinconfig_post_bind(struct udevice *dev)
+{
+       return 0;
+}
+#endif
+
+/**
+ * pinctrl_select_state_simple() - simple implementation of pinctrl_select_state
+ *
+ * @dev: peripheral device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_select_state_simple(struct udevice *dev)
+{
+       struct udevice *pctldev;
+       struct pinctrl_ops *ops;
+       int ret;
+
+       /*
+        * For simplicity, assume the first device of PINCTRL uclass
+        * is the correct one.  This is most likely OK as there is
+        * usually only one pinctrl device on the system.
+        */
+       ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
+       if (ret)
+               return ret;
+
+       ops = pinctrl_get_ops(pctldev);
+       if (!ops->set_state_simple) {
+               dev_dbg(dev, "set_state_simple op missing\n");
+               return -ENOSYS;
+       }
+
+       return ops->set_state_simple(pctldev, dev);
+}
+
+int pinctrl_select_state(struct udevice *dev, const char *statename)
+{
+       /*
+        * Try full-implemented pinctrl first.
+        * If it fails or is not implemented, try simple one.
+        */
+       if (pinctrl_select_state_full(dev, statename))
+               return pinctrl_select_state_simple(dev);
+
+       return 0;
+}
+
+/**
+ * pinconfig_post-bind() - post binding for PINCTRL uclass
+ * Recursively bind child nodes as pinconfig devices in case of full pinctrl.
+ *
+ * @dev: pinctrl device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_post_bind(struct udevice *dev)
+{
+       const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+       if (!ops) {
+               dev_dbg(dev, "ops is not set.  Do not bind.\n");
+               return -EINVAL;
+       }
+
+       /*
+        * If set_state callback is set, we assume this pinctrl driver is the
+        * full implementation.  In this case, its child nodes should be bound
+        * so that peripheral devices can easily search in parent devices
+        * during later DT-parsing.
+        */
+       if (ops->set_state)
+               return pinconfig_post_bind(dev);
+
+       return 0;
+}
+
+UCLASS_DRIVER(pinctrl) = {
+       .id = UCLASS_PINCTRL,
+       .post_bind = pinctrl_post_bind,
+       .name = "pinctrl",
+};
 
--- /dev/null
+/*
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __PINCTRL_H
+#define __PINCTRL_H
+
+/**
+ * struct pinconf_param - pin config parameters
+ *
+ * @property: property name in DT nodes
+ * @param: ID for this config parameter
+ * @default_value: default value for this config parameter used in case
+ *     no value is specified in DT nodes
+ */
+struct pinconf_param {
+       const char * const property;
+       unsigned int param;
+       u32 default_value;
+};
+
+/**
+ * struct pinctrl_ops - pin control operations, to be implemented by
+ * pin controller drivers.
+ *
+ * The @set_state is the only mandatory operation.  You can implement your
+ * pinctrl driver with its own @set_state.  In this case, the other callbacks
+ * are not required.  Otherwise, generic pinctrl framework is also available;
+ * use pinctrl_generic_set_state for @set_state, and implement other operations
+ * depending on your necessity.
+ *
+ * @get_pins_count: return number of selectable named pins available
+ *     in this driver.  (necessary to parse "pins" property in DTS)
+ * @get_pin_name: return the pin name of the pin selector,
+ *     called by the core to figure out which pin it shall do
+ *     operations to.  (necessary to parse "pins" property in DTS)
+ * @get_groups_count: return number of selectable named groups available
+ *     in this driver.  (necessary to parse "groups" property in DTS)
+ * @get_group_name: return the group name of the group selector,
+ *     called by the core to figure out which pin group it shall do
+ *     operations to.  (necessary to parse "groups" property in DTS)
+ * @get_functions_count: return number of selectable named functions available
+ *     in this driver.  (necessary for pin-muxing)
+ * @get_function_name: return the function name of the muxing selector,
+ *     called by the core to figure out which mux setting it shall map a
+ *     certain device to.  (necessary for pin-muxing)
+ * @pinmux_set: enable a certain muxing function with a certain pin.
+ *     The @func_selector selects a certain function whereas @pin_selector
+ *     selects a certain pin to be used. On simple controllers one of them
+ *     may be ignored.  (necessary for pin-muxing against a single pin)
+ * @pinmux_group_set: enable a certain muxing function with a certain pin
+ *     group.  The @func_selector selects a certain function whereas
+ *     @group_selector selects a certain set of pins to be used. On simple
+ *     controllers one of them may be ignored.
+ *     (necessary for pin-muxing against a pin group)
+ * @pinconf_num_params: number of driver-specific parameters to be parsed
+ *     from device trees  (necessary for pin-configuration)
+ * @pinconf_params: list of driver_specific parameters to be parsed from
+ *     device trees  (necessary for pin-configuration)
+ * @pinconf_set: configure an individual pin with a given parameter.
+ *     (necessary for pin-configuration against a single pin)
+ * @pinconf_group_set: configure all pins in a group with a given parameter.
+ *     (necessary for pin-configuration against a pin group)
+ * @set_state: do pinctrl operations specified by @config, a pseudo device
+ *     pointing a config node. (necessary for pinctrl_full)
+ * @set_state_simple: do needed pinctrl operations for a peripherl @periph.
+ *     (necessary for pinctrl_simple)
+ */
+struct pinctrl_ops {
+       int (*get_pins_count)(struct udevice *dev);
+       const char *(*get_pin_name)(struct udevice *dev, unsigned selector);
+       int (*get_groups_count)(struct udevice *dev);
+       const char *(*get_group_name)(struct udevice *dev, unsigned selector);
+       int (*get_functions_count)(struct udevice *dev);
+       const char *(*get_function_name)(struct udevice *dev,
+                                        unsigned selector);
+       int (*pinmux_set)(struct udevice *dev, unsigned pin_selector,
+                         unsigned func_selector);
+       int (*pinmux_group_set)(struct udevice *dev, unsigned group_selector,
+                               unsigned func_selector);
+       unsigned int pinconf_num_params;
+       const struct pinconf_param *pinconf_params;
+       int (*pinconf_set)(struct udevice *dev, unsigned pin_selector,
+                          unsigned param, unsigned argument);
+       int (*pinconf_group_set)(struct udevice *dev, unsigned group_selector,
+                                unsigned param, unsigned argument);
+       int (*set_state)(struct udevice *dev, struct udevice *config);
+       int (*set_state_simple)(struct udevice *dev, struct udevice *periph);
+};
+
+#define pinctrl_get_ops(dev)   ((struct pinctrl_ops *)(dev)->driver->ops)
+
+/**
+ * Generic pin configuration paramters
+ *
+ * @PIN_CONFIG_BIAS_DISABLE: disable any pin bias on the pin, a
+ *     transition from say pull-up to pull-down implies that you disable
+ *     pull-up in the process, this setting disables all biasing.
+ * @PIN_CONFIG_BIAS_HIGH_IMPEDANCE: the pin will be set to a high impedance
+ *     mode, also know as "third-state" (tristate) or "high-Z" or "floating".
+ *     On output pins this effectively disconnects the pin, which is useful
+ *     if for example some other pin is going to drive the signal connected
+ *     to it for a while. Pins used for input are usually always high
+ *     impedance.
+ * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
+ *     weakly drives the last value on a tristate bus, also known as a "bus
+ *     holder", "bus keeper" or "repeater". This allows another device on the
+ *     bus to change the value by driving the bus high or low and switching to
+ *     tristate. The argument is ignored.
+ * @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high
+ *     impedance to VDD). If the argument is != 0 pull-up is enabled,
+ *     if it is 0, pull-up is total, i.e. the pin is connected to VDD.
+ * @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high
+ *     impedance to GROUND). If the argument is != 0 pull-down is enabled,
+ *     if it is 0, pull-down is total, i.e. the pin is connected to GROUND.
+ * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: the pin will be pulled up or down based
+ *     on embedded knowledge of the controller hardware, like current mux
+ *     function. The pull direction and possibly strength too will normally
+ *     be decided completely inside the hardware block and not be readable
+ *     from the kernel side.
+ *     If the argument is != 0 pull up/down is enabled, if it is 0, the
+ *     configuration is ignored. The proper way to disable it is to use
+ *     @PIN_CONFIG_BIAS_DISABLE.
+ * @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and
+ *     low, this is the most typical case and is typically achieved with two
+ *     active transistors on the output. Setting this config will enable
+ *     push-pull mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_DRAIN: the pin will be driven with open drain (open
+ *     collector) which means it is usually wired with other output ports
+ *     which are then pulled up with an external resistor. Setting this
+ *     config will enable open drain mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source
+ *     (open emitter). Setting this config will enable open source mode, the
+ *     argument is ignored.
+ * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current
+ *     passed as argument. The argument is in mA.
+ * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input.  Note that this does not
+ *     affect the pin's ability to drive output.  1 enables input, 0 disables
+ *     input.
+ * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: control schmitt-trigger mode on the pin.
+ *      If the argument != 0, schmitt-trigger mode is enabled. If it's 0,
+ *      schmitt-trigger mode is disabled.
+ * @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in
+ *     schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis,
+ *     the threshold value is given on a custom format as argument when
+ *     setting pins to this mode.
+ * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
+ *     which means it will wait for signals to settle when reading inputs. The
+ *     argument gives the debounce time in usecs. Setting the
+ *     argument to zero turns debouncing off.
+ * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
+ *     supplies, the argument to this parameter (on a custom format) tells
+ *     the driver which alternative power source to use.
+ * @PIN_CONFIG_SLEW_RATE: if the pin can select slew rate, the argument to
+ *     this parameter (on a custom format) tells the driver which alternative
+ *     slew rate to use.
+ * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power
+ *     operation, if several modes of operation are supported these can be
+ *     passed in the argument on a custom form, else just use argument 1
+ *     to indicate low power mode, argument 0 turns low power mode off.
+ * @PIN_CONFIG_OUTPUT: this will configure the pin as an output. Use argument
+ *     1 to indicate high level, argument 0 to indicate low level. (Please
+ *     see Documentation/pinctrl.txt, section "GPIO mode pitfalls" for a
+ *     discussion around this parameter.)
+ * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
+ *     you need to pass in custom configurations to the pin controller, use
+ *     PIN_CONFIG_END+1 as the base offset.
+ */
+#define PIN_CONFIG_BIAS_DISABLE                        0
+#define PIN_CONFIG_BIAS_HIGH_IMPEDANCE         1
+#define PIN_CONFIG_BIAS_BUS_HOLD               2
+#define PIN_CONFIG_BIAS_PULL_UP                        3
+#define PIN_CONFIG_BIAS_PULL_DOWN              4
+#define PIN_CONFIG_BIAS_PULL_PIN_DEFAULT       5
+#define PIN_CONFIG_DRIVE_PUSH_PULL             6
+#define PIN_CONFIG_DRIVE_OPEN_DRAIN            7
+#define PIN_CONFIG_DRIVE_OPEN_SOURCE           8
+#define PIN_CONFIG_DRIVE_STRENGTH              9
+#define PIN_CONFIG_INPUT_ENABLE                        10
+#define PIN_CONFIG_INPUT_SCHMITT_ENABLE                11
+#define PIN_CONFIG_INPUT_SCHMITT               12
+#define PIN_CONFIG_INPUT_DEBOUNCE              13
+#define PIN_CONFIG_POWER_SOURCE                        14
+#define PIN_CONFIG_SLEW_RATE                   15
+#define PIN_CONFIG_LOW_POWER_MODE              16
+#define PIN_CONFIG_OUTPUT                      17
+#define PIN_CONFIG_END                         0x7FFF
+
+#if CONFIG_IS_ENABLED(PINCTRL_GENERIC)
+/**
+ * pinctrl_generic_set_state() - generic set_state operation
+ * Parse the DT node of @config and its children and handle generic properties
+ * such as "pins", "groups", "functions", and pin configuration parameters.
+ *
+ * @pctldev: pinctrl device
+ * @config: config device (pseudo device), pointing a config node in DTS
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_generic_set_state(struct udevice *pctldev, struct udevice *config);
+#else
+static inline int pinctrl_generic_set_state(struct udevice *pctldev,
+                                           struct udevice *config)
+{
+       return -EINVAL;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(PINCTRL)
+/**
+ * pinctrl_select_state() - set a device to a given state
+ *
+ * @dev: peripheral device
+ * @statename: state name, like "default"
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_select_state(struct udevice *dev, const char *statename);
+#else
+static inline int pinctrl_select_state(struct udevice *dev,
+                                      const char *statename)
+{
+       return -EINVAL;
+}
+#endif
+
+#endif /* __PINCTRL_H */
 
        UCLASS_PCH,             /* x86 platform controller hub */
        UCLASS_PCI,             /* PCI bus */
        UCLASS_PCI_GENERIC,     /* Generic PCI bus device */
+       UCLASS_PINCTRL,         /* Pinctrl (pin muxing/configuration) device */
+       UCLASS_PINCONFIG,       /* Pin configuration node device */
        UCLASS_PMIC,            /* PMIC I/O device */
        UCLASS_REGULATOR,       /* Regulator device */
        UCLASS_RESET,           /* Reset device */