All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document
@ 2016-08-26 12:19 Jun Nie
  2016-08-26 12:19 ` [PATCH 3/3] pinctrl: zx: Add ZTE ZX SoC pinctrl driver Jun Nie
       [not found] ` <1472213965-4899-1-git-send-email-jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
  0 siblings, 2 replies; 8+ messages in thread
From: Jun Nie @ 2016-08-26 12:19 UTC (permalink / raw)
  To: linus.walleij, linux-gpio; +Cc: shawn.guo, jason.liu, Jun Nie

Add initial ZTE pinctrl dts document for ZX296718 SoC.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
 .../devicetree/bindings/pinctrl/pinctrl-zx.txt     | 54 ++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-zx.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-zx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-zx.txt
new file mode 100644
index 0000000..4061f51
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-zx.txt
@@ -0,0 +1,54 @@
+* ZTE ZX Pin Controller
+
+The pins controlled by ZX pin controller are organized in banks,
+number of pins in each bank may vary.  Each pin has different multiplexing
+functions. There are two type of pins, normal ones and AON ones. AON
+pins control high level multiplex and normal pins may require multiplex
+configuration of parent AON pins. As the AON pins number is not as much as
+normal pins, some normal pins are not routed through AON pin side and are
+under direct control by itself.
+
+Required properties:
+- compatible:
+  "zte,zx296718-pinctrl"
+  "zte,zx296718-aonpmx"
+
+- reg: Should contain the register physical address and length for the
+  pin controller.
+
+IO pull up/down etc configuration is supported with unified management of
+normal pins and AON pins. The configuration registers area is just after
+AON pinmux reg area, while normal pins regs in different area. So two dts
+nodes are needed to provides the two reg regions.
+
+Below configuration are supported. Please refer to pinctrl-bindings.txt
+in this directory for more details of the common pinctrl bindings used
+by client devices.
+
+bias-pull-up            - pull up the pin
+bias-pull-down          - pull down the pin
+drive-strength          - sink or source at most 7 mA
+input-enable            - enable input on pin (no effect on output)
+power-source            - select power supplies. 1: 1.8V, 0: 3.3V
+slew-rate               - set the slew rate
+
+Pin names are defined by bank sequence and pins number in the bank. For
+example, B2 is the 3rd pin in the second bank. The AON pin has prefix
+AON, like AONC2.
+
+Example dts nodes:
+
+pinctop: pinctrl@01462000 {
+	compatible = "zte,zx296718-pinctrl";
+	reg = <0x01462000 0x1000>;
+
+	i2c5_pins: i2c5pins {
+		pins = "G6", "G7";
+		function = "I2C5";
+	}
+};
+
+pmx_aon: pinctrl@00119000 {
+	compatible = "zte,zx296718-aonpmx";
+	reg = <0x00119000 0x1000>;
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] pinctrl: zx: Add ZTE ZX SoC pinctrl driver
  2016-08-26 12:19 [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document Jun Nie
@ 2016-08-26 12:19 ` Jun Nie
  2016-09-06 14:31   ` Linus Walleij
       [not found] ` <1472213965-4899-1-git-send-email-jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
  1 sibling, 1 reply; 8+ messages in thread
From: Jun Nie @ 2016-08-26 12:19 UTC (permalink / raw)
  To: linus.walleij, linux-gpio; +Cc: shawn.guo, jason.liu, Jun Nie

This adds pinctrl driver for ZTE ZX platform. The bit width
of pinmux registers are not unified, so this dedicated driver
is needed and detail bit width data is store in private data.
The parent pin information is also stored in private data so
that parent pin can be requested automatically.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
 drivers/pinctrl/Kconfig                |   1 +
 drivers/pinctrl/Makefile               |   1 +
 drivers/pinctrl/zte/Kconfig            |   9 +
 drivers/pinctrl/zte/Makefile           |   2 +
 drivers/pinctrl/zte/pinctrl-zx.c       | 550 ++++++++++++++++++++
 drivers/pinctrl/zte/pinctrl-zx.h       | 129 +++++
 drivers/pinctrl/zte/pinctrl-zx296718.c | 893 +++++++++++++++++++++++++++++++++
 7 files changed, 1585 insertions(+)
 create mode 100644 drivers/pinctrl/zte/Kconfig
 create mode 100644 drivers/pinctrl/zte/Makefile
 create mode 100644 drivers/pinctrl/zte/pinctrl-zx.c
 create mode 100644 drivers/pinctrl/zte/pinctrl-zx.h
 create mode 100644 drivers/pinctrl/zte/pinctrl-zx296718.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index b3fe1d3..48e4217 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -271,6 +271,7 @@ source "drivers/pinctrl/tegra/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
 source "drivers/pinctrl/vt8500/Kconfig"
 source "drivers/pinctrl/mediatek/Kconfig"
+source "drivers/pinctrl/zte/Kconfig"
 
 config PINCTRL_XWAY
 	bool
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 8ebd7b8..ec42eb0 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_PINCTRL_SUNXI)	+= sunxi/
 obj-$(CONFIG_PINCTRL_UNIPHIER)	+= uniphier/
 obj-$(CONFIG_ARCH_VT8500)	+= vt8500/
 obj-$(CONFIG_PINCTRL_MTK)	+= mediatek/
+obj-$(CONFIG_PINCTRL_ZX)	+= zte/
diff --git a/drivers/pinctrl/zte/Kconfig b/drivers/pinctrl/zte/Kconfig
new file mode 100644
index 0000000..16baf74
--- /dev/null
+++ b/drivers/pinctrl/zte/Kconfig
@@ -0,0 +1,9 @@
+config PINCTRL_ZX
+	bool"ZTE pin controller driver"
+	select PINMUX
+	select GENERIC_PINCONF
+
+config PINCTRL_ZX296718
+	bool "Pinctrl driver data for ZX296718"
+	depends on OF && ARCH_ZX
+	select PINCTRL_ZX
diff --git a/drivers/pinctrl/zte/Makefile b/drivers/pinctrl/zte/Makefile
new file mode 100644
index 0000000..c42e651
--- /dev/null
+++ b/drivers/pinctrl/zte/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_ZX)	+= pinctrl-zx.o
+obj-$(CONFIG_PINCTRL_ZX296718)	+= pinctrl-zx296718.o
diff --git a/drivers/pinctrl/zte/pinctrl-zx.c b/drivers/pinctrl/zte/pinctrl-zx.c
new file mode 100644
index 0000000..a1c0a12
--- /dev/null
+++ b/drivers/pinctrl/zte/pinctrl-zx.c
@@ -0,0 +1,550 @@
+/*
+ * ZTE ZX SoCs pinctrl driver.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "pinctrl-zx.h"
+
+/**
+ * struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function
+ * @offset:	offset base of pins
+ * @npins:	number pins with the same mux value of gpio function
+ * @gpiofunc:	mux value of gpio function
+ * @node:	list node
+ */
+struct pcs_gpiofunc_range {
+	unsigned offset;
+	unsigned npins;
+	unsigned gpiofunc;
+	struct list_head node;
+};
+
+static struct zx_pinctrl_function *
+zx_pctl_find_function_by_name(struct zx_pinctrl *pctl, const char *name)
+{
+	struct zx_pinctrl_function *func = pctl->functions;
+	int i;
+
+	for (i = 0; i < pctl->nfunctions; i++) {
+		if (!func[i].name)
+			break;
+
+		if (!strcmp(func[i].name, name))
+			return func + i;
+	}
+
+	return NULL;
+}
+
+static struct zx_desc_function *
+zx_pctl_desc_find_function_by_name(struct zx_pinctrl *pctl,
+				   const char *pin_name,
+				   const char *func_name)
+{
+	int i;
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct zx_desc_pin *pin = pctl->desc->pins + i;
+
+		if (!strcmp(pin->pin.name, pin_name)) {
+			struct zx_desc_function *func = pin->functions;
+
+			while (func->name) {
+				if (!strcmp(func->name, func_name))
+					return func;
+				func++;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static int zx_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->ngroups;
+}
+
+static const char *zx_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+					   unsigned group)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->groups[group].name;
+}
+
+static int zx_pctrl_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
+				   const unsigned **pins, unsigned *num_pins)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = (unsigned *)&pctl->groups[group].pin;
+	*num_pins = 1;
+
+	return 0;
+}
+
+static int zx_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+				   struct device_node *np_config,
+				   struct pinctrl_map **map,
+				   u32 *num_maps)
+{
+	return pinconf_generic_dt_node_to_map(pctldev, np_config, map,
+					      num_maps, PIN_MAP_TYPE_INVALID);
+}
+
+static const struct pinctrl_ops zx_pctrl_ops = {
+	.dt_node_to_map		= zx_pctrl_dt_node_to_map,
+	.dt_free_map		= pinctrl_utils_free_map,
+	.get_groups_count	= zx_pctrl_get_groups_count,
+	.get_group_name		= zx_pctrl_get_group_name,
+	.get_group_pins		= zx_pctrl_get_group_pins,
+};
+
+static int zx_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->nfunctions;
+}
+
+static const char *zx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					unsigned function)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->functions[function].name;
+}
+
+static int zx_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+				  unsigned function,
+				  const char * const **groups,
+				  unsigned * const num_groups)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pctl->functions[function].groups;
+	*num_groups = pctl->functions[function].ngroups;
+
+	return 0;
+}
+
+static void zx_pmx_set(struct pinctrl_dev *pctldev, unsigned pin,
+		       u8 mval)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct pinctrl_pin_desc *pins = pctldev->desc->pins;
+	struct zx_pin_desc_data *zx_pin_dat;
+	void __iomem *membase;
+	unsigned long flags;
+	u32 val, mask;
+
+	spin_lock_irqsave(&pctl->lock, flags);
+
+	membase = pin < pctl->ntop_pins ? pctl->membase : pctl->aon_membase;
+	pins += pin;
+	zx_pin_dat = (struct zx_pin_desc_data *)pins->drv_data;
+	dev_dbg(pctl->dev, "%s set 0x%p offset 0x%x bitp %d val %d\n", __func__,
+		membase, zx_pin_dat->offset, zx_pin_dat->bitpos, mval);
+
+	val = readl(membase + zx_pin_dat->offset);
+	mask = (BIT(1 + zx_pin_dat->width) - 1) << zx_pin_dat->bitpos;
+	writel((val & ~mask) | mval << zx_pin_dat->bitpos,
+		membase + zx_pin_dat->offset);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
+}
+
+static int zx_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function,
+			  unsigned group)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct zx_pinctrl_group *g = pctl->groups + group;
+	struct zx_pinctrl_function *func = pctl->functions + function;
+	struct zx_desc_function *desc =
+		zx_pctl_desc_find_function_by_name(pctl, g->name,
+						   func->name);
+
+	if (!desc)
+		return -EINVAL;
+
+	zx_pmx_set(pctldev, g->pin, desc->muxval);
+
+	return 0;
+}
+
+#define NONAON_MVAL 2
+int zx_pmx_request(struct pinctrl_dev *pctldev, unsigned offset)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	int ret;
+	const struct pinctrl_pin_desc *pins = pctldev->desc->pins;
+	struct zx_pin_desc_data *zx_pin_dat;
+
+	pins += offset;
+	zx_pin_dat = (struct zx_pin_desc_data *)pins->drv_data;
+	if (!zx_pin_dat->parent)
+		return 0;
+
+	ret = pinctrl_request_pin(pctldev, zx_pin_dat->parent, "nonAON");
+	if (ret) {
+		dev_err(pctl->dev, "Failed to request parent pin %d\n",
+			zx_pin_dat->parent);
+		return ret;
+	}
+
+	dev_dbg(pctl->dev, "Requested parent pin %d\n", zx_pin_dat->parent);
+	zx_pmx_set(pctldev, zx_pin_dat->parent, NONAON_MVAL);
+
+	return ret;
+}
+
+static const struct pinmux_ops zx_pmx_ops = {
+	.get_functions_count	= zx_pmx_get_funcs_cnt,
+	.get_function_name	= zx_pmx_get_func_name,
+	.get_function_groups	= zx_pmx_get_func_groups,
+	.set_mux		= zx_pmx_set_mux,
+	.request		= zx_pmx_request,
+};
+
+static void zx_pin_get_pull(void __iomem *base,
+			     struct zx_pin_desc_data *zx_dat,
+			     bool *pull_up, bool *pull_down)
+{
+	u32 val;
+
+	*pull_up = false;
+	*pull_down = false;
+
+	val = readl(base + zx_dat->coffset);
+	val = val >> zx_dat->cbitpos;
+	if (val | ZX_PULL_UP_VAL)
+		*pull_up = true;
+
+	if (val | ZX_PULL_DOWN_VAL)
+		*pull_down = true;
+}
+
+static int zx_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
+			     unsigned long *config)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct pinctrl_pin_desc *pins = pctldev->desc->pins;
+	struct zx_pin_desc_data *zx_dat;
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	bool pull_up, pull_down;
+	u32 val;
+	int ret = 0;
+
+	pins += pin;
+	zx_dat = (struct zx_pin_desc_data *)pins->drv_data;
+	if (zx_dat->parent) {
+		pin = zx_dat->parent;
+		pins = pctldev->desc->pins + pin;
+		zx_dat = (struct zx_pin_desc_data *)pins->drv_data;
+	}
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		zx_pin_get_pull(pctl->cfg_membase,
+				zx_dat, &pull_up, &pull_down);
+		if (pull_up || pull_down)
+			ret = -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_UP:
+		zx_pin_get_pull(pctl->cfg_membase,
+				zx_dat, &pull_up, &pull_down);
+		if (!pull_up)
+			ret = -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		zx_pin_get_pull(pctl->cfg_membase,
+				zx_dat, &pull_up, &pull_down);
+		if (!pull_down)
+			ret = -EINVAL;
+		break;
+
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		val = readl(pctl->cfg_membase + zx_dat->coffset);
+		val = val >> zx_dat->cbitpos;
+		val &= ZX_DRV_MASK;
+		val = val >> ZX_DRV_SHIFT;
+		*config = pinconf_to_config_packed(param, (u16)val);
+		break;
+
+	case PIN_CONFIG_SLEW_RATE:
+		val = readl(pctl->cfg_membase + zx_dat->coffset);
+		val = val >> zx_dat->cbitpos;
+		val &= ZX_SLEW_MASK;
+		val = !!val;
+		*config = pinconf_to_config_packed(param, (u16)val);
+		break;
+
+	case PIN_CONFIG_INPUT_ENABLE:
+		val = readl(pctl->cfg_membase + zx_dat->coffset);
+		val = val >> zx_dat->cbitpos;
+		val &= ZX_INPUT_VAL;
+		ret = val ? 0 : -EINVAL;
+		break;
+
+	default:
+		ret = -ENOTSUPP;
+	}
+
+	return ret;
+}
+
+static int zx_pin_config_set(struct pinctrl_dev *pctldev,
+			     unsigned pin, unsigned long *configs,
+			     unsigned num_configs)
+{
+	struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct pinctrl_pin_desc *pins = pctldev->desc->pins;
+	struct zx_pin_desc_data *zx_dat;
+	u32 val, mask;
+	u16 param, arg;
+	int idx;
+
+	pins += pin;
+	zx_dat = (struct zx_pin_desc_data *)pins->drv_data;
+	if (zx_dat->parent) {
+		pin = zx_dat->parent;
+		pins = pctldev->desc->pins + pin;
+		zx_dat = (struct zx_pin_desc_data *)pins->drv_data;
+	}
+
+	for (idx = 0; idx < num_configs; idx++) {
+		param = pinconf_to_config_param(configs[idx]);
+		arg = pinconf_to_config_argument(configs[idx]);
+
+		pr_debug("PMX CFG PIN#%d [%s] CONFIG PARAM:%d ARG:%d >>>\n",
+			 pin, pins->name, param, arg);
+		switch (param) {
+		case PIN_CONFIG_BIAS_PULL_UP:
+			mask = ZX_PULL_MASK << zx_dat->cbitpos;
+			val = readl(pctl->cfg_membase + zx_dat->coffset);
+			val = val & ~mask;
+			writel(val | ZX_PULL_UP_VAL << zx_dat->cbitpos,
+				pctl->cfg_membase + zx_dat->coffset);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			mask = ZX_PULL_MASK << zx_dat->cbitpos;
+			val = readl(pctl->cfg_membase + zx_dat->coffset);
+			val = val & ~mask;
+			writel(val | ZX_PULL_DOWN_VAL << zx_dat->cbitpos,
+				pctl->cfg_membase + zx_dat->coffset);
+			break;
+
+		case PIN_CONFIG_POWER_SOURCE:
+			mask = ZX_MSC_MASK << zx_dat->cbitpos;
+			val = readl(pctl->cfg_membase + zx_dat->coffset);
+			val = val & ~mask;
+			writel(val | ZX_MSC_VAL(arg) << zx_dat->cbitpos,
+				pctl->cfg_membase + zx_dat->coffset);
+			break;
+
+		case PIN_CONFIG_SLEW_RATE:
+			mask = ZX_SLEW_MASK << zx_dat->cbitpos;
+			val = readl(pctl->cfg_membase + zx_dat->coffset);
+			val = val & ~mask;
+			writel(val | ZX_SLEW_VAL(arg) << zx_dat->cbitpos,
+				pctl->cfg_membase + zx_dat->coffset);
+			break;
+
+		case PIN_CONFIG_INPUT_ENABLE:
+			val = readl(pctl->cfg_membase + zx_dat->coffset);
+			writel(val | ZX_INPUT_VAL << zx_dat->cbitpos,
+				pctl->cfg_membase + zx_dat->coffset);
+			break;
+
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			mask = ZX_DRV_MASK << zx_dat->cbitpos;
+			val = readl(pctl->cfg_membase + zx_dat->coffset);
+			val = val & ~mask;
+			writel(val | ZX_DRV_VAL(arg) << zx_dat->cbitpos,
+				pctl->cfg_membase + zx_dat->coffset);
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	return 0;
+}
+
+static const struct pinconf_ops zx_pinconf_ops = {
+	.pin_config_set = zx_pin_config_set,
+	.pin_config_get = zx_pin_config_get,
+	.is_generic = true,
+};
+
+static int zx_pinctrl_add_function(struct zx_pinctrl *pctl, const char *name)
+{
+	struct zx_pinctrl_function *func = pctl->functions;
+
+	while (func->name) {
+		/* function already there */
+		if (strcmp(func->name, name) == 0) {
+			func->ngroups++;
+			return -EEXIST;
+		}
+		func++;
+	}
+
+	func->name = name;
+	func->ngroups = 1;
+	pctl->nfunctions++;
+
+	return 0;
+}
+
+static int zx_pinctrl_build_state(struct platform_device *pdev)
+{
+	struct zx_pinctrl *pctl = platform_get_drvdata(pdev);
+	int i;
+
+	pctl->ngroups = pctl->desc->npins;
+
+	pctl->groups = devm_kzalloc(&pdev->dev,
+				    pctl->ngroups * sizeof(*pctl->groups),
+				    GFP_KERNEL);
+	if (!pctl->groups)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct zx_desc_pin *pin = pctl->desc->pins + i;
+		struct zx_pinctrl_group *group = pctl->groups + i;
+
+		group->name = pin->pin.name;
+		group->pin = pin->pin.number;
+	}
+
+	pctl->functions = devm_kzalloc(&pdev->dev,
+				pctl->desc->npins * sizeof(*pctl->functions),
+				GFP_KERNEL);
+	if (!pctl->functions)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct zx_desc_pin *pin = pctl->desc->pins + i;
+		struct zx_desc_function *func = pin->functions;
+
+		while (func->name) {
+			zx_pinctrl_add_function(pctl, func->name);
+			func++;
+		}
+	}
+
+	pctl->functions = krealloc(pctl->functions,
+				   pctl->nfunctions * sizeof(*pctl->functions),
+				   GFP_KERNEL);
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct zx_desc_pin *pin = pctl->desc->pins + i;
+		struct zx_desc_function *func = pin->functions;
+
+		while (func->name) {
+			struct zx_pinctrl_function *func_item;
+			const char **func_grp;
+
+			func_item = zx_pctl_find_function_by_name(pctl,
+								  func->name);
+			if (!func_item)
+				return -EINVAL;
+
+			if (!func_item->groups) {
+				func_item->groups =
+					devm_kzalloc(&pdev->dev,
+						     func_item->ngroups *
+						     sizeof(*func_item->groups),
+						     GFP_KERNEL);
+				if (!func_item->groups)
+					return -ENOMEM;
+			}
+
+			func_grp = func_item->groups;
+			while (*func_grp)
+				func_grp++;
+
+			*func_grp = pin->pin.name;
+			func++;
+		}
+	}
+
+	return 0;
+}
+
+int zx_pinctrl_init(struct platform_device *pdev, struct zx_pinctrl_desc *desc)
+{
+	struct pinctrl_desc *pctrl_desc;
+	struct pinctrl_pin_desc *pins;
+	struct zx_pinctrl *pctl;
+	int i, ret;
+
+	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+	if (!pctl)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, pctl);
+	spin_lock_init(&pctl->lock);
+	pctl->membase = desc->membase;
+	pctl->aon_membase = desc->aon_membase;
+	pctl->cfg_membase = desc->cfg_membase;
+	pctl->ntop_pins = desc->ntop_pins;
+	pctl->dev = &pdev->dev;
+	pctl->desc = desc;
+
+	ret = zx_pinctrl_build_state(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
+		return ret;
+	}
+
+	pins = devm_kzalloc(&pdev->dev, pctl->desc->npins * sizeof(*pins),
+			    GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl->desc->npins; i++)
+		pins[i] = pctl->desc->pins[i].pin;
+
+	pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL);
+	if (!pctrl_desc)
+		return -ENOMEM;
+
+	pctrl_desc->name = dev_name(&pdev->dev);
+	pctrl_desc->owner = THIS_MODULE;
+	pctrl_desc->pins = pins;
+	pctrl_desc->npins = pctl->desc->npins;
+	pctrl_desc->pctlops = &zx_pctrl_ops;
+	pctrl_desc->pmxops =  &zx_pmx_ops;
+	pctrl_desc->confops = &zx_pinconf_ops;
+
+	pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl);
+	if (IS_ERR(pctl->pctl_dev)) {
+		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+		return PTR_ERR(pctl->pctl_dev);
+	}
+
+	dev_info(&pdev->dev, "initialized ZX pinctrl driver\n");
+	return 0;
+}
diff --git a/drivers/pinctrl/zte/pinctrl-zx.h b/drivers/pinctrl/zte/pinctrl-zx.h
new file mode 100644
index 0000000..5c5c614
--- /dev/null
+++ b/drivers/pinctrl/zte/pinctrl-zx.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __PINCTRL_ZX_H
+#define __PINCTRL_ZX_H
+
+#define ZX_PULL_DOWN_VAL  1
+#define ZX_PULL_UP_VAL    2
+#define ZX_PULL_MASK      0x3
+#define ZX_MSC_MASK       4
+#define ZX_MSC_VAL(a)     ((a << 2) & ZX_MSC_MASK)
+#define ZX_INPUT_VAL      8
+#define ZX_DRV_MASK       0x70
+#define ZX_DRV_SHIFT      4
+#define ZX_DRV_VAL(a)     ((a << ZX_DRV_SHIFT) & ZX_DRV_MASK)
+#define ZX_SLEW_MASK      0x100
+#define ZX_SLEW_VAL(a)    ((a << 8) & ZX_SLEW_MASK)
+
+struct zx_desc_function {
+	const char	*name;
+	u8		muxval;
+};
+
+struct zx_pin_desc_data {
+	int	parent;
+	u16	offset;
+	u16	coffset; /* config reg offset */
+	u8	bitpos;
+	u8	cbitpos; /* config bit offset */
+	u8	width;
+};
+
+struct zx_desc_pin {
+	struct pinctrl_pin_desc	pin;
+	struct zx_desc_function	*functions;
+};
+
+struct zx_pinctrl_desc {
+	const struct zx_desc_pin	*pins;
+	unsigned			npins;
+	unsigned			ntop_pins;
+	void __iomem                    *membase;
+	void __iomem                    *aon_membase;
+	void __iomem                    *cfg_membase;
+};
+
+struct zx_pinctrl_function {
+	const char	*name;
+	const char	**groups;
+	unsigned	ngroups;
+};
+
+struct zx_pinctrl_group {
+	const char	*name;
+	unsigned long	config;
+	unsigned	pin;
+};
+
+struct zx_pinctrl {
+	void __iomem			*membase;
+	void __iomem			*aon_membase;
+	void __iomem                    *cfg_membase;
+	const struct zx_pinctrl_desc	*desc;
+	struct device			*dev;
+	struct zx_pinctrl_function	*functions;
+	unsigned			nfunctions;
+	unsigned			ntop_pins;
+	struct zx_pinctrl_group		*groups;
+	unsigned			ngroups;
+	spinlock_t			lock;
+	struct pinctrl_dev		*pctl_dev;
+};
+
+#define ZX_PINCTRL_PIN(bank, pin, bitp, wd, coff, cbp) {	\
+	.number = P ## bank ## _BASE + (pin),			\
+	.name = #bank #pin,					\
+	.drv_data = (void *) &(struct zx_pin_desc_data) {	\
+		.parent = 0,					\
+		.offset = P ## bank ## _OFF,			\
+		.bitpos = bitp,					\
+		.width = wd,					\
+		.coffset = coff,				\
+		.cbitpos = cbp,					\
+	},							\
+}
+
+#define ZX_PINCTRL_PIN_WITH_PARENT(bank, pin, bitp, wd, prt) {	\
+	.number = P ## bank ## _BASE + (pin),			\
+	.name = #bank #pin,					\
+	.drv_data = (void *) &(struct zx_pin_desc_data) {	\
+		.parent = prt,					\
+		.offset = P ## bank ## _OFF,			\
+		.bitpos = bitp,					\
+		.width = wd,					\
+	},							\
+}
+
+#define ZX_PINCTRL_AONPIN(bank, pin, bitp, wd, coff, cbp) {	\
+	.number = AONP ## bank ## _BASE + (pin),		\
+	.name = "AON" #bank #pin,				\
+	.drv_data = (void *) &(struct zx_pin_desc_data) {	\
+		.parent = 0,					\
+		.offset = P ## bank ## _OFF,			\
+		.bitpos = bitp,					\
+		.width = wd,					\
+		.coffset = coff,				\
+		.cbitpos = cbp,					\
+	},							\
+}
+
+#define ZX_PIN(_pin, ...)					\
+	{							\
+		.pin = _pin,					\
+		.functions = (struct zx_desc_function[]){	\
+			__VA_ARGS__, { } },			\
+	}
+
+#define ZX_FUNCTION(_val, _name)				\
+	{							\
+		.name = _name,					\
+		.muxval = _val,					\
+	}
+
+int zx_pinctrl_init(struct platform_device *pdev, struct zx_pinctrl_desc *desc);
+#endif
diff --git a/drivers/pinctrl/zte/pinctrl-zx296718.c b/drivers/pinctrl/zte/pinctrl-zx296718.c
new file mode 100644
index 0000000..864271f
--- /dev/null
+++ b/drivers/pinctrl/zte/pinctrl-zx296718.c
@@ -0,0 +1,893 @@
+/*
+ * Copyright (C) 2016 ZTE Semiconductor Corporation.
+ * Copyright (C) 2016 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * ZX296718 AON pins control high level multiplex and normal pins
+ * may require multiplex configuration of parent AON pins. As the AON pins
+ * number is not as much as normal pins, some normal pins are not routed
+ * through AON pin controller and are under direct control by itself.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-zx.h"
+
+#define PA_OFF 0x0
+#define PA_BASE 0
+#define PA_NR 16
+#define PB_OFF 0x4
+#define PB_BASE (PA_BASE + PA_NR)
+#define PB_NR 16
+#define PC_OFF 0x8
+#define PC_BASE (PB_BASE + PB_NR)
+#define PC_NR 12
+#define PD_OFF 0xc
+#define PD_BASE (PC_BASE + PC_NR)
+#define PD_NR 23
+#define PE_OFF 0x10
+#define PE_BASE (PD_BASE + PD_NR)
+#define PE_NR 14
+#define PF_OFF 0x14
+#define PF_BASE (PE_BASE + PE_NR)
+#define PF_NR 12
+#define PG_OFF 0x18
+#define PG_BASE (PF_BASE + PF_NR)
+#define PG_NR 11
+#define PH_OFF 0x1c
+#define PH_BASE (PG_BASE + PG_NR)
+#define PH_NR 13
+#define PI_OFF 0x20
+#define PI_BASE (PH_BASE + PH_NR)
+#define PI_NR 6
+
+#define AONPA_OFF 0
+#define AONPA_BASE (PI_BASE + PI_NR)
+#define AONPA_NR 14
+#define AONPB_OFF 0x4
+#define AONPB_BASE (AONPA_BASE + AONPA_NR)
+#define AONPB_NR 13
+#define AONPC_OFF 0x8
+#define AONPC_BASE (AONPB_BASE + AONPB_NR)
+
+static const struct zx_desc_pin zx296718_pins[] = {
+	ZX_PIN(ZX_PINCTRL_PIN(A, 0, 0, 2, 0x10, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* gtx clk */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* clk */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio0 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 1, 2, 2, 0x10, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* tx clk */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* vs */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio 1 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 2, 4, 2, 0x10, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd0 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* hs */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio 2 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 3, 6, 2, 0x14, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd1 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d0 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio3 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 4, 8, 2, 0x14, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd2 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d1 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio4 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 5, 10, 2, 0x14, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd3 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d2 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio5 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 6, 12, 2, 0x18, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd4 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d3 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio6 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 7, 14, 2, 0x18, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd5 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d4 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio7 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 8, 16, 2, 0x18, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd6 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d5 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio8 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 9, 18, 2, 0x1c, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* txd7 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d6 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio9 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 10, 20, 2, 0x1c, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* tx_er */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d7 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio10 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 11, 22, 2, 0x1c, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* tx_en */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d8 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio11 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 12, 24, 2, 0x20, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rx_clk */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d9 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio12 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 13, 26, 2, 0x20, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd0 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d10 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio13 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 14, 28, 2, 0x20, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd1 */
+		  ZX_FUNCTION(0x1, "DVI0"),	/* d11 */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio14 */
+	ZX_PIN(ZX_PINCTRL_PIN(A, 15, 30, 2, 0x24, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd2 */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* clk */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio15 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 0, 0, 2, 0x24, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd3 */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* hs */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio16 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 1, 2, 2, 0x24, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd4 */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* vs */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio17 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 2, 4, 2, 0x28, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd5 */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d0 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio18 */
+		  ZX_FUNCTION(0x3, "TSI0")),	/* dat0 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 3, 6, 2, 0x28, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd6 */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d1 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio19 */
+		  ZX_FUNCTION(0x3, "TSI0")),	/* clk */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 4, 8, 2, 0x28, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rxd7 */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d2 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio20 */
+		  ZX_FUNCTION(0x3, "TSI0")),	/* sync */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 5, 10, 2, 0x2c, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rx_er */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d3 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio21 */
+		  ZX_FUNCTION(0x3, "TSI0")),	/* valid */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 6, 12, 2, 0x2c, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* rx_dv */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d4 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio22 */
+		  ZX_FUNCTION(0x3, "TSI1")),	/* dat0 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 7, 14, 2, 0x2c, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* col */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d5 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio23 */
+		  ZX_FUNCTION(0x3, "TSI1")),	/* clk */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 8, 16, 2, 0x30, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* crs */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d6 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio24 */
+		  ZX_FUNCTION(0x3, "TSI1")),	/* sync */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 9, 18, 2, 0x30, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* mdc */
+		  ZX_FUNCTION(0x1, "DVI1"),	/* d7 */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio25 */
+		  ZX_FUNCTION(0x3, "TSI1")),	/* valid */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 10, 20, 1, 0x30, 18),
+		  ZX_FUNCTION(0x0, "GMII"),	/* mdio */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio26 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 11, 21, 2, 0x34, 18),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* clk */
+		  ZX_FUNCTION(0x1, "USIM0"),	/* clk */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio27 */
+		  ZX_FUNCTION(0x3, "SPINOR")),	/* clk */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 12, 23, 2, 0x38, 0),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* cmd */
+		  ZX_FUNCTION(0x1, "USIM0"),	/* cd */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio28 */
+		  ZX_FUNCTION(0x3, "SPINOR")),	/* cs */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 13, 25, 2, 0x38, 9),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* dat0 */
+		  ZX_FUNCTION(0x1, "USIM0"),	/* rst */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio29 */
+		  ZX_FUNCTION(0x3, "SPINOR")),	/* dq0 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 14, 27, 2, 0x38, 18),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* dat1 */
+		  ZX_FUNCTION(0x1, "USIM0"),	/* data */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio30 */
+		  ZX_FUNCTION(0x3, "SPINOR")),	/* dq1 */
+	ZX_PIN(ZX_PINCTRL_PIN(B, 15, 29, 2, 0x3c, 0),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* dat2 */
+		  ZX_FUNCTION(0x1, "BGPIO"),	/* gpio31 */
+		  ZX_FUNCTION(0x2, "SPINOR")),	/* dq2 */
+	ZX_PIN(ZX_PINCTRL_PIN(C, 0, 0, 2, 0x3c, 9),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* dat3 */
+		  ZX_FUNCTION(0x1, "BGPIO"),	/* gpio32 */
+		  ZX_FUNCTION(0x2, "SPINOR")),	/* dq3 */
+	ZX_PIN(ZX_PINCTRL_PIN(C, 1, 2, 2, 0x3c, 18),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* cd */
+		  ZX_FUNCTION(0x1, "BGPIO"),	/* gpio33 */
+		  ZX_FUNCTION(0x2, "ISP")),	/* fl_trig */
+	ZX_PIN(ZX_PINCTRL_PIN(C, 2, 4, 2, 0x40, 0),
+		  ZX_FUNCTION(0x0, "SDIO1"),	/* wp */
+		  ZX_FUNCTION(0x1, "BGPIO"),	/* gpio34 */
+		  ZX_FUNCTION(0x2, "ISP")),	/* ref_clk */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(C, 3, 6, 3, AONPC_BASE),
+		  ZX_FUNCTION(0x0, "SPI1"),	/* clk */
+		  ZX_FUNCTION(0x1, "PCM"),	/* clk */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio35 */
+		  ZX_FUNCTION(0x3, "I2C4"),	/* scl */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* mclk */
+		  ZX_FUNCTION(0x5, "ISP")),	/* flash_trig */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(C, 4, 9, 3, AONPC_BASE + 1),
+		  ZX_FUNCTION(0x0, "SPI1"),	/* cs */
+		  ZX_FUNCTION(0x1, "PCM"),	/* fs */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio36 */
+		  ZX_FUNCTION(0x3, "I2C4"),	/* sda */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* bclk */
+		  ZX_FUNCTION(0x5, "ISP")),	/* prelight_trig */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(C, 5, 12, 3, AONPC_BASE + 2),
+		  ZX_FUNCTION(0x0, "SPI1"),	/* txd */
+		  ZX_FUNCTION(0x1, "PCM"),	/* txd */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio37 */
+		  ZX_FUNCTION(0x3, "UART5"),	/* rxd */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* ws */
+		  ZX_FUNCTION(0x5, "ISP")),	/* shutter_trig */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(C, 6, 15, 3, AONPC_BASE + 3),
+		  ZX_FUNCTION(0x0, "SPI1"),	/* rxd */
+		  ZX_FUNCTION(0x1, "PCM"),	/* rxd */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio38 */
+		  ZX_FUNCTION(0x3, "UART5"),	/* txd */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* dout0 */
+		  ZX_FUNCTION(0x5, "ISP")),	/* shutter_open */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(C, 7, 18, 2, AONPA_BASE),
+		  ZX_FUNCTION(0x0, "I2C3"),	/* scl */
+		  ZX_FUNCTION(0x1, "SPI2"),	/* txd */
+		  ZX_FUNCTION(0x2, "I2S1")),	/* din0 */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(C, 8, 20, 2, AONPA_BASE + 1),
+		  ZX_FUNCTION(0x0, "I2C3"),	/* sda */
+		  ZX_FUNCTION(0x1, "SPI2"),	/* rxd */
+		  ZX_FUNCTION(0x2, "I2S0")),	/* mclk */
+	ZX_PIN(ZX_PINCTRL_PIN(C, 9, 22, 3, 0x44, 18),
+		  ZX_FUNCTION(0x0, "USIM1"),	/* cd */
+		  ZX_FUNCTION(0x1, "UART4"),	/* rxd */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio39 */
+		  ZX_FUNCTION(0x3, "SPI3"),	/* clk */
+		  ZX_FUNCTION(0x4, "I2S0"),	/* bclk */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d8 */
+	ZX_PIN(ZX_PINCTRL_PIN(C, 10, 25, 3, 0x4c, 18),
+		  ZX_FUNCTION(0x0, "USIM1"),	/* clk */
+		  ZX_FUNCTION(0x1, "UART4"),	/* txd */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio40 */
+		  ZX_FUNCTION(0x3, "SPI3"),	/* cs */
+		  ZX_FUNCTION(0x4, "I2S0"),	/* ws */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d9 */
+	ZX_PIN(ZX_PINCTRL_PIN(C, 11, 28, 3, 0x4c, 0),
+		  ZX_FUNCTION(0x0, "USIM1"),	/* rst */
+		  ZX_FUNCTION(0x1, "UART4"),	/* cts */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio41 */
+		  ZX_FUNCTION(0x3, "SPI3"),	/* txd */
+		  ZX_FUNCTION(0x4, "I2S0"),	/* dout0 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d10 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 0, 0, 3, 0x4c, 9),
+		  ZX_FUNCTION(0x0, "USIM1"),	/* dat */
+		  ZX_FUNCTION(0x1, "UART4"),	/* rst */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio42 */
+		  ZX_FUNCTION(0x3, "SPI3"),	/* rxd */
+		  ZX_FUNCTION(0x4, "I2S0"),	/* din0 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d11 */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 1, 3, 2, AONPC_BASE + 4),
+		  ZX_FUNCTION(0x0, "AUDIO"),	/* detect */
+		  ZX_FUNCTION(0x1, "I2C2"),	/* scl */
+		  ZX_FUNCTION(0x2, "SPI2")),	/* clk */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 2, 5, 1, AONPA_BASE + 2),
+		  ZX_FUNCTION(0x0, "I2C2"),	/* sda */
+		  ZX_FUNCTION(0x1, "SPI2")),	/* cs */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 3, 6, 1, 0x58, 0),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* clk */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio43 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 4, 7, 1, 0x58, 9),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* cmd */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio44 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 5, 8, 1, 0x58, 18),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* dat0 */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio45 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 6, 9, 1, 0x5c, 0),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* dat1 */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio46 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 7, 10, 1, 0x5c, 9),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* dat2 */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio47 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 8, 11, 1, 0x5c, 18),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* dat3 */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio48 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 9, 12, 1, 0x60, 0),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* cd */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio49 */
+	ZX_PIN(ZX_PINCTRL_PIN(D, 10, 13, 1, 0x60, 9),
+		  ZX_FUNCTION(0x0, "SDIO0"),	/* wp */
+		  ZX_FUNCTION(0x1, "GPIO")),	/* gpio50 */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 11, 14, 2, AONPC_BASE + 5),
+		  ZX_FUNCTION(0x0, "SPDIF"),	/* out */
+		  ZX_FUNCTION(0x1, "PWM"),	/* out0 */
+		  ZX_FUNCTION(0x2, "ISP")),	/* fl_trig */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 12, 16, 1, AONPA_BASE + 7),
+		  ZX_FUNCTION(0x0, "SPI0"),	/* clk */
+		  ZX_FUNCTION(0x1, "ISP")),	/* flash_trig */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 13, 17, 1, AONPA_BASE + 8),
+		  ZX_FUNCTION(0x0, "SPI0"),	/* cs */
+		  ZX_FUNCTION(0x1, "ISP")),	/* prelight_trig */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 14, 18, 1, AONPA_BASE + 9),
+		  ZX_FUNCTION(0x0, "SPI0"),	/* txd */
+		  ZX_FUNCTION(0x1, "ISP")),	/* shutter_trig */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 15, 19, 1, AONPA_BASE + 10),
+		  ZX_FUNCTION(0x0, "SPI0"),	/* rxd */
+		  ZX_FUNCTION(0x1, "ISP")),	/* shutter_open */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 16, 20, 1, AONPA_BASE + 11),
+		  ZX_FUNCTION(0x0, "UART3"),	/* rxd */
+		  ZX_FUNCTION(0x1, "I2S0")),	/* din1 */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 17, 21, 2, AONPA_BASE + 12),
+		  ZX_FUNCTION(0x0, "UART3"),	/* txd */
+		  ZX_FUNCTION(0x1, "I2S0"),	/* din2 */
+		  ZX_FUNCTION(0x2, "VGA")),	/* scl */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 18, 23, 2, AONPA_BASE + 13),
+		  ZX_FUNCTION(0x0, "PWM"),	/* out1 */
+		  ZX_FUNCTION(0x1, "I2S0"),	/* din3 */
+		  ZX_FUNCTION(0x2, "VGA")),	/* sda */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 19, 25, 2, AONPB_BASE),
+		  ZX_FUNCTION(0x0, "LCD"),	/* port0 lcd_te */
+		  ZX_FUNCTION(0x1, "I2S0"),	/* dout2 */
+		  ZX_FUNCTION(0x2, "PWM"),	/* out2 */
+		  ZX_FUNCTION(0x3, "VGA")),	/* hs1 */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 20, 27, 2, AONPB_BASE + 1),
+		  ZX_FUNCTION(0x0, "LCD"),	/* port1 lcd_te */
+		  ZX_FUNCTION(0x1, "I2S0"),	/* dout3 */
+		  ZX_FUNCTION(0x2, "PWM"),	/* out3 */
+		  ZX_FUNCTION(0x3, "VGA")),	/* vs1 */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 21, 29, 1, AONPB_BASE + 2),
+		  ZX_FUNCTION(0x0, "HDMI"),	/* scl */
+		  ZX_FUNCTION(0x1, "UART3")),	/* rxd */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(D, 22, 30, 1, AONPB_BASE + 3),
+		  ZX_FUNCTION(0x0, "HDMI"),	/* sda */
+		  ZX_FUNCTION(0x1, "UART3")),	/* txd */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 0, 0, 2, 0x60, 18),
+		  ZX_FUNCTION(0x0, "TSI0"),	/* dat0 */
+		  ZX_FUNCTION(0x1, "LCD"),	/* clk */
+		  ZX_FUNCTION(0x2, "BGPIO")),	/* gpio51 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 1, 2, 2, 0xa8, 18),
+		  ZX_FUNCTION(0x0, "SPINOR"),	/* clk */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* dat1 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat0 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio52 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 2, 4, 2, 0x7c, 0),
+		  ZX_FUNCTION(0x0, "TSI2"),	/* dat */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* dat2 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat1 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio53 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 3, 6, 2, 0x7c, 9),
+		  ZX_FUNCTION(0x0, "TSI2"),	/* clk */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* dat3 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat2 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio54 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 4, 8, 2, 0x7c, 18),
+		  ZX_FUNCTION(0x0, "TSI2"),	/* sync */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* dat4 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat3 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio55 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 5, 10, 2, 0x80, 0),
+		  ZX_FUNCTION(0x0, "TSI2"),	/* valid */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* dat5 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat4 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio56 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 6, 12, 2, 0x80, 9),
+		  ZX_FUNCTION(0x0, "SPINOR"),	/* cs */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* dat6 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat5 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio57 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 7, 14, 2, 0x80, 18),
+		  ZX_FUNCTION(0x0, "SPINOR"),	/* dq0 */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* dat7 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat6 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio58 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 8, 16, 2, 0x84, 0),
+		  ZX_FUNCTION(0x0, "SPINOR"),	/* dq1 */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* clk */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat7 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio59 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 9, 18, 2, 0x84, 9),
+		  ZX_FUNCTION(0x0, "SPINOR"),	/* dq2 */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* sync */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat8 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio60 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 10, 20, 2, 0x84, 18),
+		  ZX_FUNCTION(0x0, "SPINOR"),	/* dq3 */
+		  ZX_FUNCTION(0x1, "TSI0"),	/* valid */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat9 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio61 */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 11, 22, 3, 0x88, 0),
+		  ZX_FUNCTION(0x0, "VGA"),	/* hs */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat0 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat10 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio62 */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* din1 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* clk */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 12, 25, 3, 0x88, 9),
+		  ZX_FUNCTION(0x0, "VGA"),	/* vs0 */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat1 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat11 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio63 */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* din2 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* vs */
+	ZX_PIN(ZX_PINCTRL_PIN(E, 13, 28, 3, 0x88, 18),
+		  ZX_FUNCTION(0x0, "TSI3"),	/* dat */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat2 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat12 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio64 */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* din3 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* hs */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 0, 0, 3, 0x8c, 0),
+		  ZX_FUNCTION(0x0, "TSI3"),	/* clk */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat3 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat13 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio65 */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* dout1 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d0 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 1, 3, 3, 0x8c, 9),
+		  ZX_FUNCTION(0x0, "TSI3"),	/* sync */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat4 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat14 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio66 */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* dout2 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d1 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 2, 6, 3, 0x8c, 18),
+		  ZX_FUNCTION(0x0, "TSI3"),	/* valid */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat5 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat15 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio67 */
+		  ZX_FUNCTION(0x4, "I2S1"),	/* dout3 */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d2 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 3, 9, 3, 0x90, 0),
+		  ZX_FUNCTION(0x0, "I2S1"),	/* ws */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat6 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat16 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio68 */
+		  ZX_FUNCTION(0x4, "VGA"),	/* scl */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d3 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 4, 12, 3, 0x90, 9),
+		  ZX_FUNCTION(0x0, "I2S1"),	/* bclk */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* dat7 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat17 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio69 */
+		  ZX_FUNCTION(0x4, "VGA"),	/* sda */
+		  ZX_FUNCTION(0x5, "B_DVI0")),	/* d4 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 5, 15, 2, 0x90, 18),
+		  ZX_FUNCTION(0x0, "I2S1"),	/* mclk */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* clk */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat18 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio70 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 6, 17, 2, 0x94, 0),
+		  ZX_FUNCTION(0x0, "I2S1"),	/* din0 */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* sync */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat19 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio71 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 7, 19, 2, 0x94, 9),
+		  ZX_FUNCTION(0x0, "I2S1"),	/* dout0 */
+		  ZX_FUNCTION(0x1, "TSI1"),	/* valid */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat20 */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio72 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 8, 21, 3, 0x94, 18),
+		  ZX_FUNCTION(0x0, "SPI3"),	/* clk */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* clk */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat21 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio73 */
+		  ZX_FUNCTION(0x4, "UART5"),	/* rxd */
+		  ZX_FUNCTION(0x5, "PCM"),	/* fs */
+		  ZX_FUNCTION(0x6, "I2S0"),	/* din1 */
+		  ZX_FUNCTION(0x7, "B_DVI0")),	/* d5 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 9, 24, 3, 0x98, 0),
+		  ZX_FUNCTION(0x0, "SPI3"),	/* cs */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat0 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat22 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio74 */
+		  ZX_FUNCTION(0x4, "UART5"),	/* txd */
+		  ZX_FUNCTION(0x5, "PCM"),	/* clk */
+		  ZX_FUNCTION(0x6, "I2S0"),	/* din2 */
+		  ZX_FUNCTION(0x7, "B_DVI0")),	/* d6 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 10, 27, 3, 0x98, 9),
+		  ZX_FUNCTION(0x0, "SPI3"),	/* txd */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat1 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* dat23 */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio75 */
+		  ZX_FUNCTION(0x4, "UART5"),	/* cts */
+		  ZX_FUNCTION(0x5, "PCM"),	/* txd */
+		  ZX_FUNCTION(0x6, "I2S0"),	/* din3 */
+		  ZX_FUNCTION(0x7, "B_DVI0")),	/* d7 */
+	ZX_PIN(ZX_PINCTRL_PIN(F, 11, 30, 1, 0xe4, 0),
+		  ZX_FUNCTION(0x0, "NAND"),	/* ldo_ms18_sel */
+		  ZX_FUNCTION(0x1, "BGPIO")),	/* gpio99 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 0, 0, 3, 0x98, 18),
+		  ZX_FUNCTION(0x0, "SPI3"),	/* rxd */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat2 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* stvu_vsync */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio76 */
+		  ZX_FUNCTION(0x4, "UART5"),	/* rts */
+		  ZX_FUNCTION(0x5, "PCM"),	/* rxd */
+		  ZX_FUNCTION(0x6, "I2S0"),	/* dout1 */
+		  ZX_FUNCTION(0x7, "B_DVI1")),	/* clk */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 1, 3, 3, 0x9c, 0),
+		  ZX_FUNCTION(0x0, "I2S0"),	/* mclk */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat3 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* stvd */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio77 */
+		  ZX_FUNCTION(0x4, "USIM0"),	/* cd */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* vs */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 2, 6, 3, 0x9c, 9),
+		  ZX_FUNCTION(0x0, "I2S0"),	/* bclk */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat4 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* sthl_hsync */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio78 */
+		  ZX_FUNCTION(0x4, "USIM0"),	/* clk */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* hs */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 3, 9, 3, 0x9c, 18),
+		  ZX_FUNCTION(0x0, "I2S0"),	/* ws */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat5 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* sthr */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio79 */
+		  ZX_FUNCTION(0x4, "USIM0"),	/* rst */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* d0 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 4, 12, 3, 0xa0, 0),
+		  ZX_FUNCTION(0x0, "I2S0"),	/* din0 */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat6 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* OEV_DATAEN */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio80 */
+		  ZX_FUNCTION(0x4, "USIM0"),	/* dat */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* d1 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 5, 15, 2, 0xa0, 9),
+		  ZX_FUNCTION(0x0, "I2S0"),	/* dout0 */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* dat7 */
+		  ZX_FUNCTION(0x2, "LCD"),	/* CKV */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio81 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 6, 17, 3, 0xa0, 18),
+		  ZX_FUNCTION(0x0, "I2C5"),	/* scl */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* sync */
+		  ZX_FUNCTION(0x2, "LCD"),	/* ld */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio82 */
+		  ZX_FUNCTION(0x4, "PWM"),	/* out2 */
+		  ZX_FUNCTION(0x5, "I2S0"),	/* dout2 */
+		  ZX_FUNCTION(0x6, "B_DVI1")),	/* d2 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 7, 20, 3, 0xa4, 0),
+		  ZX_FUNCTION(0x0, "I2C5"),	/* sda */
+		  ZX_FUNCTION(0x1, "TSO1"),	/* vld */
+		  ZX_FUNCTION(0x2, "LCD"),	/* pol */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio83 */
+		  ZX_FUNCTION(0x4, "PWM"),	/* out3 */
+		  ZX_FUNCTION(0x5, "I2S0"),	/* dout3 */
+		  ZX_FUNCTION(0x6, "B_DVI1")),	/* d3 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 8, 23, 3, 0xa4, 9),
+		  ZX_FUNCTION(0x0, "SPI2"),	/* clk */
+		  ZX_FUNCTION(0x1, "TSO0"),	/* clk */
+		  ZX_FUNCTION(0x2, "LCD"),	/* degsl */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio84 */
+		  ZX_FUNCTION(0x4, "I2C4"),	/* scl */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* d4 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 9, 26, 3, 0xa4, 18),
+		  ZX_FUNCTION(0x0, "SPI2"),	/* cs */
+		  ZX_FUNCTION(0x1, "TSO0"),	/* data */
+		  ZX_FUNCTION(0x2, "LCD"),	/* rev */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio85 */
+		  ZX_FUNCTION(0x4, "I2C4"),	/* sda */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* d5 */
+	ZX_PIN(ZX_PINCTRL_PIN(G, 10, 29, 3, 0xa8, 0),
+		  ZX_FUNCTION(0x0, "SPI2"),	/* txd */
+		  ZX_FUNCTION(0x1, "TSO0"),	/* sync */
+		  ZX_FUNCTION(0x2, "LCD"),	/* u_d */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio86 */
+		  ZX_FUNCTION(0x4, "I2C4"),	/* scl */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* d6 */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 0, 0, 3, 0xa8, 9),
+		  ZX_FUNCTION(0x0, "SPI2"),	/* rxd */
+		  ZX_FUNCTION(0x1, "TSO0"),	/* vld */
+		  ZX_FUNCTION(0x2, "LCD"),	/* r_l */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio87 */
+		  ZX_FUNCTION(0x4, "I2C3"),	/* sda */
+		  ZX_FUNCTION(0x5, "B_DVI1")),	/* d7 */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(H, 1, 3, 1, AONPB_BASE + 4),
+		  ZX_FUNCTION(0x0, "SPI4"),	/* clk */
+		  ZX_FUNCTION(0x1, "UART1")),	/* rxd */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(H, 2, 4, 1, AONPB_BASE + 5),
+		  ZX_FUNCTION(0x0, "SPI4"),	/* cs */
+		  ZX_FUNCTION(0x1, "UART1")),	/* txd */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(H, 3, 5, 1, AONPB_BASE + 6),
+		  ZX_FUNCTION(0x0, "SPI4"),	/* txd */
+		  ZX_FUNCTION(0x1, "UART2")),	/* rxd */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(H, 4, 6, 1, AONPB_BASE + 7),
+		  ZX_FUNCTION(0x0, "SPI4"),	/* rxd */
+		  ZX_FUNCTION(0x1, "UART2")),	/* txd */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 5, 7, 3, 0x54, 9),
+		  ZX_FUNCTION(0x0, "NAND"),	/* wp */
+		  ZX_FUNCTION(0x1, "PWM"),	/* out2 */
+		  ZX_FUNCTION(0x2, "SPI2"),	/* clk */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio88 */
+		  ZX_FUNCTION(0x4, "TSI0"),	/* dat0 */
+		  ZX_FUNCTION(0x5, "I2S1")),	/* din1 */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 6, 10, 3, 0xb8, 0),
+		  ZX_FUNCTION(0x0, "NAND"),	/* boot_pagesize0 */
+		  ZX_FUNCTION(0x1, "PWM"),	/* out3 */
+		  ZX_FUNCTION(0x2, "SPI2"),	/* cs */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio89 */
+		  ZX_FUNCTION(0x4, "TSI0"),	/* clk */
+		  ZX_FUNCTION(0x5, "I2S1")),	/* din2 */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 7, 13, 3, 0xb8, 9),
+		  ZX_FUNCTION(0x0, "NAND"),	/* boot_pagesize1 */
+		  ZX_FUNCTION(0x1, "I2C4"),	/* scl */
+		  ZX_FUNCTION(0x2, "SPI2"),	/* txd */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio90 */
+		  ZX_FUNCTION(0x4, "TSI0"),	/* sync */
+		  ZX_FUNCTION(0x5, "I2S1")),	/* din3 */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 8, 16, 3, 0xb8, 18),
+		  ZX_FUNCTION(0x0, "NAND"),	/* BOOT_ADDR_CYCLES */
+		  ZX_FUNCTION(0x1, "I2C4"),	/* sda */
+		  ZX_FUNCTION(0x2, "SPI2"),	/* rxd */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio91 */
+		  ZX_FUNCTION(0x4, "TSI0"),	/* valid */
+		  ZX_FUNCTION(0x5, "I2S1")),	/* dout1 */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 9, 19, 3, 0xbc, 0),
+		  ZX_FUNCTION(0x0, "NAND"),	/* RDY_BUSY0 */
+		  ZX_FUNCTION(0x1, "I2C2"),	/* scl */
+		  ZX_FUNCTION(0x2, "USIM0"),	/* cd */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio92 */
+		  ZX_FUNCTION(0x4, "TSI1")),	/* data0 */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 10, 22, 3, 0xbc, 9),
+		  ZX_FUNCTION(0x0, "NAND"),	/* RDY_BUSY1 */
+		  ZX_FUNCTION(0x1, "I2C2"),	/* sda */
+		  ZX_FUNCTION(0x2, "USIM0"),	/* clk */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio93 */
+		  ZX_FUNCTION(0x4, "TSI1")),	/* clk */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 11, 25, 3, 0xbc, 18),
+		  ZX_FUNCTION(0x0, "NAND"),	/* RDY_BUSY2 */
+		  ZX_FUNCTION(0x1, "UART5"),	/* rxd */
+		  ZX_FUNCTION(0x2, "USIM0"),	/* rst */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio94 */
+		  ZX_FUNCTION(0x4, "TSI1"),	/* sync */
+		  ZX_FUNCTION(0x4, "I2S1")),	/* dout2 */
+	ZX_PIN(ZX_PINCTRL_PIN(H, 12, 28, 3, 0x54, 18),
+		  ZX_FUNCTION(0x0, "NAND"),	/* RDY_BUSY3 */
+		  ZX_FUNCTION(0x1, "UART5"),	/* txd */
+		  ZX_FUNCTION(0x2, "USIM0"),	/* dat */
+		  ZX_FUNCTION(0x3, "BGPIO"),	/* gpio95 */
+		  ZX_FUNCTION(0x4, "TSI1"),	/* valid */
+		  ZX_FUNCTION(0x4, "I2S1")),	/* dout3 */
+	ZX_PIN(ZX_PINCTRL_PIN(I, 0, 0, 2, 0x34, 0),
+		  ZX_FUNCTION(0x0, "GMII"),	/* 125m_in */
+		  ZX_FUNCTION(0x1, "USB2"),	/* 0_drvvbus */
+		  ZX_FUNCTION(0x2, "ISP"),	/* ref_clk */
+		  ZX_FUNCTION(0x3, "BGPIO")),	/* gpio96 */
+	ZX_PIN(ZX_PINCTRL_PIN(I, 1, 2, 2, 0x34, 9),
+		  ZX_FUNCTION(0x0, "GMII"),	/* 50m_out */
+		  ZX_FUNCTION(0x1, "USB2"),	/* 1_drvvbus */
+		  ZX_FUNCTION(0x2, "BGPIO"),	/* gpio97 */
+		  ZX_FUNCTION(0x3, "USB2")),	/* 0_drvvbus */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(I, 2, 4, 1, AONPB_BASE + 11),
+		  ZX_FUNCTION(0x0, "LCD")),	/* port0 lcd_te */
+	ZX_PIN(ZX_PINCTRL_PIN_WITH_PARENT(I, 3, 5, 1, AONPB_BASE + 12),
+		  ZX_FUNCTION(0x0, "LCD")),	/* port1 lcd_te */
+	ZX_PIN(ZX_PINCTRL_PIN(I, 4, 6, 1, 0xc8, 9),
+		  ZX_FUNCTION(0x0, "SPINOR")),	/* SDIO1_CLK_I */
+	ZX_PIN(ZX_PINCTRL_PIN(I, 5, 7, 1, 0xc8, 18),
+		  ZX_FUNCTION(0x0, "SPINOR")),	/* SSCLK_I */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 0, 0, 2, 0x48, 0),
+		  ZX_FUNCTION(0x0, "ANMI"),
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio29 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin0 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int4 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 1, 2, 2, 0x48, 9),
+		  ZX_FUNCTION(0x0, "WD"),	/* rst_b */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio30 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin1 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int5 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 2, 8, 2, 0x50, 0),
+		  ZX_FUNCTION(0x0, "SEC"),	/* en */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio28 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin3 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int7 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 3, 10, 2, 0x50, 9),
+		  ZX_FUNCTION(0x0, "UART0"),	/* rxd */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio20 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin34 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 4, 12, 2, 0x50, 18),
+		  ZX_FUNCTION(0x0, "UART0"),	/* txd */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio21 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin32 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 5, 14, 2, 0x64, 0),
+		  ZX_FUNCTION(0x0, "IR"),	/* in */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio0 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin27 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 6, 16, 2, 0x64, 9),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int0 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio23 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin5 */
+		  ZX_FUNCTION(0x3, "PCU")),	/* test6 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 7, 18, 2, 0x64, 18),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int1 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio24 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin6 */
+		  ZX_FUNCTION(0x3, "PCU")),	/* test0 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 8, 20, 2, 0x68, 0),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int2 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio25 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin7 */
+		  ZX_FUNCTION(0x3, "PCU")),	/* test1 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 9, 22, 2, 0x68, 9),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int3 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio26 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin8 */
+		  ZX_FUNCTION(0x3, "PCU")),	/* test2 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 10, 24, 2, 0x68, 18),
+		  ZX_FUNCTION(0x0, "KEY"),	/* col0 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio5 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin9 */
+		  ZX_FUNCTION(0x3, "PCU")),	/* test3 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 11, 26, 2, 0x6c, 0),
+		  ZX_FUNCTION(0x0, "KEY"),	/* col1 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio6 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin10 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 12, 28, 2, 0x6c, 9),
+		  ZX_FUNCTION(0x0, "KEY"),	/* col2 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio7 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin11 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(A, 13, 30, 2, 0x6c, 18),
+		  ZX_FUNCTION(0x0, "KEY"),	/* row0 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio8 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin33 */
+		  ZX_FUNCTION(0x3, "WD")),	/* rst_b */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 0, 0, 2, 0x70, 0),
+		  ZX_FUNCTION(0x0, "KEY"),	/* row1 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio9 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin12 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 1, 2, 2, 0x70, 9),
+		  ZX_FUNCTION(0x0, "KEY"),	/* row2 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio10 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin13 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 2, 4, 2, 0x70, 18),
+		  ZX_FUNCTION(0x0, "PCU"),	/* test7 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio3 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin14 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 3, 6, 2, 0x74, 0),
+		  ZX_FUNCTION(0x0, "PCU"),	/* test8 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio4 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin15 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 4, 8, 2, 0x78, 18),
+		  ZX_FUNCTION(0x0, "JTAG"),	/* tck */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio11 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin22 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int4 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 5, 10, 2, 0xac, 0),
+		  ZX_FUNCTION(0x0, "JTAG"),	/* trstn */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio12 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin23 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int5 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 6, 12, 2, 0xac, 9),
+		  ZX_FUNCTION(0x0, "JTAG"),	/* tms */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio13 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin24 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int6 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 7, 14, 2, 0xac, 18),
+		  ZX_FUNCTION(0x0, "JTAG"),	/* tdi */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio14 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin25 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int7 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 8, 16, 2, 0xb0, 0),
+		  ZX_FUNCTION(0x0, "JTAG"),	/* tdo */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio15 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin26 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 9, 18, 2, 0xb0, 9),
+		  ZX_FUNCTION(0x0, "I2C0"),	/* scl */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio16 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin28 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 10, 20, 2, 0xb0, 18),
+		  ZX_FUNCTION(0x0, "I2C0"),	/* sda */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio17 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin29 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 11, 22, 2, 0xb4, 0),
+		  ZX_FUNCTION(0x0, "I2C1"),	/* scl */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio18 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin30 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(B, 12, 24, 2, 0xb4, 9),
+		  ZX_FUNCTION(0x0, "I2C1"),	/* sda */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio19 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin31 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 0, 0, 2, 0x40, 9),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int0 */
+		  ZX_FUNCTION(0x1, "PCU"),	/* test12 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin39 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 1, 2, 2, 0x40, 18),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int1 */
+		  ZX_FUNCTION(0x1, "PCU"),	/* test13 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin40 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 2, 4, 2, 0x44, 0),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int2 */
+		  ZX_FUNCTION(0x1, "PCU"),	/* test14 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin41 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 3, 6, 2, 0x44, 9),
+		  ZX_FUNCTION(0x0, "EXT_INT"),	/* int3 */
+		  ZX_FUNCTION(0x1, "PCU"),	/* test15 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin42 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 4, 12, 2, 0x48, 18),
+		  ZX_FUNCTION(0x0, "PCU"),	/* test4 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio27 */
+		  ZX_FUNCTION(0x2, "nonAON"),	/* pin2 */
+		  ZX_FUNCTION(0x3, "EXT_INT")),	/* int16 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 5, 14, 2, 0x78, 9),
+		  ZX_FUNCTION(0x0, "PCU"),	/* test5 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio22 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin4 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 6, 16, 2, 0x74, 9),
+		  ZX_FUNCTION(0x0, "PCU"),	/* test9 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio1 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin16 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 7, 18, 2, 0x74, 18),
+		  ZX_FUNCTION(0x0, "PCU"),	/* test10 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio2 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin17 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 8, 20, 2, 0x78, 0),
+		  ZX_FUNCTION(0x0, "PCU"),	/* test11 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio31 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin43 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 9, 22, 2, 0xc0, 9),
+		  ZX_FUNCTION(0x0, "BOOT"),	/* sel0 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio18 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin18 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 10, 24, 2, 0xc0, 18),
+		  ZX_FUNCTION(0x0, "BOOT"),	/* sel1 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio19 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin19 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 11, 26, 2, 0xc4, 0),
+		  ZX_FUNCTION(0x0, "BOOT"),	/* sel2 */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio20 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin20 */
+	ZX_PIN(ZX_PINCTRL_AONPIN(C, 12, 28, 2, 0xc4, 9),
+		  ZX_FUNCTION(0x0, "DEEPSLP"),	/* deep sleep out_n */
+		  ZX_FUNCTION(0x1, "AGPIO"),	/* agpio21 */
+		  ZX_FUNCTION(0x2, "nonAON")),	/* pin21 */
+};
+
+static struct zx_pinctrl_desc zx296718_pinctrl_data = {
+	.pins = zx296718_pins,
+	.ntop_pins = AONPA_BASE,
+	.npins = ARRAY_SIZE(zx296718_pins),
+};
+
+static int zx296718_pinctrl_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct device_node *np;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	zx296718_pinctrl_data.membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(zx296718_pinctrl_data.membase))
+		return PTR_ERR(zx296718_pinctrl_data.membase);
+
+	np = of_find_compatible_node(NULL, NULL, "zte,zx296718-aonpmx");
+	zx296718_pinctrl_data.aon_membase = of_iomap(np, 0);
+	WARN_ON(!zx296718_pinctrl_data.aon_membase);
+	zx296718_pinctrl_data.cfg_membase = zx296718_pinctrl_data.aon_membase;
+
+	return zx_pinctrl_init(pdev, &zx296718_pinctrl_data);
+}
+
+static const struct of_device_id zx296718_pinctrl_match[] = {
+	{ .compatible = "zte,zx296718-pinctrl", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, zx296718_pinctrl_match);
+
+static struct platform_driver zx296718_pinctrl_driver = {
+	.probe  = zx296718_pinctrl_probe,
+	.driver = {
+		.name       = "zx296718-pinctrl",
+		.of_match_table = zx296718_pinctrl_match,
+	},
+};
+builtin_platform_driver(zx296718_pinctrl_driver);
+
+MODULE_DESCRIPTION("ZTE ZX296718 pinctrl driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document
       [not found] ` <1472213965-4899-1-git-send-email-jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
@ 2016-09-06 14:15   ` Linus Walleij
       [not found]     ` <CACRpkdZ5aHJs8EK29_y7wYZhyHAUdD99wy2RRGD-CZdoJo+NrA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Walleij @ 2016-09-06 14:15 UTC (permalink / raw)
  To: Jun Nie, devicetree-u79uwXL29TY76Z2rM5mHXA, Heiko Stübner,
	Doug Anderson
  Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA, Shawn Guo, Jason Liu

Please always include devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org on subsequent
postings of the bindings.

Also include Heiko Stübner and Doug Andersson who are also
interested in hierarchical pin controllers on subsequent postings.

On Fri, Aug 26, 2016 at 2:19 PM, Jun Nie <jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:

> +The pins controlled by ZX pin controller are organized in banks,
> +number of pins in each bank may vary.  Each pin has different multiplexing
> +functions. There are two type of pins, normal ones and AON ones.

I understand so far. Spell out what the acronym AON means. Does
it mean "always-on?"

> + AON
> +pins control high level multiplex and normal pins may require multiplex
> +configuration of parent AON pins.

I don't understand this at all.

What is "high level multiplex"?

Since you mention parents I suspect that what you are referring to is
that the pins are hierarchical, and that they are controlled by two
levels of pin controllers, such that a physical pin is connected to pin
controller A which can multiplex pins to N functions, and then the line
from A is connected to another pin controller B that can again multiplex
to M other functions?

Please describe this hardware set-up with *lots* of detail so we have
a chance of understanding it fully. All necessary information shall go
into this DT binding document so we know where to look it up.

> + As the AON pins number is not as much as
> +normal pins, some normal pins are not routed through AON pin side and are
> +under direct control by itself.

I don't understand this. I suspect the English language may be a
problem here, I think "as much as" should be "as many as", also
subject and object is very hard to understand when the pin controller
is referred to as "itself". It's just very hard to parse, sorry. Please
elaborate and I will try to understand and help as much as I can.

> +Required properties:
> +- compatible:
> +  "zte,zx296718-pinctrl"
> +  "zte,zx296718-aonpmx"
> +
> +- reg: Should contain the register physical address and length for the
> +  pin controller.

OK

> +IO pull up/down etc configuration is supported with unified management of
> +normal pins and AON pins. The configuration registers area is just after
> +AON pinmux reg area, while normal pins regs in different area. So two dts
> +nodes are needed to provides the two reg regions.

Again hard to understand, but why do you need two nodes
and not just two register areas regs = <a b>, <c d>;?

I guess because one pin controller is using another one but
I'm not sure.

> +Below configuration are supported. Please refer to pinctrl-bindings.txt
> +in this directory for more details of the common pinctrl bindings used
> +by client devices.
> +
> +bias-pull-up            - pull up the pin
> +bias-pull-down          - pull down the pin
> +drive-strength          - sink or source at most 7 mA
> +input-enable            - enable input on pin (no effect on output)
> +power-source            - select power supplies. 1: 1.8V, 0: 3.3V
> +slew-rate               - set the slew rate

OK

> +Pin names are defined by bank sequence and pins number in the bank. For
> +example, B2 is the 3rd pin in the second bank. The AON pin has prefix
> +AON, like AONC2.

OK

> +Example dts nodes:
> +
> +pinctop: pinctrl@01462000 {
> +       compatible = "zte,zx296718-pinctrl";
> +       reg = <0x01462000 0x1000>;
> +
> +       i2c5_pins: i2c5pins {
> +               pins = "G6", "G7";
> +               function = "I2C5";
> +       }
> +};
> +
> +pmx_aon: pinctrl@00119000 {
> +       compatible = "zte,zx296718-aonpmx";
> +       reg = <0x00119000 0x1000>;
> +};

The problem with this devicetree is that it does not express the hierarchical
nature that you describe above. And I have no idea how the driver
handles that relation. These look like two independent pin controller
but AFAICT they are not.

These are arrangements that make more sense:

pinctrla {
    compatible = "parent-device-compat";
    (...)
    pinctrlb {
        compatible = "child-device-compat";
        (...)
    };
};

This makes the child pin controller a proper child of the parent and
make the child probe instantiate from the parent (in
Linux of_platform_default_populate() inside the parent driver)
and thus it knows the parent is always available before the child.

Another arrangement is:

pa: pinctrla {
    compatible = "parent-device-compat";
    (...)
};

pb: pinctrlb {
    compatible = "child-device-compat";
    pinctrl-parent = &pinctrla;
    (...)
};

This is in case we need to have hierarchies defined this way.

I don't know the best way to define hierarchical pin controllers yet
so we definately need some discussion about it.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] pinctrl: zx: Add ZTE ZX SoC pinctrl driver
  2016-08-26 12:19 ` [PATCH 3/3] pinctrl: zx: Add ZTE ZX SoC pinctrl driver Jun Nie
@ 2016-09-06 14:31   ` Linus Walleij
  2016-09-07  4:45     ` Jun Nie
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Walleij @ 2016-09-06 14:31 UTC (permalink / raw)
  To: Jun Nie, Heiko Stübner, Doug Anderson
  Cc: linux-gpio, Shawn Guo, Jason Liu

On Fri, Aug 26, 2016 at 2:19 PM, Jun Nie <jun.nie@linaro.org> wrote:

> This adds pinctrl driver for ZTE ZX platform. The bit width
> of pinmux registers are not unified, so this dedicated driver
> is needed and detail bit width data is store in private data.
> The parent pin information is also stored in private data so
> that parent pin can be requested automatically.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>

(...)
> +static int zx_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
> +                                  struct device_node *np_config,
> +                                  struct pinctrl_map **map,
> +                                  u32 *num_maps)
> +{
> +       return pinconf_generic_dt_node_to_map(pctldev, np_config, map,
> +                                             num_maps, PIN_MAP_TYPE_INVALID);
> +}

Uhm...

> +static const struct pinctrl_ops zx_pctrl_ops = {
> +       .dt_node_to_map         = zx_pctrl_dt_node_to_map,

Can't you just put pinconf_generic_dt_node_to_map here?

> +       .dt_free_map            = pinctrl_utils_free_map,
> +       .get_groups_count       = zx_pctrl_get_groups_count,
> +       .get_group_name         = zx_pctrl_get_group_name,
> +       .get_group_pins         = zx_pctrl_get_group_pins,
> +};

(...)

> +#define NONAON_MVAL 2
> +int zx_pmx_request(struct pinctrl_dev *pctldev, unsigned offset)
> +{
> +       struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
> +       int ret;
> +       const struct pinctrl_pin_desc *pins = pctldev->desc->pins;
> +       struct zx_pin_desc_data *zx_pin_dat;
> +
> +       pins += offset;
> +       zx_pin_dat = (struct zx_pin_desc_data *)pins->drv_data;
> +       if (!zx_pin_dat->parent)
> +               return 0;
> +
> +       ret = pinctrl_request_pin(pctldev, zx_pin_dat->parent, "nonAON");
> +       if (ret) {
> +               dev_err(pctl->dev, "Failed to request parent pin %d\n",
> +                       zx_pin_dat->parent);
> +               return ret;
> +       }

This is the real trick isn't it?

I don't like exposing that function directly like this. It's
shortcutting through
the abstractions.

What we need is either:

- A way to describe that a pin controller is fully a child of another
  pin controller, a "strict hierarchy" if all pins go through both pin
  controllers.

OR

- If only *some* pins go routed through the hierarchy: something akin
  to the GPIO pin ranges. That makes it possible to specify in the
  device tree which lines are hierarchical and how that plays out.

Apart from this the driver looks all right, but we need to figure out
how to represent the hierarchy.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document
       [not found]     ` <CACRpkdZ5aHJs8EK29_y7wYZhyHAUdD99wy2RRGD-CZdoJo+NrA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2016-09-06 14:43       ` Linus Walleij
  2016-09-07  4:07         ` Jun Nie
  2016-09-07  3:40       ` Jun Nie
  1 sibling, 1 reply; 8+ messages in thread
From: Linus Walleij @ 2016-09-06 14:43 UTC (permalink / raw)
  To: Jun Nie, devicetree-u79uwXL29TY76Z2rM5mHXA, Heiko Stübner,
	Doug Anderson
  Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA, Shawn Guo, Jason Liu

On Tue, Sep 6, 2016 at 4:15 PM, Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:

> pa: pinctrla {
>     compatible = "parent-device-compat";
>     (...)
> };
>
> pb: pinctrlb {
>     compatible = "child-device-compat";
>     pinctrl-parent = &pinctrla;
>     (...)
> };

After thinking some more I kind of fancy the GPIO ranges
approach to be reused:

pa: pinctrla {
    compatible = "parent-device-compat";
    (...)
};

pb: pinctrlb {
    compatible = "child-device-compat";
    pinctrl-ranges = <&pa 0 31 0>;
    (...)
};

The definition and use would be similar to gpio-ranges, see:
Documentation/devicetree/bindings/gpio/gpio.txt, but these
bindings are specified in BNF which IMO is just confusing.

Anyways its <phandle local-offset count remote-offset>

Also group names are supported for GPIO ranges.

In the Linux implementation this facilitates reuse of the
existing GPIO ranges parsing and resolution.

To make cross-calls we need an abstract call akin to the
existing pinctrl_request_gpio() and pinctrl_free_gpio()
just named pinctrl_request_hierarchical()
pinctrl_free_hierarchical() or so so it is chrystal clear
what is going on when reading the code.

As this passes through the pinctrl driver core, new callbacks
are needed in struct pinmux_ops such as
.hierarchical_request(), .hierarchical_free().

This is going to be complex, but a way more maintainable
solution than doing the hack in patch 1/3 where we totally
loose control and definition of what happens.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document
       [not found]     ` <CACRpkdZ5aHJs8EK29_y7wYZhyHAUdD99wy2RRGD-CZdoJo+NrA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2016-09-06 14:43       ` Linus Walleij
@ 2016-09-07  3:40       ` Jun Nie
  1 sibling, 0 replies; 8+ messages in thread
From: Jun Nie @ 2016-09-07  3:40 UTC (permalink / raw)
  To: Linus Walleij
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Heiko Stübner,
	Doug Anderson, linux-gpio-u79uwXL29TY76Z2rM5mHXA, Shawn Guo,
	Jason Liu

2016-09-06 22:15 GMT+08:00 Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
> Please always include devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org on subsequent
> postings of the bindings.
>
> Also include Heiko Stübner and Doug Andersson who are also
> interested in hierarchical pin controllers on subsequent postings.
>
> On Fri, Aug 26, 2016 at 2:19 PM, Jun Nie <jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>
>> +The pins controlled by ZX pin controller are organized in banks,
>> +number of pins in each bank may vary.  Each pin has different multiplexing
>> +functions. There are two type of pins, normal ones and AON ones.
>
> I understand so far. Spell out what the acronym AON means. Does
> it mean "always-on?"
>
>> + AON
>> +pins control high level multiplex and normal pins may require multiplex
>> +configuration of parent AON pins.
>
> I don't understand this at all.
>
> What is "high level multiplex"?
>
> Since you mention parents I suspect that what you are referring to is
> that the pins are hierarchical, and that they are controlled by two
> levels of pin controllers, such that a physical pin is connected to pin
> controller A which can multiplex pins to N functions, and then the line
> from A is connected to another pin controller B that can again multiplex
> to M other functions?
>
> Please describe this hardware set-up with *lots* of detail so we have
> a chance of understanding it fully. All necessary information shall go
> into this DT binding document so we know where to look it up.
>
Here is more hardware detail. Will add it to document later.

Hardware has two register regions to control pinmux, one is for normal
function configuration and the other one is for always on subsystem(AON).
Some pins are controlled by both normal register and AON register, while
some pins are controlled only by normal register. That means some pins
are hierarchical, AON register is the 1st level control for pinmux. If
we need any function in normal register pin multiplexing, we need configure
related AON pinmux register to non-AON function first. Then we configure
normal pinmux register to get the pin function we want. For those pins
that are not controlled by AON registers, we just need to configure normal
pinmux register for function multiplexing.

All pin configuration, such as pull up/down, is controlled by registers
in AON register region, which is layouted just after AON pinmux registers.
So we need access AON register region even we are configuring normal
pins which has no AON pin multiplex functions.

>> + As the AON pins number is not as much as
>> +normal pins, some normal pins are not routed through AON pin side and are
>> +under direct control by itself.
>
> I don't understand this. I suspect the English language may be a
> problem here, I think "as much as" should be "as many as", also
> subject and object is very hard to understand when the pin controller
> is referred to as "itself". It's just very hard to parse, sorry. Please
> elaborate and I will try to understand and help as much as I can.
>
>> +Required properties:
>> +- compatible:
>> +  "zte,zx296718-pinctrl"
>> +  "zte,zx296718-aonpmx"
>> +
>> +- reg: Should contain the register physical address and length for the
>> +  pin controller.
>
> OK
>
>> +IO pull up/down etc configuration is supported with unified management of
>> +normal pins and AON pins. The configuration registers area is just after
>> +AON pinmux reg area, while normal pins regs in different area. So two dts
>> +nodes are needed to provides the two reg regions.
>
> Again hard to understand, but why do you need two nodes
> and not just two register areas regs = <a b>, <c d>;?
>
> I guess because one pin controller is using another one but
> I'm not sure.

Thanks for pointing the usage of  regs = <a b>, <c d>;
For normal pinmux function, we still need AON registers for pin
configuration, maybe
this is what you care.

>
>> +Below configuration are supported. Please refer to pinctrl-bindings.txt
>> +in this directory for more details of the common pinctrl bindings used
>> +by client devices.
>> +
>> +bias-pull-up            - pull up the pin
>> +bias-pull-down          - pull down the pin
>> +drive-strength          - sink or source at most 7 mA
>> +input-enable            - enable input on pin (no effect on output)
>> +power-source            - select power supplies. 1: 1.8V, 0: 3.3V
>> +slew-rate               - set the slew rate
>
> OK
>
>> +Pin names are defined by bank sequence and pins number in the bank. For
>> +example, B2 is the 3rd pin in the second bank. The AON pin has prefix
>> +AON, like AONC2.
>
> OK
>
>> +Example dts nodes:
>> +
>> +pinctop: pinctrl@01462000 {
>> +       compatible = "zte,zx296718-pinctrl";
>> +       reg = <0x01462000 0x1000>;
>> +
>> +       i2c5_pins: i2c5pins {
>> +               pins = "G6", "G7";
>> +               function = "I2C5";
>> +       }
>> +};
>> +
>> +pmx_aon: pinctrl@00119000 {
>> +       compatible = "zte,zx296718-aonpmx";
>> +       reg = <0x00119000 0x1000>;
>> +};
>
> The problem with this devicetree is that it does not express the hierarchical
> nature that you describe above. And I have no idea how the driver
> handles that relation. These look like two independent pin controller
> but AFAICT they are not.
>
> These are arrangements that make more sense:
>
> pinctrla {
>     compatible = "parent-device-compat";
>     (...)
>     pinctrlb {
>         compatible = "child-device-compat";
>         (...)
>     };
> };
>
> This makes the child pin controller a proper child of the parent and
> make the child probe instantiate from the parent (in
> Linux of_platform_default_populate() inside the parent driver)
> and thus it knows the parent is always available before the child.
>
> Another arrangement is:
>
> pa: pinctrla {
>     compatible = "parent-device-compat";
>     (...)
> };
>
> pb: pinctrlb {
>     compatible = "child-device-compat";
>     pinctrl-parent = &pinctrla;
>     (...)
> };
>
> This is in case we need to have hierarchies defined this way.

Yes, the two arrangements are clearer to show the parent relation.

>
> I don't know the best way to define hierarchical pin controllers yet
> so we definately need some discussion about it.
>
> Yours,
> Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document
  2016-09-06 14:43       ` Linus Walleij
@ 2016-09-07  4:07         ` Jun Nie
  0 siblings, 0 replies; 8+ messages in thread
From: Jun Nie @ 2016-09-07  4:07 UTC (permalink / raw)
  To: Linus Walleij
  Cc: devicetree, Heiko Stübner, Doug Anderson, linux-gpio,
	Shawn Guo, Jason Liu

2016-09-06 22:43 GMT+08:00 Linus Walleij <linus.walleij@linaro.org>:
> On Tue, Sep 6, 2016 at 4:15 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
>
>> pa: pinctrla {
>>     compatible = "parent-device-compat";
>>     (...)
>> };
>>
>> pb: pinctrlb {
>>     compatible = "child-device-compat";
>>     pinctrl-parent = &pinctrla;
>>     (...)
>> };
>
> After thinking some more I kind of fancy the GPIO ranges
> approach to be reused:
>
> pa: pinctrla {
>     compatible = "parent-device-compat";
>     (...)
> };
>
> pb: pinctrlb {
>     compatible = "child-device-compat";
>     pinctrl-ranges = <&pa 0 31 0>;
>     (...)
> };
>
> The definition and use would be similar to gpio-ranges, see:
> Documentation/devicetree/bindings/gpio/gpio.txt, but these
> bindings are specified in BNF which IMO is just confusing.
>
> Anyways its <phandle local-offset count remote-offset>
>
> Also group names are supported for GPIO ranges.
>
> In the Linux implementation this facilitates reuse of the
> existing GPIO ranges parsing and resolution.
>
> To make cross-calls we need an abstract call akin to the
> existing pinctrl_request_gpio() and pinctrl_free_gpio()
> just named pinctrl_request_hierarchical()
> pinctrl_free_hierarchical() or so so it is chrystal clear
> what is going on when reading the code.
>
> As this passes through the pinctrl driver core, new callbacks
> are needed in struct pinmux_ops such as
> .hierarchical_request(), .hierarchical_free().

The GPIO range method does provide clear hierarchical relation
and ease maintenance. But pin configuration of normal pins
and AON/normal shared pins are mixed together with one register
controlling 3 pin config. So I need find a way to handle the pin
configuration sharing.

Maybe splitting pin configuration to another driver is a solution with
pin config range linked the two pinmux devices like GPIO range.
But this lead to more complexity.

>
> This is going to be complex, but a way more maintainable
> solution than doing the hack in patch 1/3 where we totally
> loose control and definition of what happens.
>
> Yours,
> Linus Walleij

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] pinctrl: zx: Add ZTE ZX SoC pinctrl driver
  2016-09-06 14:31   ` Linus Walleij
@ 2016-09-07  4:45     ` Jun Nie
  0 siblings, 0 replies; 8+ messages in thread
From: Jun Nie @ 2016-09-07  4:45 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Heiko Stübner, Doug Anderson, linux-gpio, Shawn Guo, Jason Liu

2016-09-06 22:31 GMT+08:00 Linus Walleij <linus.walleij@linaro.org>:
> On Fri, Aug 26, 2016 at 2:19 PM, Jun Nie <jun.nie@linaro.org> wrote:
>
>> This adds pinctrl driver for ZTE ZX platform. The bit width
>> of pinmux registers are not unified, so this dedicated driver
>> is needed and detail bit width data is store in private data.
>> The parent pin information is also stored in private data so
>> that parent pin can be requested automatically.
>>
>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>
> (...)
>> +static int zx_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
>> +                                  struct device_node *np_config,
>> +                                  struct pinctrl_map **map,
>> +                                  u32 *num_maps)
>> +{
>> +       return pinconf_generic_dt_node_to_map(pctldev, np_config, map,
>> +                                             num_maps, PIN_MAP_TYPE_INVALID);
>> +}
>
> Uhm...
>
>> +static const struct pinctrl_ops zx_pctrl_ops = {
>> +       .dt_node_to_map         = zx_pctrl_dt_node_to_map,
>
> Can't you just put pinconf_generic_dt_node_to_map here?

The callback function argument number is different with
pinconf_generic_dt_node_to_map. So a wrapper is needed.

>
>> +       .dt_free_map            = pinctrl_utils_free_map,
>> +       .get_groups_count       = zx_pctrl_get_groups_count,
>> +       .get_group_name         = zx_pctrl_get_group_name,
>> +       .get_group_pins         = zx_pctrl_get_group_pins,
>> +};
>
> (...)
>
>> +#define NONAON_MVAL 2
>> +int zx_pmx_request(struct pinctrl_dev *pctldev, unsigned offset)
>> +{
>> +       struct zx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
>> +       int ret;
>> +       const struct pinctrl_pin_desc *pins = pctldev->desc->pins;
>> +       struct zx_pin_desc_data *zx_pin_dat;
>> +
>> +       pins += offset;
>> +       zx_pin_dat = (struct zx_pin_desc_data *)pins->drv_data;
>> +       if (!zx_pin_dat->parent)
>> +               return 0;
>> +
>> +       ret = pinctrl_request_pin(pctldev, zx_pin_dat->parent, "nonAON");
>> +       if (ret) {
>> +               dev_err(pctl->dev, "Failed to request parent pin %d\n",
>> +                       zx_pin_dat->parent);
>> +               return ret;
>> +       }
>
> This is the real trick isn't it?
>
> I don't like exposing that function directly like this. It's
> shortcutting through
> the abstractions.
>
> What we need is either:
>
> - A way to describe that a pin controller is fully a child of another
>   pin controller, a "strict hierarchy" if all pins go through both pin
>   controllers.
>
> OR
>
> - If only *some* pins go routed through the hierarchy: something akin
>   to the GPIO pin ranges. That makes it possible to specify in the
>   device tree which lines are hierarchical and how that plays out.

As my reply in 2/3 patches, the shared pin config registers make me to
merge the two pin controllers driver together to ease pin config code.
GPIO pin ranges like logic surely provide clearer hierarchical. I am thinking
whether pin config can share the pinmux hierarchical path to get the
data to configure the required register.

>
> Apart from this the driver looks all right, but we need to figure out
> how to represent the hierarchy.
>
> Yours,
> Linus Walleij

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-09-07  4:45 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-26 12:19 [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document Jun Nie
2016-08-26 12:19 ` [PATCH 3/3] pinctrl: zx: Add ZTE ZX SoC pinctrl driver Jun Nie
2016-09-06 14:31   ` Linus Walleij
2016-09-07  4:45     ` Jun Nie
     [not found] ` <1472213965-4899-1-git-send-email-jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2016-09-06 14:15   ` [PATCH 2/3] pinctrl: zx: Add ZTE pinctrl dts document Linus Walleij
     [not found]     ` <CACRpkdZ5aHJs8EK29_y7wYZhyHAUdD99wy2RRGD-CZdoJo+NrA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-09-06 14:43       ` Linus Walleij
2016-09-07  4:07         ` Jun Nie
2016-09-07  3:40       ` Jun Nie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.