linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support
@ 2012-07-24  6:50 John Crispin
  2012-07-24  6:50 ` [PATCH 2/6] Document: devicetree: add OF documents for lantiq xway pinctrl John Crispin
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: John Crispin @ 2012-07-24  6:50 UTC (permalink / raw)
  To: Grant Likely; +Cc: John Crispin, devicetree-discuss, linux-kernel

Implement support for pinctrl on lantiq/xway socs. The IO core found on these
socs has the registers for pinctrl, pinconf and gpio mixed up in the same
register range. As the gpio_chip handling is only a few lines, the driver also
implements the gpio functionality. This obseletes the old gpio driver that was
located in the arch/ folder.

Signed-off-by: John Crispin <blogic@openwrt.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-kernel@vger.kernel.org

---
Previously ack'ed in V2
--> http://www.linux-mips.org/archives/linux-mips/2012-05/msg00127.html

Changes in V3
* add MDIO definitions

Changes in V2
* cleanup select/depends of the relevant Kconfig symbols
* dont assume that the arry with out MFPs is linearly mapped
* sane return code checks inside ltq_pinctrl_dt_node_to_map
* remove 2 calls to pr_err and replace them with calls to dev_err
* propagate gpio_chips base addr to the gpio_range
* define the pin count inside the of_device_id.data
* minor changes to accomodate the pinctrl-falcon driver (more virt pointers
  and clocks)
* change from core_initcall_sync to arch_initcall
* several typos, codestyle and whitespace cleanups
* use BIT(x) in favour of (1 << x)

 arch/mips/Kconfig                |    2 +
 arch/mips/lantiq/Kconfig         |    1 +
 arch/mips/lantiq/xway/Makefile   |    2 +-
 arch/mips/lantiq/xway/gpio.c     |  183 -----------
 drivers/pinctrl/Kconfig          |   11 +
 drivers/pinctrl/Makefile         |    2 +
 drivers/pinctrl/pinctrl-lantiq.c |  342 ++++++++++++++++++++
 drivers/pinctrl/pinctrl-lantiq.h |  190 +++++++++++
 drivers/pinctrl/pinctrl-xway.c   |  657 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 1206 insertions(+), 184 deletions(-)
 delete mode 100644 arch/mips/lantiq/xway/gpio.c
 create mode 100644 drivers/pinctrl/pinctrl-lantiq.c
 create mode 100644 drivers/pinctrl/pinctrl-lantiq.h
 create mode 100644 drivers/pinctrl/pinctrl-xway.c

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 61e1459..ec6e2a7 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -237,6 +237,8 @@ config LANTIQ
 	select HAVE_MACH_CLKDEV
 	select CLKDEV_LOOKUP
 	select USE_OF
+	select PINCTRL
+	select PINCTRL_LANTIQ
 
 config LASAT
 	bool "LASAT Networks platforms"
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
index 20bdf40..080c013 100644
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -2,6 +2,7 @@ if LANTIQ
 
 config SOC_TYPE_XWAY
 	bool
+	select PINCTRL_XWAY
 	default n
 
 choice
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index dc3194f..729ea9e 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1 +1 @@
-obj-y := prom.o sysctrl.o clk.o reset.o gpio.o dma.o
+obj-y := prom.o sysctrl.o clk.o reset.o dma.o
diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c
deleted file mode 100644
index 2ab39e9..0000000
--- a/arch/mips/lantiq/xway/gpio.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *  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.
- *
- *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-
-#include <lantiq_soc.h>
-
-#define LTQ_GPIO_OUT		0x00
-#define LTQ_GPIO_IN		0x04
-#define LTQ_GPIO_DIR		0x08
-#define LTQ_GPIO_ALTSEL0	0x0C
-#define LTQ_GPIO_ALTSEL1	0x10
-#define LTQ_GPIO_OD		0x14
-
-#define PINS_PER_PORT		16
-#define MAX_PORTS		3
-
-#define ltq_gpio_getbit(m, r, p)	(!!(ltq_r32(m + r) & (1 << p)))
-#define ltq_gpio_setbit(m, r, p)	ltq_w32_mask(0, (1 << p), m + r)
-#define ltq_gpio_clearbit(m, r, p)	ltq_w32_mask((1 << p), 0, m + r)
-
-struct ltq_gpio {
-	void __iomem *membase;
-	struct gpio_chip chip;
-};
-
-static struct ltq_gpio ltq_gpio_port[MAX_PORTS];
-
-int ltq_gpio_request(unsigned int pin, unsigned int alt0,
-	unsigned int alt1, unsigned int dir, const char *name)
-{
-	int id = 0;
-
-	if (pin >= (MAX_PORTS * PINS_PER_PORT))
-		return -EINVAL;
-	if (gpio_request(pin, name)) {
-		pr_err("failed to setup lantiq gpio: %s\n", name);
-		return -EBUSY;
-	}
-	if (dir)
-		gpio_direction_output(pin, 1);
-	else
-		gpio_direction_input(pin);
-	while (pin >= PINS_PER_PORT) {
-		pin -= PINS_PER_PORT;
-		id++;
-	}
-	if (alt0)
-		ltq_gpio_setbit(ltq_gpio_port[id].membase,
-			LTQ_GPIO_ALTSEL0, pin);
-	else
-		ltq_gpio_clearbit(ltq_gpio_port[id].membase,
-			LTQ_GPIO_ALTSEL0, pin);
-	if (alt1)
-		ltq_gpio_setbit(ltq_gpio_port[id].membase,
-			LTQ_GPIO_ALTSEL1, pin);
-	else
-		ltq_gpio_clearbit(ltq_gpio_port[id].membase,
-			LTQ_GPIO_ALTSEL1, pin);
-	return 0;
-}
-EXPORT_SYMBOL(ltq_gpio_request);
-
-static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
-{
-	struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
-
-	if (value)
-		ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
-	else
-		ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
-}
-
-static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
-	struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
-
-	return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset);
-}
-
-static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
-{
-	struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
-
-	ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
-	ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
-
-	return 0;
-}
-
-static int ltq_gpio_direction_output(struct gpio_chip *chip,
-	unsigned int offset, int value)
-{
-	struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
-
-	ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
-	ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
-	ltq_gpio_set(chip, offset, value);
-
-	return 0;
-}
-
-static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
-{
-	struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
-
-	ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset);
-	ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
-	return 0;
-}
-
-static int ltq_gpio_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-
-	if (pdev->id >= MAX_PORTS) {
-		dev_err(&pdev->dev, "invalid gpio port %d\n",
-			pdev->id);
-		return -EINVAL;
-	}
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to get memory for gpio port %d\n",
-			pdev->id);
-		return -ENOENT;
-	}
-	res = devm_request_mem_region(&pdev->dev, res->start,
-		resource_size(res), dev_name(&pdev->dev));
-	if (!res) {
-		dev_err(&pdev->dev,
-			"failed to request memory for gpio port %d\n",
-			pdev->id);
-		return -EBUSY;
-	}
-	ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev,
-		res->start, resource_size(res));
-	if (!ltq_gpio_port[pdev->id].membase) {
-		dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n",
-			pdev->id);
-		return -ENOMEM;
-	}
-	ltq_gpio_port[pdev->id].chip.label = "ltq_gpio";
-	ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input;
-	ltq_gpio_port[pdev->id].chip.direction_output =
-		ltq_gpio_direction_output;
-	ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get;
-	ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set;
-	ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req;
-	ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id;
-	ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
-	platform_set_drvdata(pdev, &ltq_gpio_port[pdev->id]);
-	return gpiochip_add(&ltq_gpio_port[pdev->id].chip);
-}
-
-static struct platform_driver
-ltq_gpio_driver = {
-	.probe = ltq_gpio_probe,
-	.driver = {
-		.name = "ltq_gpio",
-		.owner = THIS_MODULE,
-	},
-};
-
-int __init ltq_gpio_init(void)
-{
-	int ret = platform_driver_register(&ltq_gpio_driver);
-
-	if (ret)
-		pr_info("ltq_gpio : Error registering platform driver!");
-	return ret;
-}
-
-postcore_initcall(ltq_gpio_init);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 54e3588..f77dce0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -55,6 +55,12 @@ config PINCTRL_IMX6Q
 	help
 	  Say Y here to enable the imx6q pinctrl driver
 
+config PINCTRL_LANTIQ
+	bool
+	depends on LANTIQ
+	select PINMUX
+	select PINCONF
+
 config PINCTRL_PXA3xx
 	bool
 	select PINMUX
@@ -147,6 +153,11 @@ config PINCTRL_COH901
 
 source "drivers/pinctrl/spear/Kconfig"
 
+config PINCTRL_XWAY
+	bool
+	depends on SOC_TYPE_XWAY
+	depends on PINCTRL_LANTIQ
+
 endmenu
 
 endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f40b1f8..e19e207 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -29,5 +29,7 @@ obj-$(CONFIG_PINCTRL_TEGRA20)	+= pinctrl-tegra20.o
 obj-$(CONFIG_PINCTRL_TEGRA30)	+= pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_U300)	+= pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)	+= pinctrl-coh901.o
+obj-$(CONFIG_PINCTRL_XWAY)	+= pinctrl-xway.o
+obj-$(CONFIG_PINCTRL_LANTIQ)	+= pinctrl-lantiq.o
 
 obj-$(CONFIG_PLAT_SPEAR)	+= spear/
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
new file mode 100644
index 0000000..07ba768
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -0,0 +1,342 @@
+/*
+ *  linux/drivers/pinctrl/pinctrl-lantiq.c
+ *  based on linux/drivers/pinctrl/pinctrl-pxa3xx.c
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "pinctrl-lantiq.h"
+
+static int ltq_get_group_count(struct pinctrl_dev *pctrldev)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	return info->num_grps;
+}
+
+static const char *ltq_get_group_name(struct pinctrl_dev *pctrldev,
+					 unsigned selector)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	if (selector >= info->num_grps)
+		return NULL;
+	return info->grps[selector].name;
+}
+
+static int ltq_get_group_pins(struct pinctrl_dev *pctrldev,
+				 unsigned selector,
+				 const unsigned **pins,
+				 unsigned *num_pins)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	if (selector >= info->num_grps)
+		return -EINVAL;
+	*pins = info->grps[selector].pins;
+	*num_pins = info->grps[selector].npins;
+	return 0;
+}
+
+void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+				struct pinctrl_map *map, unsigned num_maps)
+{
+	int i;
+
+	for (i = 0; i < num_maps; i++)
+		if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+			kfree(map[i].data.configs.configs);
+	kfree(map);
+}
+
+static void ltq_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+					struct seq_file *s,
+					unsigned offset)
+{
+	seq_printf(s, " %s", dev_name(pctldev->dev));
+}
+
+static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+				struct device_node *np,
+				struct pinctrl_map **map)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
+	unsigned long configs[3];
+	unsigned num_configs = 0;
+	struct property *prop;
+	const char *group, *pin;
+	const char *function;
+	int ret, i;
+
+	ret = of_property_read_string(np, "lantiq,function", &function);
+	if (!ret) {
+		of_property_for_each_string(np, "lantiq,groups", prop, group) {
+			(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
+			(*map)->name = function;
+			(*map)->data.mux.group = group;
+			(*map)->data.mux.function = function;
+			(*map)++;
+		}
+		if (of_find_property(np, "lantiq,pins", NULL))
+			dev_err(pctldev->dev,
+				"%s mixes pins and groups settings\n",
+				np->name);
+		return 0;
+	}
+
+	for (i = 0; i < info->num_params; i++) {
+		u32 val;
+		int ret = of_property_read_u32(np,
+				info->params[i].property, &val);
+		if (!ret)
+			configs[num_configs++] =
+				LTQ_PINCONF_PACK(info->params[i].param,
+				val);
+	}
+
+	if (!num_configs)
+		return -EINVAL;
+
+	of_property_for_each_string(np, "lantiq,pins", prop, pin) {
+		(*map)->data.configs.configs = kmemdup(configs,
+					num_configs * sizeof(unsigned long),
+					GFP_KERNEL);
+		(*map)->type = PIN_MAP_TYPE_CONFIGS_PIN;
+		(*map)->name = pin;
+		(*map)->data.configs.group_or_pin = pin;
+		(*map)->data.configs.num_configs = num_configs;
+		(*map)++;
+	}
+	return 0;
+}
+
+static int ltq_pinctrl_dt_subnode_size(struct device_node *np)
+{
+	int ret;
+
+	ret = of_property_count_strings(np, "lantiq,groups");
+	if (ret < 0)
+		ret = of_property_count_strings(np, "lantiq,pins");
+	return ret;
+}
+
+int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+				struct device_node *np_config,
+				struct pinctrl_map **map,
+				unsigned *num_maps)
+{
+	struct pinctrl_map *tmp;
+	struct device_node *np;
+	int ret;
+
+	*num_maps = 0;
+	for_each_child_of_node(np_config, np)
+		*num_maps += ltq_pinctrl_dt_subnode_size(np);
+	*map = kzalloc(*num_maps * sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (!*map)
+		return -ENOMEM;
+	tmp = *map;
+
+	for_each_child_of_node(np_config, np) {
+		ret = ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp);
+		if (ret < 0) {
+			ltq_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static struct pinctrl_ops ltq_pctrl_ops = {
+	.get_groups_count	= ltq_get_group_count,
+	.get_group_name		= ltq_get_group_name,
+	.get_group_pins		= ltq_get_group_pins,
+	.pin_dbg_show		= ltq_pinctrl_pin_dbg_show,
+	.dt_node_to_map		= ltq_pinctrl_dt_node_to_map,
+	.dt_free_map		= ltq_pinctrl_dt_free_map,
+};
+
+static int ltq_pmx_func_count(struct pinctrl_dev *pctrldev)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+
+	return info->num_funcs;
+}
+
+static const char *ltq_pmx_func_name(struct pinctrl_dev *pctrldev,
+					 unsigned selector)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+
+	if (selector >= info->num_funcs)
+		return NULL;
+
+	return info->funcs[selector].name;
+}
+
+static int ltq_pmx_get_groups(struct pinctrl_dev *pctrldev,
+				unsigned func,
+				const char * const **groups,
+				unsigned * const num_groups)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+
+	*groups = info->funcs[func].groups;
+	*num_groups = info->funcs[func].num_groups;
+
+	return 0;
+}
+
+/* Return function number. If failure, return negative value. */
+static int match_mux(const struct ltq_mfp_pin *mfp, unsigned mux)
+{
+	int i;
+	for (i = 0; i < LTQ_MAX_MUX; i++) {
+		if (mfp->func[i] == mux)
+			break;
+	}
+	if (i >= LTQ_MAX_MUX)
+		return -EINVAL;
+	return i;
+}
+
+/* dont assume .mfp is linearly mapped. find the mfp with the correct .pin */
+static int match_mfp(const struct ltq_pinmux_info *info, int pin)
+{
+	int i;
+	for (i = 0; i < info->num_mfp; i++) {
+		if (info->mfp[i].pin == pin)
+			return i;
+	}
+	return -1;
+}
+
+/* check whether current pin configuration is valid. Negative for failure */
+static int match_group_mux(const struct ltq_pin_group *grp,
+			   const struct ltq_pinmux_info *info,
+			   unsigned mux)
+{
+	int i, pin, ret = 0;
+	for (i = 0; i < grp->npins; i++) {
+		pin = match_mfp(info, grp->pins[i]);
+		if (pin < 0) {
+			dev_err(info->dev, "could not find mfp for pin %d\n",
+				grp->pins[i]);
+			return -EINVAL;
+		}
+		ret = match_mux(&info->mfp[pin], mux);
+		if (ret < 0) {
+			dev_err(info->dev, "Can't find mux %d on pin%d\n",
+				mux, pin);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int ltq_pmx_enable(struct pinctrl_dev *pctrldev,
+				unsigned func,
+				unsigned group)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	const struct ltq_pin_group *pin_grp = &info->grps[group];
+	int i, pin, pin_func, ret;
+
+	if (!pin_grp->npins ||
+		(match_group_mux(pin_grp, info, pin_grp->mux) < 0)) {
+		dev_err(info->dev, "Failed to set the pin group: %s\n",
+			info->grps[group].name);
+		return -EINVAL;
+	}
+	for (i = 0; i < pin_grp->npins; i++) {
+		pin = match_mfp(info, pin_grp->pins[i]);
+		if (pin < 0) {
+			dev_err(info->dev, "could not find mfp for pin %d\n",
+				pin_grp->pins[i]);
+			return -EINVAL;
+		}
+		pin_func = match_mux(&info->mfp[pin], pin_grp->mux);
+		ret = info->apply_mux(pctrldev, pin, pin_func);
+		if (ret) {
+			dev_err(info->dev,
+				"failed to apply mux %d for pin %d\n",
+				pin_func, pin);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static void ltq_pmx_disable(struct pinctrl_dev *pctrldev,
+				unsigned func,
+				unsigned group)
+{
+	/*
+	 * Nothing to do here. However, pinconf_check_ops() requires this
+	 * callback to be defined.
+	 */
+}
+
+static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev,
+				struct pinctrl_gpio_range *range,
+				unsigned pin)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	int mfp = match_mfp(info, pin + (range->id * 32));
+	int pin_func;
+
+	if (mfp < 0) {
+		dev_err(info->dev, "could not find mfp for pin %d\n", pin);
+		return -EINVAL;
+	}
+
+	pin_func = match_mux(&info->mfp[mfp], 0);
+	if (pin_func < 0) {
+		dev_err(info->dev, "No GPIO function on pin%d\n", mfp);
+		return -EINVAL;
+	}
+
+	return info->apply_mux(pctrldev, mfp, pin_func);
+}
+
+static struct pinmux_ops ltq_pmx_ops = {
+	.get_functions_count	= ltq_pmx_func_count,
+	.get_function_name	= ltq_pmx_func_name,
+	.get_function_groups	= ltq_pmx_get_groups,
+	.enable			= ltq_pmx_enable,
+	.disable		= ltq_pmx_disable,
+	.gpio_request_enable	= ltq_pmx_gpio_request_enable,
+};
+
+/*
+ * allow different socs to register with the generic part of the lanti
+ * pinctrl code
+ */
+int ltq_pinctrl_register(struct platform_device *pdev,
+				struct ltq_pinmux_info *info)
+{
+	struct pinctrl_desc *desc;
+
+	if (!info)
+		return -EINVAL;
+	desc = info->desc;
+	desc->pctlops = &ltq_pctrl_ops;
+	desc->pmxops = &ltq_pmx_ops;
+	info->dev = &pdev->dev;
+
+	info->pctrl = pinctrl_register(desc, &pdev->dev, info);
+	if (!info->pctrl) {
+		dev_err(&pdev->dev, "failed to register LTQ pinmux driver\n");
+		return -EINVAL;
+	}
+	platform_set_drvdata(pdev, info);
+	return 0;
+}
diff --git a/drivers/pinctrl/pinctrl-lantiq.h b/drivers/pinctrl/pinctrl-lantiq.h
new file mode 100644
index 0000000..9ccc1a6
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-lantiq.h
@@ -0,0 +1,190 @@
+/*
+ *  linux/drivers/pinctrl/pinctrl-lantiq.h
+ *  based on linux/drivers/pinctrl/pinctrl-pxa3xx.h
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef __PINCTRL_LANTIQ_H
+
+#include <linux/clkdev.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+
+#include "core.h"
+
+#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
+
+#define LTQ_MAX_MUX		4
+#define MFPR_FUNC_MASK		0x3
+
+#define LTQ_PINCONF_PACK(param, arg)		((param) << 16 | (arg))
+#define LTQ_PINCONF_UNPACK_PARAM(conf)		((conf) >> 16)
+#define LTQ_PINCONF_UNPACK_ARG(conf)		((conf) & 0xffff)
+
+enum ltq_pinconf_param {
+	LTQ_PINCONF_PARAM_PULL,
+	LTQ_PINCONF_PARAM_OPEN_DRAIN,
+	LTQ_PINCONF_PARAM_DRIVE_CURRENT,
+	LTQ_PINCONF_PARAM_SLEW_RATE,
+};
+
+struct ltq_cfg_param {
+	const char *property;
+	enum ltq_pinconf_param param;
+};
+
+struct ltq_mfp_pin {
+	const char *name;
+	const unsigned int pin;
+	const unsigned short func[LTQ_MAX_MUX];
+};
+
+struct ltq_pin_group {
+	const char *name;
+	const unsigned mux;
+	const unsigned *pins;
+	const unsigned npins;
+};
+
+struct ltq_pmx_func {
+	const char *name;
+	const char * const *groups;
+	const unsigned num_groups;
+};
+
+struct ltq_pinmux_info {
+	struct device *dev;
+	struct pinctrl_dev *pctrl;
+
+	/* we need to manage up to 5 pad controllers */
+	void __iomem *membase[5];
+
+	/* the descriptor for the subsystem */
+	struct pinctrl_desc *desc;
+
+	/* we expose our pads to the subsystem */
+	struct pinctrl_pin_desc *pads;
+
+	/* the number of pads. this varies between socs */
+	unsigned int num_pads;
+
+	/* these are our multifunction pins */
+	const struct ltq_mfp_pin *mfp;
+	unsigned int num_mfp;
+
+	/* a number of multifunction pins can be grouped together */
+	const struct ltq_pin_group *grps;
+	unsigned int num_grps;
+
+	/* a mapping between function string and id */
+	const struct ltq_pmx_func *funcs;
+	unsigned int num_funcs;
+
+	/* the pinconf options that we are able to read from the DT */
+	const struct ltq_cfg_param *params;
+	unsigned int num_params;
+
+	/* we need 5 clocks max */
+	struct clk *clk[5];
+
+	/* soc specific callback used to apply muxing */
+	int (*apply_mux)(struct pinctrl_dev *pctrldev, int pin, int mux);
+};
+
+enum ltq_pin {
+	GPIO0 = 0,
+	GPIO1,
+	GPIO2,
+	GPIO3,
+	GPIO4,
+	GPIO5,
+	GPIO6,
+	GPIO7,
+	GPIO8,
+	GPIO9,
+	GPIO10, /* 10 */
+	GPIO11,
+	GPIO12,
+	GPIO13,
+	GPIO14,
+	GPIO15,
+	GPIO16,
+	GPIO17,
+	GPIO18,
+	GPIO19,
+	GPIO20, /* 20 */
+	GPIO21,
+	GPIO22,
+	GPIO23,
+	GPIO24,
+	GPIO25,
+	GPIO26,
+	GPIO27,
+	GPIO28,
+	GPIO29,
+	GPIO30, /* 30 */
+	GPIO31,
+	GPIO32,
+	GPIO33,
+	GPIO34,
+	GPIO35,
+	GPIO36,
+	GPIO37,
+	GPIO38,
+	GPIO39,
+	GPIO40, /* 40 */
+	GPIO41,
+	GPIO42,
+	GPIO43,
+	GPIO44,
+	GPIO45,
+	GPIO46,
+	GPIO47,
+	GPIO48,
+	GPIO49,
+	GPIO50, /* 50 */
+	GPIO51,
+	GPIO52,
+	GPIO53,
+	GPIO54,
+	GPIO55,
+
+	GPIO64,
+	GPIO65,
+	GPIO66,
+	GPIO67,
+	GPIO68,
+	GPIO69,
+	GPIO70,
+	GPIO71,
+	GPIO72,
+	GPIO73,
+	GPIO74,
+	GPIO75,
+	GPIO76,
+	GPIO77,
+	GPIO78,
+	GPIO79,
+	GPIO80,
+	GPIO81,
+	GPIO82,
+	GPIO83,
+	GPIO84,
+	GPIO85,
+	GPIO86,
+	GPIO87,
+	GPIO88,
+};
+
+extern int ltq_pinctrl_register(struct platform_device *pdev,
+				   struct ltq_pinmux_info *info);
+extern int ltq_pinctrl_unregister(struct platform_device *pdev);
+#endif	/* __PINCTRL_PXA3XX_H */
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
new file mode 100644
index 0000000..6049379
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -0,0 +1,657 @@
+/*
+ *  linux/drivers/pinctrl/pinmux-xway.c
+ *  based on linux/drivers/pinctrl/pinmux-pxa910.c
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-lantiq.h"
+
+#include <lantiq_soc.h>
+
+/* we have 3 1/2 banks of 16 bit each */
+#define PINS			16
+#define PORT3			3
+#define PORT(x)			(x / PINS)
+#define PORT_PIN(x)		(x % PINS)
+
+/* we have 2 mux bits that can be set for each pin */
+#define MUX_ALT0	0x1
+#define MUX_ALT1	0x2
+
+/*
+ * each bank has this offset apart from the 1/2 bank that is mixed into the
+ * other 3 ranges
+ */
+#define REG_OFF			0x30
+
+/* these are the offsets to our registers */
+#define GPIO_BASE(p)		(REG_OFF * PORT(p))
+#define GPIO_OUT(p)		GPIO_BASE(p)
+#define GPIO_IN(p)		(GPIO_BASE(p) + 0x04)
+#define GPIO_DIR(p)		(GPIO_BASE(p) + 0x08)
+#define GPIO_ALT0(p)		(GPIO_BASE(p) + 0x0C)
+#define GPIO_ALT1(p)		(GPIO_BASE(p) + 0x10)
+#define GPIO_OD(p)		(GPIO_BASE(p) + 0x14)
+#define GPIO_PUDSEL(p)		(GPIO_BASE(p) + 0x1c)
+#define GPIO_PUDEN(p)		(GPIO_BASE(p) + 0x20)
+
+/* the 1/2 port needs special offsets for some registers */
+#define GPIO3_OD		(GPIO_BASE(0) + 0x24)
+#define GPIO3_PUDSEL		(GPIO_BASE(0) + 0x28)
+#define GPIO3_PUDEN		(GPIO_BASE(0) + 0x2C)
+#define GPIO3_ALT1		(GPIO_BASE(PINS) + 0x24)
+
+/* macros to help us access the registers */
+#define gpio_getbit(m, r, p)	(!!(ltq_r32(m + r) & BIT(p)))
+#define gpio_setbit(m, r, p)	ltq_w32_mask(0, BIT(p), m + r)
+#define gpio_clearbit(m, r, p)	ltq_w32_mask(BIT(p), 0, m + r)
+
+#define MFP_XWAY(a, f0, f1, f2, f3)	\
+	{				\
+		.name = #a,		\
+		.pin = a,		\
+		.func = {		\
+			XWAY_MUX_##f0,	\
+			XWAY_MUX_##f1,	\
+			XWAY_MUX_##f2,	\
+			XWAY_MUX_##f3,	\
+		},			\
+	}
+
+#define GRP_MUX(a, m, p)		\
+	{ .name = a, .mux = XWAY_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
+
+#define FUNC_MUX(f, m)		\
+	{ .func = f, .mux = XWAY_MUX_##m, }
+
+#define XWAY_MAX_PIN		32
+#define XR9_MAX_PIN		56
+
+enum xway_mux {
+	XWAY_MUX_GPIO = 0,
+	XWAY_MUX_SPI,
+	XWAY_MUX_ASC,
+	XWAY_MUX_PCI,
+	XWAY_MUX_CGU,
+	XWAY_MUX_EBU,
+	XWAY_MUX_JTAG,
+	XWAY_MUX_EXIN,
+	XWAY_MUX_TDM,
+	XWAY_MUX_STP,
+	XWAY_MUX_SIN,
+	XWAY_MUX_GPT,
+	XWAY_MUX_NMI,
+	XWAY_MUX_MDIO,
+	XWAY_MUX_NONE = 0xffff,
+};
+
+static const struct ltq_mfp_pin xway_mfp[] = {
+	/*       pin    f0	f1	f2	f3   */
+	MFP_XWAY(GPIO0, GPIO,	EXIN,	NONE,	TDM),
+	MFP_XWAY(GPIO1, GPIO,	EXIN,	NONE,	NONE),
+	MFP_XWAY(GPIO2, GPIO,	CGU,	EXIN,	NONE),
+	MFP_XWAY(GPIO3, GPIO,	CGU,	NONE,	PCI),
+	MFP_XWAY(GPIO4, GPIO,	STP,	NONE,	ASC),
+	MFP_XWAY(GPIO5, GPIO,	STP,	NONE,	NONE),
+	MFP_XWAY(GPIO6, GPIO,	STP,	GPT,	ASC),
+	MFP_XWAY(GPIO7, GPIO,	CGU,	PCI,	NONE),
+	MFP_XWAY(GPIO8, GPIO,	CGU,	NMI,	NONE),
+	MFP_XWAY(GPIO9, GPIO,	ASC,	SPI,	NONE),
+	MFP_XWAY(GPIO10, GPIO,	ASC,	SPI,	NONE),
+	MFP_XWAY(GPIO11, GPIO,	ASC,	PCI,	SPI),
+	MFP_XWAY(GPIO12, GPIO,	ASC,	NONE,	NONE),
+	MFP_XWAY(GPIO13, GPIO,	EBU,	SPI,	NONE),
+	MFP_XWAY(GPIO14, GPIO,	CGU,	PCI,	NONE),
+	MFP_XWAY(GPIO15, GPIO,	SPI,	JTAG,	NONE),
+	MFP_XWAY(GPIO16, GPIO,	SPI,	NONE,	JTAG),
+	MFP_XWAY(GPIO17, GPIO,	SPI,	NONE,	JTAG),
+	MFP_XWAY(GPIO18, GPIO,	SPI,	NONE,	JTAG),
+	MFP_XWAY(GPIO19, GPIO,	PCI,	NONE,	NONE),
+	MFP_XWAY(GPIO20, GPIO,	JTAG,	NONE,	NONE),
+	MFP_XWAY(GPIO21, GPIO,	PCI,	EBU,	GPT),
+	MFP_XWAY(GPIO22, GPIO,	SPI,	NONE,	NONE),
+	MFP_XWAY(GPIO23, GPIO,	EBU,	PCI,	STP),
+	MFP_XWAY(GPIO24, GPIO,	EBU,	TDM,	PCI),
+	MFP_XWAY(GPIO25, GPIO,	TDM,	NONE,	ASC),
+	MFP_XWAY(GPIO26, GPIO,	EBU,	NONE,	TDM),
+	MFP_XWAY(GPIO27, GPIO,	TDM,	NONE,	ASC),
+	MFP_XWAY(GPIO28, GPIO,	GPT,	NONE,	NONE),
+	MFP_XWAY(GPIO29, GPIO,	PCI,	NONE,	NONE),
+	MFP_XWAY(GPIO30, GPIO,	PCI,	NONE,	NONE),
+	MFP_XWAY(GPIO31, GPIO,	EBU,	PCI,	NONE),
+	MFP_XWAY(GPIO32, GPIO,	NONE,	NONE,	EBU),
+	MFP_XWAY(GPIO33, GPIO,	NONE,	NONE,	EBU),
+	MFP_XWAY(GPIO34, GPIO,	NONE,	NONE,	EBU),
+	MFP_XWAY(GPIO35, GPIO,	NONE,	NONE,	EBU),
+	MFP_XWAY(GPIO36, GPIO,	SIN,	NONE,	EBU),
+	MFP_XWAY(GPIO37, GPIO,	PCI,	NONE,	NONE),
+	MFP_XWAY(GPIO38, GPIO,	PCI,	NONE,	NONE),
+	MFP_XWAY(GPIO39, GPIO,	EXIN,	NONE,	NONE),
+	MFP_XWAY(GPIO40, GPIO,	NONE,	NONE,	NONE),
+	MFP_XWAY(GPIO41, GPIO,	NONE,	NONE,	NONE),
+	MFP_XWAY(GPIO42, GPIO,	MDIO,	NONE,	NONE),
+	MFP_XWAY(GPIO43, GPIO,	MDIO,	NONE,	NONE),
+	MFP_XWAY(GPIO44, GPIO,	NONE,	NONE,	SIN),
+	MFP_XWAY(GPIO45, GPIO,	NONE,	NONE,	SIN),
+	MFP_XWAY(GPIO46, GPIO,	NONE,	NONE,	EXIN),
+	MFP_XWAY(GPIO47, GPIO,	NONE,	NONE,	SIN),
+	MFP_XWAY(GPIO48, GPIO,	EBU,	NONE,	NONE),
+	MFP_XWAY(GPIO49, GPIO,	EBU,	NONE,	NONE),
+	MFP_XWAY(GPIO50, GPIO,	NONE,	NONE,	NONE),
+	MFP_XWAY(GPIO51, GPIO,	NONE,	NONE,	NONE),
+	MFP_XWAY(GPIO52, GPIO,	NONE,	NONE,	NONE),
+	MFP_XWAY(GPIO53, GPIO,	NONE,	NONE,	NONE),
+	MFP_XWAY(GPIO54, GPIO,	NONE,	NONE,	NONE),
+	MFP_XWAY(GPIO55, GPIO,	NONE,	NONE,	NONE),
+};
+
+static const unsigned pins_jtag[] = {GPIO15, GPIO16, GPIO17, GPIO19, GPIO35};
+static const unsigned pins_asc0[] = {GPIO11, GPIO12};
+static const unsigned pins_asc0_cts_rts[] = {GPIO9, GPIO10};
+static const unsigned pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned pins_nmi[] = {GPIO8};
+static const unsigned pins_mdio[] = {GPIO42, GPIO43};
+
+static const unsigned pins_ebu_a24[] = {GPIO13};
+static const unsigned pins_ebu_clk[] = {GPIO21};
+static const unsigned pins_ebu_cs1[] = {GPIO23};
+static const unsigned pins_ebu_a23[] = {GPIO24};
+static const unsigned pins_ebu_wait[] = {GPIO26};
+static const unsigned pins_ebu_a25[] = {GPIO31};
+static const unsigned pins_ebu_rdy[] = {GPIO48};
+static const unsigned pins_ebu_rd[] = {GPIO49};
+
+static const unsigned pins_nand_ale[] = {GPIO13};
+static const unsigned pins_nand_cs1[] = {GPIO23};
+static const unsigned pins_nand_cle[] = {GPIO24};
+static const unsigned pins_nand_rdy[] = {GPIO48};
+static const unsigned pins_nand_rd[] = {GPIO49};
+
+static const unsigned pins_exin0[] = {GPIO0};
+static const unsigned pins_exin1[] = {GPIO1};
+static const unsigned pins_exin2[] = {GPIO2};
+static const unsigned pins_exin3[] = {GPIO39};
+static const unsigned pins_exin4[] = {GPIO46};
+
+static const unsigned pins_spi[] = {GPIO16, GPIO17, GPIO18};
+static const unsigned pins_spi_cs1[] = {GPIO15};
+static const unsigned pins_spi_cs2[] = {GPIO21};
+static const unsigned pins_spi_cs3[] = {GPIO13};
+static const unsigned pins_spi_cs4[] = {GPIO10};
+static const unsigned pins_spi_cs5[] = {GPIO9};
+static const unsigned pins_spi_cs6[] = {GPIO11};
+
+static const unsigned pins_gpt1[] = {GPIO28};
+static const unsigned pins_gpt2[] = {GPIO21};
+static const unsigned pins_gpt3[] = {GPIO6};
+
+static const unsigned pins_clkout0[] = {GPIO8};
+static const unsigned pins_clkout1[] = {GPIO7};
+static const unsigned pins_clkout2[] = {GPIO3};
+static const unsigned pins_clkout3[] = {GPIO2};
+
+static const unsigned pins_pci_gnt1[] = {GPIO30};
+static const unsigned pins_pci_gnt2[] = {GPIO23};
+static const unsigned pins_pci_gnt3[] = {GPIO19};
+static const unsigned pins_pci_gnt4[] = {GPIO38};
+static const unsigned pins_pci_req1[] = {GPIO29};
+static const unsigned pins_pci_req2[] = {GPIO31};
+static const unsigned pins_pci_req3[] = {GPIO3};
+static const unsigned pins_pci_req4[] = {GPIO37};
+
+static const struct ltq_pin_group xway_grps[] = {
+	GRP_MUX("exin0", EXIN, pins_exin0),
+	GRP_MUX("exin1", EXIN, pins_exin1),
+	GRP_MUX("exin2", EXIN, pins_exin2),
+	GRP_MUX("jtag", JTAG, pins_jtag),
+	GRP_MUX("ebu a23", EBU, pins_ebu_a23),
+	GRP_MUX("ebu a24", EBU, pins_ebu_a24),
+	GRP_MUX("ebu a25", EBU, pins_ebu_a25),
+	GRP_MUX("ebu clk", EBU, pins_ebu_clk),
+	GRP_MUX("ebu cs1", EBU, pins_ebu_cs1),
+	GRP_MUX("ebu wait", EBU, pins_ebu_wait),
+	GRP_MUX("nand ale", EBU, pins_nand_ale),
+	GRP_MUX("nand cs1", EBU, pins_nand_cs1),
+	GRP_MUX("nand cle", EBU, pins_nand_cle),
+	GRP_MUX("spi", SPI, pins_spi),
+	GRP_MUX("spi_cs1", SPI, pins_spi_cs1),
+	GRP_MUX("spi_cs2", SPI, pins_spi_cs2),
+	GRP_MUX("spi_cs3", SPI, pins_spi_cs3),
+	GRP_MUX("spi_cs4", SPI, pins_spi_cs4),
+	GRP_MUX("spi_cs5", SPI, pins_spi_cs5),
+	GRP_MUX("spi_cs6", SPI, pins_spi_cs6),
+	GRP_MUX("asc0", ASC, pins_asc0),
+	GRP_MUX("asc0 cts rts", ASC, pins_asc0_cts_rts),
+	GRP_MUX("stp", STP, pins_stp),
+	GRP_MUX("nmi", NMI, pins_nmi),
+	GRP_MUX("gpt1", GPT, pins_gpt1),
+	GRP_MUX("gpt2", GPT, pins_gpt2),
+	GRP_MUX("gpt3", GPT, pins_gpt3),
+	GRP_MUX("clkout0", CGU, pins_clkout0),
+	GRP_MUX("clkout1", CGU, pins_clkout1),
+	GRP_MUX("clkout2", CGU, pins_clkout2),
+	GRP_MUX("clkout3", CGU, pins_clkout3),
+	GRP_MUX("gnt1", PCI, pins_pci_gnt1),
+	GRP_MUX("gnt2", PCI, pins_pci_gnt2),
+	GRP_MUX("gnt3", PCI, pins_pci_gnt3),
+	GRP_MUX("req1", PCI, pins_pci_req1),
+	GRP_MUX("req2", PCI, pins_pci_req2),
+	GRP_MUX("req3", PCI, pins_pci_req3),
+/* xrx only */
+	GRP_MUX("nand rdy", EBU, pins_nand_rdy),
+	GRP_MUX("nand rd", EBU, pins_nand_rd),
+	GRP_MUX("exin3", EXIN, pins_exin3),
+	GRP_MUX("exin4", EXIN, pins_exin4),
+	GRP_MUX("gnt4", PCI, pins_pci_gnt4),
+	GRP_MUX("req4", PCI, pins_pci_gnt4),
+	GRP_MUX("mdio", MDIO, pins_mdio),
+};
+
+static const char * const xway_pci_grps[] = {"gnt1", "gnt2",
+						"gnt3", "req1",
+						"req2", "req3"};
+static const char * const xway_spi_grps[] = {"spi", "spi_cs1",
+						"spi_cs2", "spi_cs3",
+						"spi_cs4", "spi_cs5",
+						"spi_cs6"};
+static const char * const xway_cgu_grps[] = {"clkout0", "clkout1",
+						"clkout2", "clkout3"};
+static const char * const xway_ebu_grps[] = {"ebu a23", "ebu a24",
+						"ebu a25", "ebu cs1",
+						"ebu wait", "ebu clk",
+						"nand ale", "nand cs1",
+						"nand cle"};
+static const char * const xway_exin_grps[] = {"exin0", "exin1", "exin2"};
+static const char * const xway_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const xway_asc_grps[] = {"asc0", "asc0 cts rts"};
+static const char * const xway_jtag_grps[] = {"jtag"};
+static const char * const xway_stp_grps[] = {"stp"};
+static const char * const xway_nmi_grps[] = {"nmi"};
+
+/* ar9/vr9/gr9 */
+static const char * const xrx_mdio_grps[] = {"mdio"};
+static const char * const xrx_ebu_grps[] = {"ebu a23", "ebu a24",
+						"ebu a25", "ebu cs1",
+						"ebu wait", "ebu clk",
+						"nand ale", "nand cs1",
+						"nand cle", "nand rdy",
+						"nand rd"};
+static const char * const xrx_exin_grps[] = {"exin0", "exin1", "exin2",
+						"exin3", "exin4"};
+static const char * const xrx_pci_grps[] = {"gnt1", "gnt2",
+						"gnt3", "gnt4",
+						"req1", "req2",
+						"req3", "req4"};
+
+static const struct ltq_pmx_func danube_funcs[] = {
+	{"spi",		ARRAY_AND_SIZE(xway_spi_grps)},
+	{"asc",		ARRAY_AND_SIZE(xway_asc_grps)},
+	{"cgu",		ARRAY_AND_SIZE(xway_cgu_grps)},
+	{"jtag",	ARRAY_AND_SIZE(xway_jtag_grps)},
+	{"exin",	ARRAY_AND_SIZE(xway_exin_grps)},
+	{"stp",		ARRAY_AND_SIZE(xway_stp_grps)},
+	{"gpt",		ARRAY_AND_SIZE(xway_gpt_grps)},
+	{"nmi",		ARRAY_AND_SIZE(xway_nmi_grps)},
+	{"pci",		ARRAY_AND_SIZE(xway_pci_grps)},
+	{"ebu",		ARRAY_AND_SIZE(xway_ebu_grps)},
+};
+
+static const struct ltq_pmx_func xrx_funcs[] = {
+	{"spi",		ARRAY_AND_SIZE(xway_spi_grps)},
+	{"asc",		ARRAY_AND_SIZE(xway_asc_grps)},
+	{"cgu",		ARRAY_AND_SIZE(xway_cgu_grps)},
+	{"jtag",	ARRAY_AND_SIZE(xway_jtag_grps)},
+	{"exin",	ARRAY_AND_SIZE(xrx_exin_grps)},
+	{"stp",		ARRAY_AND_SIZE(xway_stp_grps)},
+	{"gpt",		ARRAY_AND_SIZE(xway_gpt_grps)},
+	{"nmi",		ARRAY_AND_SIZE(xway_nmi_grps)},
+	{"pci",		ARRAY_AND_SIZE(xrx_pci_grps)},
+	{"ebu",		ARRAY_AND_SIZE(xrx_ebu_grps)},
+	{"mdio",		ARRAY_AND_SIZE(xrx_mdio_grps)},
+};
+
+/* ---------  pinconf related code --------- */
+static int xway_pinconf_get(struct pinctrl_dev *pctldev,
+				unsigned pin,
+				unsigned long *config)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
+	enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(*config);
+	int port = PORT(pin);
+	u32 reg;
+
+	switch (param) {
+	case LTQ_PINCONF_PARAM_OPEN_DRAIN:
+		if (port == PORT3)
+			reg = GPIO3_OD;
+		else
+			reg = GPIO_OD(port);
+		*config = LTQ_PINCONF_PACK(param,
+			!!gpio_getbit(info->membase[0], reg, PORT_PIN(port)));
+		break;
+
+	case LTQ_PINCONF_PARAM_PULL:
+		if (port == PORT3)
+			reg = GPIO3_PUDEN;
+		else
+			reg = GPIO_PUDEN(port);
+		if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port))) {
+			*config = LTQ_PINCONF_PACK(param, 0);
+			break;
+		}
+
+		if (port == PORT3)
+			reg = GPIO3_PUDSEL;
+		else
+			reg = GPIO_PUDSEL(port);
+		if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port)))
+			*config = LTQ_PINCONF_PACK(param, 2);
+		else
+			*config = LTQ_PINCONF_PACK(param, 1);
+		break;
+
+	default:
+		dev_err(pctldev->dev, "Invalid config param %04x\n", param);
+		return -ENOTSUPP;
+	}
+	return 0;
+}
+
+static int xway_pinconf_set(struct pinctrl_dev *pctldev,
+				unsigned pin,
+				unsigned long config)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
+	enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config);
+	int arg = LTQ_PINCONF_UNPACK_ARG(config);
+	int port = PORT(pin);
+	u32 reg;
+
+	switch (param) {
+	case LTQ_PINCONF_PARAM_OPEN_DRAIN:
+		if (port == PORT3)
+			reg = GPIO3_OD;
+		else
+			reg = GPIO_OD(port);
+		gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+		break;
+
+	case LTQ_PINCONF_PARAM_PULL:
+		if (port == PORT3)
+			reg = GPIO3_PUDEN;
+		else
+			reg = GPIO_PUDEN(port);
+		if (arg == 0) {
+			gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
+			break;
+		}
+		gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+
+		if (port == PORT3)
+			reg = GPIO3_PUDSEL;
+		else
+			reg = GPIO_PUDSEL(port);
+		if (arg == 1)
+			gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
+		else if (arg == 2)
+			gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+		else
+			dev_err(pctldev->dev, "Invalid pull value %d\n", arg);
+		break;
+
+	default:
+		dev_err(pctldev->dev, "Invalid config param %04x\n", param);
+		return -ENOTSUPP;
+	}
+	return 0;
+}
+
+struct pinconf_ops xway_pinconf_ops = {
+	.pin_config_get	= xway_pinconf_get,
+	.pin_config_set	= xway_pinconf_set,
+};
+
+static struct pinctrl_desc xway_pctrl_desc = {
+	.owner		= THIS_MODULE,
+	.confops	= &xway_pinconf_ops,
+};
+
+static inline int xway_mux_apply(struct pinctrl_dev *pctrldev,
+				int pin, int mux)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	int port = PORT(pin);
+	u32 alt1_reg = GPIO_ALT1(pin);
+
+	if (port == PORT3)
+		alt1_reg = GPIO3_ALT1;
+
+	if (mux & MUX_ALT0)
+		gpio_setbit(info->membase[0], GPIO_ALT0(pin), PORT_PIN(pin));
+	else
+		gpio_clearbit(info->membase[0], GPIO_ALT0(pin), PORT_PIN(pin));
+
+	if (mux & MUX_ALT1)
+		gpio_setbit(info->membase[0], alt1_reg, PORT_PIN(pin));
+	else
+		gpio_clearbit(info->membase[0], alt1_reg, PORT_PIN(pin));
+
+	return 0;
+}
+
+static const struct ltq_cfg_param xway_cfg_params[] = {
+	{"lantiq,pull",		LTQ_PINCONF_PARAM_PULL},
+	{"lantiq,open-drain",	LTQ_PINCONF_PARAM_OPEN_DRAIN},
+};
+
+static struct ltq_pinmux_info xway_info = {
+	.mfp		= xway_mfp,
+	.desc		= &xway_pctrl_desc,
+	.apply_mux	= xway_mux_apply,
+	.params		= xway_cfg_params,
+	.num_params	= ARRAY_SIZE(xway_cfg_params),
+};
+
+/* ---------  gpio_chip related code --------- */
+static void xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
+{
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+
+	if (val)
+		gpio_setbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin));
+	else
+		gpio_clearbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin));
+}
+
+static int xway_gpio_get(struct gpio_chip *chip, unsigned int pin)
+{
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+
+	return gpio_getbit(info->membase[0], GPIO_IN(pin), PORT_PIN(pin));
+}
+
+static int xway_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
+{
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+
+	gpio_clearbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
+
+	return 0;
+}
+
+static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val)
+{
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+
+	gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
+	xway_gpio_set(chip, pin, val);
+
+	return 0;
+}
+
+static int xway_gpio_req(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	return pinctrl_request_gpio(gpio);
+}
+
+static void xway_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	pinctrl_free_gpio(gpio);
+}
+
+static struct gpio_chip xway_chip = {
+	.label = "gpio-xway",
+	.direction_input = xway_gpio_dir_in,
+	.direction_output = xway_gpio_dir_out,
+	.get = xway_gpio_get,
+	.set = xway_gpio_set,
+	.request = xway_gpio_req,
+	.free = xway_gpio_free,
+	.base = -1,
+};
+
+/* --------- register the pinctrl layer --------- */
+static struct pinctrl_xway_soc {
+	int pin_count;
+	const struct ltq_pmx_func *funcs;
+	unsigned int num_funcs;
+} soc_cfg[] = {
+	/* legacy xway */
+	{XWAY_MAX_PIN, danube_funcs, ARRAY_SIZE(danube_funcs)},
+	/* xway xr9 series */
+	{XR9_MAX_PIN, xrx_funcs, ARRAY_SIZE(xrx_funcs)},
+};
+
+static struct pinctrl_gpio_range xway_gpio_range = {
+	.name	= "XWAY GPIO",
+	.gc	= &xway_chip,
+};
+
+static const struct of_device_id xway_match[] = {
+	{ .compatible = "lantiq,pinctrl-xway", .data = &soc_cfg[0]},
+	{ .compatible = "lantiq,pinctrl-xr9", .data = &soc_cfg[1]},
+	{},
+};
+MODULE_DEVICE_TABLE(of, xway_match);
+
+static int __devinit pinmux_xway_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	const struct pinctrl_xway_soc *xway_soc;
+	struct resource *res;
+	int ret, i;
+
+	/* get and remap our register range */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource\n");
+		return -ENOENT;
+	}
+	xway_info.membase[0] = devm_request_and_ioremap(&pdev->dev, res);
+	if (!xway_info.membase[0]) {
+		dev_err(&pdev->dev, "Failed to remap resource\n");
+		return -ENOMEM;
+	}
+
+	match = of_match_device(xway_match, &pdev->dev);
+	if (match)
+		xway_soc = (const struct pinctrl_xway_soc *) match->data;
+	else
+		xway_soc = &soc_cfg[0];
+
+	/* find out how many pads we have */
+	xway_chip.ngpio = xway_soc->pin_count;
+
+	/* load our pad descriptors */
+	xway_info.pads = devm_kzalloc(&pdev->dev,
+			sizeof(struct pinctrl_pin_desc) * xway_chip.ngpio,
+			GFP_KERNEL);
+	if (!xway_info.pads) {
+		dev_err(&pdev->dev, "Failed to allocate pads\n");
+		return -ENOMEM;
+	}
+	for (i = 0; i < xway_chip.ngpio; i++) {
+		/* strlen("ioXY") + 1 = 5 */
+		char *name = devm_kzalloc(&pdev->dev, 5, GFP_KERNEL);
+
+		if (!name) {
+			dev_err(&pdev->dev, "Failed to allocate pad name\n");
+			return -ENOMEM;
+		}
+		snprintf(name, 5, "io%d", i);
+		xway_info.pads[i].number = GPIO0 + i;
+		xway_info.pads[i].name = name;
+	}
+	xway_pctrl_desc.pins = xway_info.pads;
+
+	/* load the gpio chip */
+	xway_chip.dev = &pdev->dev;
+	of_gpiochip_add(&xway_chip);
+	ret = gpiochip_add(&xway_chip);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register gpio chip\n");
+		return ret;
+	}
+
+	/* setup the data needed by pinctrl */
+	xway_pctrl_desc.name	= dev_name(&pdev->dev);
+	xway_pctrl_desc.npins	= xway_chip.ngpio;
+
+	xway_info.num_pads	= xway_chip.ngpio;
+	xway_info.num_mfp	= xway_chip.ngpio;
+	xway_info.grps		= xway_grps;
+	xway_info.num_grps	= ARRAY_SIZE(xway_grps);
+	xway_info.funcs		= xway_soc->funcs;
+	xway_info.num_funcs	= xway_soc->num_funcs;
+
+	/* register with the generic lantiq layer */
+	ret = ltq_pinctrl_register(pdev, &xway_info);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register pinctrl driver\n");
+		return ret;
+	}
+
+	/* finish with registering the gpio range in pinctrl */
+	xway_gpio_range.npins = xway_chip.ngpio;
+	xway_gpio_range.base = xway_chip.base;
+	pinctrl_add_gpio_range(xway_info.pctrl, &xway_gpio_range);
+	dev_info(&pdev->dev, "Init done\n");
+	return 0;
+}
+
+static struct platform_driver pinmux_xway_driver = {
+	.probe	= pinmux_xway_probe,
+	.driver = {
+		.name	= "pinctrl-xway",
+		.owner	= THIS_MODULE,
+		.of_match_table = xway_match,
+	},
+};
+
+static int __init pinmux_xway_init(void)
+{
+	return platform_driver_register(&pinmux_xway_driver);
+}
+
+core_initcall_sync(pinmux_xway_init);
-- 
1.7.9.1


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

* [PATCH 2/6] Document: devicetree: add OF documents for lantiq xway pinctrl
  2012-07-24  6:50 [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support John Crispin
@ 2012-07-24  6:50 ` John Crispin
  2012-07-24  6:50 ` [PATCH 3/6] OF: pinctrl: MIPS: lantiq: adds support for FALCON SoC John Crispin
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: John Crispin @ 2012-07-24  6:50 UTC (permalink / raw)
  To: Grant Likely
  Cc: John Crispin, Linus Walleij, devicetree-discuss, linux-kernel

Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-kernel@vger.kernel.org
---
 .../bindings/pinctrl/lantiq,xway-pinumx.txt        |   97 ++++++++++++++++++++
 1 files changed, 97 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt b/Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt
new file mode 100644
index 0000000..b5469db
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt
@@ -0,0 +1,97 @@
+Lantiq XWAY pinmux controller
+
+Required properties:
+- compatible: "lantiq,pinctrl-xway" or "lantiq,pinctrl-xr9"
+- reg: Should contain the physical address and length of the gpio/pinmux
+  register range
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Lantiq's pin configuration nodes act as a container for an abitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those group(s), and two pin configuration parameters:
+pull-up and open-drain
+
+The name of each subnode is not important as long as it is unique; all subnodes
+should be enumerated and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+We support 2 types of nodes.
+
+Definition of mux function groups:
+
+Required subnode-properties:
+- lantiq,groups : An array of strings. Each string contains the name of a group.
+  Valid values for these names are listed below.
+- lantiq,function: A string containing the name of the function to mux to the
+  group. Valid values for function names are listed below.
+
+Valid values for group and function names:
+
+  mux groups:
+    exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1,
+    ebu wait, nand ale, nand cs1, nand cle, spi, spi_cs1, spi_cs2, spi_cs3,
+    spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi , gpt1, gpt2,
+    gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3, req1, req2,
+    req3
+
+  additional mux groups (XR9 only):
+    mdio, nand rdy, nand rd, exin3, exin4, gnt4, req4
+
+  functions:
+    spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio
+
+
+
+Definition of pin configurations:
+
+Required subnode-properties:
+- lantiq,pins : An array of strings. Each string contains the name of a pin.
+  Valid values for these names are listed below.
+
+Optional subnode-properties:
+- lantiq,pull: Integer, representing the pull-down/up to apply to the pin.
+    0: none, 1: down, 2: up.
+- lantiq,open-drain: Boolean, enables open-drain on the defined pin.
+
+Valid values for XWAY pin names:
+  Pinconf pins can be referenced via the names io0-io31.
+
+Valid values for XR9 pin names:
+  Pinconf pins can be referenced via the names io0-io55.
+
+Example:
+	gpio: pinmux@E100B10 {
+		compatible = "lantiq,pinctrl-xway";
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0xE100B10 0xA0>;
+
+		state_default: pinmux {
+			stp {
+				lantiq,groups = "stp";
+				lantiq,function = "stp";
+			};
+			pci {
+				lantiq,groups = "gnt1";
+				lantiq,function = "pci";
+			};
+			conf_out {
+				lantiq,pins = "io4", "io5", "io6"; /* stp */
+				lantiq,open-drain;
+				lantiq,pull = <0>;
+			};
+		};
+	};
+
-- 
1.7.9.1


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

* [PATCH 3/6] OF: pinctrl: MIPS: lantiq: adds support for FALCON SoC
  2012-07-24  6:50 [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support John Crispin
  2012-07-24  6:50 ` [PATCH 2/6] Document: devicetree: add OF documents for lantiq xway pinctrl John Crispin
@ 2012-07-24  6:50 ` John Crispin
  2012-07-27 23:23   ` Linus Walleij
  2012-07-24  6:50 ` [PATCH 4/6] Document: devicetree: add OF documents for lantiq falcon pinctrl John Crispin
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: John Crispin @ 2012-07-24  6:50 UTC (permalink / raw)
  To: Grant Likely
  Cc: John Crispin, Thomas Langer, Linus Walleij, devicetree-discuss,
	linux-kernel

Implement support for pinctrl on lantiq/falcon socs. The FALCON has 5 banks
of up to 32 pins.

Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-kernel@vger.kernel.org
---
 .../include/asm/mach-lantiq/falcon/lantiq_soc.h    |    4 +
 arch/mips/lantiq/Kconfig                           |    1 +
 drivers/pinctrl/Kconfig                            |    5 +
 drivers/pinctrl/Makefile                           |    1 +
 drivers/pinctrl/pinctrl-falcon.c                   |  468 ++++++++++++++++++++
 5 files changed, 479 insertions(+), 0 deletions(-)
 create mode 100644 drivers/pinctrl/pinctrl-falcon.c

diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
index b385252..fccac35 100644
--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
@@ -57,6 +57,10 @@ extern __iomem void *ltq_sys1_membase;
 #define ltq_sys1_w32_mask(clear, set, reg)   \
 	ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg)
 
+/* allow the gpio and pinctrl drivers to talk to eachother */
+extern int pinctrl_falcon_get_range_size(int id);
+extern void pinctrl_falcon_add_gpio_range(struct pinctrl_gpio_range *range);
+
 /*
  * to keep the irq code generic we need to define this to 0 as falcon
  * has no EIU/EBU
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
index 080c013..d84f361 100644
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -20,6 +20,7 @@ config SOC_XWAY
 
 config SOC_FALCON
 	bool "FALCON"
+	select PINCTRL_FALCON
 
 endchoice
 
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index f77dce0..45d2158 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -65,6 +65,11 @@ config PINCTRL_PXA3xx
 	bool
 	select PINMUX
 
+config PINCTRL_FALCON
+	bool
+	depends on SOC_FALCON
+	depends on PINCTRL_LANTIQ
+
 config PINCTRL_MMP2
 	bool "MMP2 pin controller driver"
 	depends on ARCH_MMP
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index e19e207..c0566c8 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_PINCTRL_IMX51)	+= pinctrl-imx51.o
 obj-$(CONFIG_PINCTRL_IMX53)	+= pinctrl-imx53.o
 obj-$(CONFIG_PINCTRL_IMX6Q)	+= pinctrl-imx6q.o
 obj-$(CONFIG_PINCTRL_PXA3xx)	+= pinctrl-pxa3xx.o
+obj-$(CONFIG_PINCTRL_FALCON)	+= pinctrl-falcon.o
 obj-$(CONFIG_PINCTRL_MMP2)	+= pinctrl-mmp2.o
 obj-$(CONFIG_PINCTRL_MXS)	+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)	+= pinctrl-imx23.o
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
new file mode 100644
index 0000000..ee73059
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -0,0 +1,468 @@
+/*
+ *  linux/drivers/pinctrl/pinmux-falcon.c
+ *  based on linux/drivers/pinctrl/pinmux-pxa910.c
+ *
+ *  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.
+ *
+ *  Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-lantiq.h"
+
+#include <lantiq_soc.h>
+
+/* Multiplexer Control Register */
+#define LTQ_PADC_MUX(x)         (x * 0x4)
+/* Pull Up Enable Register */
+#define LTQ_PADC_PUEN		0x80
+/* Pull Down Enable Register */
+#define LTQ_PADC_PDEN		0x84
+/* Slew Rate Control Register */
+#define LTQ_PADC_SRC		0x88
+/* Drive Current Control Register */
+#define LTQ_PADC_DCC		0x8C
+/* Pad Control Availability Register */
+#define LTQ_PADC_AVAIL          0xF0
+
+#define pad_r32(p, reg)		ltq_r32(p + reg)
+#define pad_w32(p, val, reg)	ltq_w32(val, p + reg)
+#define pad_w32_mask(c, clear, set, reg) \
+		pad_w32(c, (pad_r32(c, reg) & ~(clear)) | (set), reg)
+
+#define pad_getbit(m, r, p)	(!!(ltq_r32(m + r) & (1 << p)))
+
+#define PORTS			5
+#define PINS			32
+#define PORT(x)                 (x / PINS)
+#define PORT_PIN(x)             (x % PINS)
+
+#define MFP_FALCON(a, f0, f1, f2, f3)		\
+{						\
+	.name = #a,				\
+	.pin = a,				\
+	.func = {				\
+		FALCON_MUX_##f0,		\
+		FALCON_MUX_##f1,		\
+		FALCON_MUX_##f2,		\
+		FALCON_MUX_##f3,		\
+	},					\
+}
+
+#define GRP_MUX(a, m, p)	\
+{				\
+	.name = a,		\
+	.mux = FALCON_MUX_##m,	\
+	.pins = p,		\
+	.npins = ARRAY_SIZE(p),	\
+}
+
+enum falcon_mux {
+	FALCON_MUX_GPIO = 0,
+	FALCON_MUX_RST,
+	FALCON_MUX_NTR,
+	FALCON_MUX_MDIO,
+	FALCON_MUX_LED,
+	FALCON_MUX_SPI,
+	FALCON_MUX_ASC,
+	FALCON_MUX_I2C,
+	FALCON_MUX_HOSTIF,
+	FALCON_MUX_SLIC,
+	FALCON_MUX_JTAG,
+	FALCON_MUX_PCM,
+	FALCON_MUX_MII,
+	FALCON_MUX_PHY,
+	FALCON_MUX_NONE = 0xffff,
+};
+
+static struct pinctrl_pin_desc falcon_pads[PORTS * PINS];
+static int pad_count[PORTS];
+
+static void lantiq_load_pin_desc(struct pinctrl_pin_desc *d, int bank, int len)
+{
+	int base = bank * PINS;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		/* strlen("ioXYZ") + 1 = 6 */
+		char *name = kzalloc(6, GFP_KERNEL);
+		snprintf(name, 6, "io%d", base + i);
+		d[i].number = base + i;
+		d[i].name = name;
+	}
+	pad_count[bank] = len;
+}
+
+static struct ltq_mfp_pin falcon_mfp[] = {
+	/*	pin		f0	f1	f2	f3 */
+	MFP_FALCON(GPIO0,	RST,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO1,	GPIO,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO2,	GPIO,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO3,	GPIO,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO4,	NTR,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO5,	NTR,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO6,	RST,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO7,	MDIO,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO8,	MDIO,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO9,	LED,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO10,	LED,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO11,	LED,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO12,	LED,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO13,	LED,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO14,	LED,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO32,	ASC,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO33,	ASC,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO34,	SPI,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO35,	SPI,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO36,	SPI,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO37,	SPI,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO38,	SPI,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO39,	I2C,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO40,	I2C,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO41,	HOSTIF,	GPIO,	HOSTIF,	JTAG),
+	MFP_FALCON(GPIO42,	HOSTIF,	GPIO,	HOSTIF,	NONE),
+	MFP_FALCON(GPIO43,	SLIC,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO44,	SLIC,	GPIO,	PCM,	ASC),
+	MFP_FALCON(GPIO45,	SLIC,	GPIO,	PCM,	ASC),
+	MFP_FALCON(GPIO64,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO65,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO66,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO67,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO68,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO69,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO70,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO71,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO72,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO73,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO74,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO75,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO76,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO77,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO78,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO79,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO80,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO81,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO82,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO83,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO84,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO85,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO86,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO87,	MII,	GPIO,	NONE,	NONE),
+	MFP_FALCON(GPIO88,	PHY,	GPIO,	NONE,	NONE),
+};
+
+static const unsigned pins_por[] = {GPIO0};
+static const unsigned pins_ntr[] = {GPIO4};
+static const unsigned pins_ntr8k[] = {GPIO5};
+static const unsigned pins_hrst[] = {GPIO6};
+static const unsigned pins_mdio[] = {GPIO7, GPIO8};
+static const unsigned pins_bled[] = {GPIO7, GPIO10, GPIO11,
+					GPIO12, GPIO13, GPIO14};
+static const unsigned pins_asc0[] = {GPIO32, GPIO33};
+static const unsigned pins_spi[] = {GPIO34, GPIO35, GPIO36};
+static const unsigned pins_spi_cs0[] = {GPIO37};
+static const unsigned pins_spi_cs1[] = {GPIO38};
+static const unsigned pins_i2c[] = {GPIO39, GPIO40};
+static const unsigned pins_jtag[] = {GPIO41};
+static const unsigned pins_slic[] = {GPIO43, GPIO44, GPIO45};
+static const unsigned pins_pcm[] = {GPIO44, GPIO45};
+static const unsigned pins_asc1[] = {GPIO44, GPIO45};
+
+static struct ltq_pin_group falcon_grps[] = {
+	GRP_MUX("por", RST, pins_por),
+	GRP_MUX("ntr", NTR, pins_ntr),
+	GRP_MUX("ntr8k", NTR, pins_ntr8k),
+	GRP_MUX("hrst", RST, pins_hrst),
+	GRP_MUX("mdio", MDIO, pins_mdio),
+	GRP_MUX("bootled", LED, pins_bled),
+	GRP_MUX("asc0", ASC, pins_asc0),
+	GRP_MUX("spi", SPI, pins_spi),
+	GRP_MUX("spi cs0", SPI, pins_spi_cs0),
+	GRP_MUX("spi cs1", SPI, pins_spi_cs1),
+	GRP_MUX("i2c", I2C, pins_i2c),
+	GRP_MUX("jtag", JTAG, pins_jtag),
+	GRP_MUX("slic", SLIC, pins_slic),
+	GRP_MUX("pcm", PCM, pins_pcm),
+	GRP_MUX("asc1", ASC, pins_asc1),
+};
+
+static const char * const ltq_rst_grps[] = {"por", "hrst"};
+static const char * const ltq_ntr_grps[] = {"ntr", "ntr8k"};
+static const char * const ltq_mdio_grps[] = {"mdio"};
+static const char * const ltq_bled_grps[] = {"bootled"};
+static const char * const ltq_asc_grps[] = {"asc0", "asc1"};
+static const char * const ltq_spi_grps[] = {"spi", "spi cs0", "spi cs1"};
+static const char * const ltq_i2c_grps[] = {"i2c"};
+static const char * const ltq_jtag_grps[] = {"jtag"};
+static const char * const ltq_slic_grps[] = {"slic"};
+static const char * const ltq_pcm_grps[] = {"pcm"};
+
+static struct ltq_pmx_func falcon_funcs[] = {
+	{"rst",		ARRAY_AND_SIZE(ltq_rst_grps)},
+	{"ntr",		ARRAY_AND_SIZE(ltq_ntr_grps)},
+	{"mdio",	ARRAY_AND_SIZE(ltq_mdio_grps)},
+	{"led",		ARRAY_AND_SIZE(ltq_bled_grps)},
+	{"asc",		ARRAY_AND_SIZE(ltq_asc_grps)},
+	{"spi",		ARRAY_AND_SIZE(ltq_spi_grps)},
+	{"i2c",		ARRAY_AND_SIZE(ltq_i2c_grps)},
+	{"jtag",	ARRAY_AND_SIZE(ltq_jtag_grps)},
+	{"slic",	ARRAY_AND_SIZE(ltq_slic_grps)},
+	{"pcm",		ARRAY_AND_SIZE(ltq_pcm_grps)},
+};
+
+
+
+
+/* ---------  pinconf related code --------- */
+static int falcon_pinconf_group_get(struct pinctrl_dev *pctrldev,
+				unsigned group, unsigned long *config)
+{
+	return -ENOTSUPP;
+}
+
+static int falcon_pinconf_group_set(struct pinctrl_dev *pctrldev,
+				unsigned group, unsigned long config)
+{
+	return -ENOTSUPP;
+}
+
+static int falcon_pinconf_get(struct pinctrl_dev *pctrldev,
+				unsigned pin, unsigned long *config)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(*config);
+	void __iomem *mem = info->membase[PORT(pin)];
+
+	switch (param) {
+	case LTQ_PINCONF_PARAM_DRIVE_CURRENT:
+		*config = LTQ_PINCONF_PACK(param,
+			!!pad_getbit(mem, LTQ_PADC_DCC, PORT_PIN(pin)));
+		break;
+
+	case LTQ_PINCONF_PARAM_SLEW_RATE:
+		*config = LTQ_PINCONF_PACK(param,
+			!!pad_getbit(mem, LTQ_PADC_SRC, PORT_PIN(pin)));
+		break;
+
+	case LTQ_PINCONF_PARAM_PULL:
+		if (pad_getbit(mem, LTQ_PADC_PDEN, PORT_PIN(pin)))
+			*config = LTQ_PINCONF_PACK(param, 1);
+		else if (pad_getbit(mem, LTQ_PADC_PUEN, PORT_PIN(pin)))
+			*config = LTQ_PINCONF_PACK(param, 2);
+		else
+			*config = LTQ_PINCONF_PACK(param, 0);
+
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int falcon_pinconf_set(struct pinctrl_dev *pctrldev,
+			unsigned pin, unsigned long config)
+{
+	enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config);
+	int arg = LTQ_PINCONF_UNPACK_ARG(config);
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	void __iomem *mem = info->membase[PORT(pin)];
+	u32 reg;
+
+	switch (param) {
+	case LTQ_PINCONF_PARAM_DRIVE_CURRENT:
+		reg = LTQ_PADC_DCC;
+		break;
+
+	case LTQ_PINCONF_PARAM_SLEW_RATE:
+		reg = LTQ_PADC_SRC;
+		break;
+
+	case LTQ_PINCONF_PARAM_PULL:
+		if (arg == 1)
+			reg = LTQ_PADC_PDEN;
+		else
+			reg = LTQ_PADC_PUEN;
+		break;
+
+	default:
+		pr_err("%s: Invalid config param %04x\n",
+		pinctrl_dev_get_name(pctrldev), param);
+		return -ENOTSUPP;
+	}
+
+	pad_w32(mem, BIT(PORT_PIN(pin)), reg);
+	if (!(pad_r32(mem, reg) & BIT(PORT_PIN(pin))))
+		return -ENOTSUPP;
+	return 0;
+}
+
+static void falcon_pinconf_dbg_show(struct pinctrl_dev *pctrldev,
+			struct seq_file *s, unsigned offset)
+{
+}
+
+static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
+			struct seq_file *s, unsigned selector)
+{
+}
+
+struct pinconf_ops falcon_pinconf_ops = {
+	.pin_config_get			= falcon_pinconf_get,
+	.pin_config_set			= falcon_pinconf_set,
+	.pin_config_group_get		= falcon_pinconf_group_get,
+	.pin_config_group_set		= falcon_pinconf_group_set,
+	.pin_config_dbg_show		= falcon_pinconf_dbg_show,
+	.pin_config_group_dbg_show	= falcon_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc falcon_pctrl_desc = {
+	.owner		= THIS_MODULE,
+	.pins		= falcon_pads,
+	.confops	= &falcon_pinconf_ops,
+};
+
+static inline int falcon_mux_apply(struct pinctrl_dev *pctrldev,
+			int mfp, int mux)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	int port = PORT(info->mfp[mfp].pin);
+
+	if ((port >= PORTS) || (!info->membase[port]))
+		return -ENODEV;
+
+	pad_w32(info->membase[port], mux,
+		LTQ_PADC_MUX(PORT_PIN(info->mfp[mfp].pin)));
+	return 0;
+}
+
+static const struct ltq_cfg_param falcon_cfg_params[] = {
+	{"lantiq,pull",			LTQ_PINCONF_PARAM_PULL},
+	{"lantiq,drive-current",	LTQ_PINCONF_PARAM_DRIVE_CURRENT},
+	{"lantiq,slew-rate",		LTQ_PINCONF_PARAM_SLEW_RATE},
+};
+
+static struct ltq_pinmux_info falcon_info = {
+	.desc		= &falcon_pctrl_desc,
+	.apply_mux	= falcon_mux_apply,
+};
+
+
+
+
+/* --------- register the pinctrl layer --------- */
+
+int pinctrl_falcon_get_range_size(int id)
+{
+	u32 avail;
+
+	if ((id >= PORTS) || (!falcon_info.membase[id]))
+		return -EINVAL;
+
+	avail = pad_r32(falcon_info.membase[id], LTQ_PADC_AVAIL);
+
+	return fls(avail);
+}
+
+void pinctrl_falcon_add_gpio_range(struct pinctrl_gpio_range *range)
+{
+	pinctrl_add_gpio_range(falcon_info.pctrl, range);
+}
+
+static int pinctrl_falcon_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	int pad_count = 0;
+	int ret = 0;
+
+	/* load and remap the pad resources of the different banks */
+	for_each_compatible_node(np, NULL, "lantiq,pad-falcon") {
+		struct platform_device *ppdev = of_find_device_by_node(np);
+		const __be32 *bank = of_get_property(np, "lantiq,bank", NULL);
+		struct resource res;
+		u32 avail;
+		int pins;
+
+		if (!ppdev) {
+			dev_err(&pdev->dev, "failed to find pad pdev\n");
+			continue;
+		}
+		if (!bank || *bank >= PORTS)
+			continue;
+		if (of_address_to_resource(np, 0, &res))
+			continue;
+		falcon_info.clk[*bank] = clk_get(&ppdev->dev, NULL);
+		if (IS_ERR(falcon_info.clk[*bank])) {
+			dev_err(&ppdev->dev, "failed to get clock\n");
+			return PTR_ERR(falcon_info.clk[*bank]);
+		}
+		falcon_info.membase[*bank] =
+				devm_request_and_ioremap(&pdev->dev, &res);
+		if (!falcon_info.membase[*bank]) {
+			dev_err(&pdev->dev,
+				"Failed to remap memory for bank %d\n",
+				*bank);
+			return -ENOMEM;
+		}
+		avail = pad_r32(falcon_info.membase[*bank],
+					LTQ_PADC_AVAIL);
+		pins = fls(avail);
+		lantiq_load_pin_desc(&falcon_pads[pad_count], *bank, pins);
+		pad_count += pins;
+		clk_enable(falcon_info.clk[*bank]);
+		dev_dbg(&pdev->dev, "found %s with %d pads\n",
+				res.name, pins);
+	}
+	dev_dbg(&pdev->dev, "found a total of %d pads\n", pad_count);
+	falcon_pctrl_desc.name	= dev_name(&pdev->dev);
+	falcon_pctrl_desc.npins	= pad_count;
+
+	falcon_info.mfp		= falcon_mfp;
+	falcon_info.num_mfp	= ARRAY_SIZE(falcon_mfp);
+	falcon_info.grps	= falcon_grps;
+	falcon_info.num_grps	= ARRAY_SIZE(falcon_grps);
+	falcon_info.funcs	= falcon_funcs;
+	falcon_info.num_funcs	= ARRAY_SIZE(falcon_funcs);
+
+	ret = ltq_pinctrl_register(pdev, &falcon_info);
+	if (!ret)
+		dev_info(&pdev->dev, "Init done\n");
+	return ret;
+}
+
+static const struct of_device_id falcon_match[] = {
+	{ .compatible = "lantiq,pinctrl-falcon" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, falcon_match);
+
+static struct platform_driver pinctrl_falcon_driver = {
+	.probe = pinctrl_falcon_probe,
+	.driver = {
+		.name = "pinctrl-falcon",
+		.owner = THIS_MODULE,
+		.of_match_table = falcon_match,
+	},
+};
+
+int __init pinctrl_falcon_init(void)
+{
+	return platform_driver_register(&pinctrl_falcon_driver);
+}
+
+core_initcall_sync(pinctrl_falcon_init);
-- 
1.7.9.1


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

* [PATCH 4/6] Document: devicetree: add OF documents for lantiq falcon pinctrl
  2012-07-24  6:50 [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support John Crispin
  2012-07-24  6:50 ` [PATCH 2/6] Document: devicetree: add OF documents for lantiq xway pinctrl John Crispin
  2012-07-24  6:50 ` [PATCH 3/6] OF: pinctrl: MIPS: lantiq: adds support for FALCON SoC John Crispin
@ 2012-07-24  6:50 ` John Crispin
  2012-07-24  6:50 ` [PATCH 5/6] GPIO: MIPS: add gpio driver for flacon SoC John Crispin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: John Crispin @ 2012-07-24  6:50 UTC (permalink / raw)
  To: Grant Likely
  Cc: John Crispin, Thomas Langer, Linus Walleij, devicetree-discuss,
	linux-kernel

Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-kernel@vger.kernel.org
---
 .../bindings/pinctrl/lantiq,falcon-pinumx.txt      |   83 ++++++++++++++++++++
 1 files changed, 83 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt b/Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt
new file mode 100644
index 0000000..daa7689
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt
@@ -0,0 +1,83 @@
+Lantiq FALCON pinmux controller
+
+Required properties:
+- compatible: "lantiq,pinctrl-falcon"
+- reg: Should contain the physical address and length of the gpio/pinmux
+  register range
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Lantiq's pin configuration nodes act as a container for an abitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those group(s), and two pin configuration parameters:
+pull-up and open-drain
+
+The name of each subnode is not important as long as it is unique; all subnodes
+should be enumerated and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+We support 2 types of nodes.
+
+Definition of mux function groups:
+
+Required subnode-properties:
+- lantiq,groups : An array of strings. Each string contains the name of a group.
+  Valid values for these names are listed below.
+- lantiq,function: A string containing the name of the function to mux to the
+  group. Valid values for function names are listed below.
+
+Valid values for group and function names:
+
+  mux groups:
+    por, ntr, ntr8k, hrst, mdio, bootled, asc0, spi, spi cs0, spi cs1, i2c,
+    jtag, slic, pcm, asc1
+
+  functions:
+    rst, ntr, mdio, led, asc, spi, i2c, jtag, slic, pcm
+
+
+Definition of pin configurations:
+
+Required subnode-properties:
+- lantiq,pins : An array of strings. Each string contains the name of a pin.
+  Valid values for these names are listed below.
+
+Optional subnode-properties:
+- lantiq,pull: Integer, representing the pull-down/up to apply to the pin.
+    0: none, 1: down
+- lantiq,drive-current: Boolean, enables drive-current
+- lantiq,slew-rate: Boolean, enables slew-rate
+
+Example:
+	pinmux0 {
+		compatible = "lantiq,pinctrl-falcon";
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			asc0 {
+				lantiq,groups = "asc0";
+				lantiq,function = "asc";
+			};
+			ntr {
+				lantiq,groups = "ntr8k";
+				lantiq,function = "ntr";
+			};
+			i2c {
+				lantiq,groups = "i2c";
+				lantiq,function = "i2c";
+			};
+			hrst {
+				lantiq,groups = "hrst";
+				lantiq,function = "rst";
+			};
+		};
+	};
-- 
1.7.9.1


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

* [PATCH 5/6] GPIO: MIPS: add gpio driver for flacon SoC
  2012-07-24  6:50 [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support John Crispin
                   ` (2 preceding siblings ...)
  2012-07-24  6:50 ` [PATCH 4/6] Document: devicetree: add OF documents for lantiq falcon pinctrl John Crispin
@ 2012-07-24  6:50 ` John Crispin
  2012-07-24  8:09   ` Langer Thomas (LQDE RD ST PON SW)
  2012-07-24  6:51 ` [PATCH 6/6] GPIO: MIPS: lantiq: fix overflow inside stp-xway driver John Crispin
  2012-07-27 23:23 ` [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support Linus Walleij
  5 siblings, 1 reply; 11+ messages in thread
From: John Crispin @ 2012-07-24  6:50 UTC (permalink / raw)
  To: Grant Likely; +Cc: John Crispin, Thomas Langer, linux-kernel

Add driver for GPIO blocks found on Lantiq FALCON SoC. The SoC has 5 banks of
up to 32 pads. The GPIO blocks have a per pin IRQs.

Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
Cc: linux-kernel@vger.kernel.org
---
 arch/mips/include/asm/mach-lantiq/gpio.h |    4 +
 drivers/gpio/Kconfig                     |    5 +
 drivers/gpio/Makefile                    |    1 +
 drivers/gpio/gpio-falcon.c               |  355 ++++++++++++++++++++++++++++++
 4 files changed, 365 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/gpio-falcon.c

diff --git a/arch/mips/include/asm/mach-lantiq/gpio.h b/arch/mips/include/asm/mach-lantiq/gpio.h
index f79505b..fdc8638 100644
--- a/arch/mips/include/asm/mach-lantiq/gpio.h
+++ b/arch/mips/include/asm/mach-lantiq/gpio.h
@@ -1,10 +1,14 @@
 #ifndef __ASM_MIPS_MACH_LANTIQ_GPIO_H
 #define __ASM_MIPS_MACH_LANTIQ_GPIO_H
 
+#ifndef CONFIG_SOC_FALCON
 static inline int gpio_to_irq(unsigned int gpio)
 {
 	return -1;
 }
+#else
+extern int gpio_to_irq(unsigned int gpio);
+#endif
 
 #define gpio_get_value __gpio_get_value
 #define gpio_set_value __gpio_set_value
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 502b5ea..f083a8a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -114,6 +114,11 @@ config GPIO_EP93XX
 	depends on ARCH_EP93XX
 	select GPIO_GENERIC
 
+config GPIO_FALCON
+	def_bool y
+	depends on MIPS && SOC_FALCON
+	select GPIO_GENERIC
+
 config GPIO_MM_LANTIQ
 	bool "Lantiq Memory mapped GPIOs"
 	depends on LANTIQ && SOC_XWAY
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d370481..fbf2c51 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_DA9052)	+= gpio-da9052.o
 obj-$(CONFIG_ARCH_DAVINCI)	+= gpio-davinci.o
 obj-$(CONFIG_GPIO_EM)		+= gpio-em.o
 obj-$(CONFIG_GPIO_EP93XX)	+= gpio-ep93xx.o
+obj-$(CONFIG_GPIO_FALCON)	+= gpio-falcon.o
 obj-$(CONFIG_GPIO_GE_FPGA)	+= gpio-ge.o
 obj-$(CONFIG_GPIO_ICH)		+= gpio-ich.o
 obj-$(CONFIG_GPIO_IT8761E)	+= gpio-it8761e.o
diff --git a/drivers/gpio/gpio-falcon.c b/drivers/gpio/gpio-falcon.c
new file mode 100644
index 0000000..e0ff32c
--- /dev/null
+++ b/drivers/gpio/gpio-falcon.c
@@ -0,0 +1,355 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+
+#include <lantiq_soc.h>
+
+/* Data Output Register */
+#define GPIO_OUT            0x00000000
+/* Data Input Register */
+#define GPIO_IN             0x00000004
+/* Direction Register */
+#define GPIO_DIR            0x00000008
+/* External Interrupt Control Register 0 */
+#define GPIO_EXINTCR0       0x00000018
+/* External Interrupt Control Register 1 */
+#define GPIO_EXINTCR1       0x0000001C
+/* IRN Capture Register */
+#define GPIO_IRNCR          0x00000020
+/* IRN Interrupt Configuration Register */
+#define GPIO_IRNCFG		0x0000002C
+/* IRN Interrupt Enable Set Register */
+#define GPIO_IRNRNSET       0x00000030
+/* IRN Interrupt Enable Clear Register */
+#define GPIO_IRNENCLR       0x00000034
+/* Output Set Register */
+#define GPIO_OUTSET         0x00000040
+/* Output Cler Register */
+#define GPIO_OUTCLR         0x00000044
+/* Direction Clear Register */
+#define GPIO_DIRSET         0x00000048
+/* Direction Set Register */
+#define GPIO_DIRCLR         0x0000004C
+
+/* turn a gpio_chip into a falcon_gpio_port */
+#define ctop(c)		container_of(c, struct falcon_gpio_port, gpio_chip)
+/* turn a irq_data into a falcon_gpio_port */
+#define itop(i)		((struct falcon_gpio_port *) irq_get_chip_data(i->irq))
+
+#define port_r32(p, reg)	ltq_r32(p->port + reg)
+#define port_w32(p, val, reg)	ltq_w32(val, p->port + reg)
+#define port_w32_mask(p, clear, set, reg) \
+		port_w32(p, (port_r32(p, reg) & ~(clear)) | (set), reg)
+
+#define MAX_PORTS		5
+#define PINS_PER_PORT		32
+
+struct falcon_gpio_port {
+	struct gpio_chip gpio_chip;
+	void __iomem *port;
+	unsigned int irq_base;
+	unsigned int chained_irq;
+	struct clk *clk;
+	char name[6];
+};
+
+int gpio_to_irq(unsigned int gpio)
+{
+	return __gpio_to_irq(gpio);
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+static int falcon_gpio_direction_input(struct gpio_chip *chip,
+					unsigned int offset)
+{
+	port_w32(ctop(chip), 1 << offset, GPIO_DIRCLR);
+
+	return 0;
+}
+
+static void falcon_gpio_set(struct gpio_chip *chip, unsigned int offset,
+					int value)
+{
+	if (value)
+		port_w32(ctop(chip), 1 << offset, GPIO_OUTSET);
+	else
+		port_w32(ctop(chip), 1 << offset, GPIO_OUTCLR);
+}
+
+static int falcon_gpio_direction_output(struct gpio_chip *chip,
+					unsigned int offset, int value)
+{
+	falcon_gpio_set(chip, offset, value);
+	port_w32(ctop(chip), 1 << offset, GPIO_DIRSET);
+
+	return 0;
+}
+
+static int falcon_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	if ((port_r32(ctop(chip), GPIO_DIR) >> offset) & 1)
+		return (port_r32(ctop(chip), GPIO_OUT) >> offset) & 1;
+	else
+		return (port_r32(ctop(chip), GPIO_IN) >> offset) & 1;
+}
+
+static int falcon_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	return pinctrl_request_gpio(gpio);
+}
+
+static void falcon_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	pinctrl_free_gpio(gpio);
+}
+
+static int falcon_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	return ctop(chip)->irq_base + offset;
+}
+
+static void falcon_gpio_disable_irq(struct irq_data *d)
+{
+	unsigned int offset = d->irq - itop(d)->irq_base;
+
+	port_w32(itop(d), 1 << offset, GPIO_IRNENCLR);
+}
+
+static void falcon_gpio_enable_irq(struct irq_data *d)
+{
+	unsigned int offset = d->irq - itop(d)->irq_base;
+
+	port_w32(itop(d), 1 << offset, GPIO_IRNRNSET);
+}
+
+static void falcon_gpio_ack_irq(struct irq_data *d)
+{
+	unsigned int offset = d->irq - itop(d)->irq_base;
+
+	port_w32(itop(d), 1 << offset, GPIO_IRNCR);
+}
+
+static void falcon_gpio_mask_and_ack_irq(struct irq_data *d)
+{
+	unsigned int offset = d->irq - itop(d)->irq_base;
+
+	port_w32(itop(d), 1 << offset, GPIO_IRNENCLR);
+	port_w32(itop(d), 1 << offset, GPIO_IRNCR);
+}
+
+static struct irq_chip falcon_gpio_irq_chip;
+static int falcon_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+	unsigned int offset = d->irq - itop(d)->irq_base;
+	unsigned int mask = 1 << offset;
+
+	if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE)
+		return 0;
+
+	if ((type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) != 0) {
+		/* level triggered */
+		port_w32_mask(itop(d), 0, mask, GPIO_IRNCFG);
+		irq_set_chip_and_handler_name(d->irq,
+			&falcon_gpio_irq_chip, handle_level_irq, "mux");
+	} else {
+		/* edge triggered */
+		port_w32_mask(itop(d), mask, 0, GPIO_IRNCFG);
+		irq_set_chip_and_handler_name(d->irq,
+			&falcon_gpio_irq_chip, handle_simple_irq, "mux");
+	}
+
+	if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+		port_w32_mask(itop(d), mask, 0, GPIO_EXINTCR0);
+		port_w32_mask(itop(d), 0, mask, GPIO_EXINTCR1);
+	} else {
+		if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) != 0)
+			/* positive logic: rising edge, high level */
+			port_w32_mask(itop(d), mask, 0, GPIO_EXINTCR0);
+		else
+			/* negative logic: falling edge, low level */
+			port_w32_mask(itop(d), 0, mask, GPIO_EXINTCR0);
+		port_w32_mask(itop(d), mask, 0, GPIO_EXINTCR1);
+	}
+
+	return gpio_direction_input(itop(d)->gpio_chip.base + offset);
+}
+
+static void falcon_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct falcon_gpio_port *gpio_port = irq_desc_get_handler_data(desc);
+	unsigned long irncr;
+	int offset;
+
+	/* acknowledge interrupt */
+	irncr = port_r32(gpio_port, GPIO_IRNCR);
+	port_w32(gpio_port, irncr, GPIO_IRNCR);
+
+	desc->irq_data.chip->irq_ack(&desc->irq_data);
+
+	for_each_set_bit(offset, &irncr, gpio_port->gpio_chip.ngpio)
+		generic_handle_irq(gpio_port->irq_base + offset);
+}
+
+static int falcon_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+				irq_hw_number_t hw)
+{
+	struct falcon_gpio_port *port = d->host_data;
+
+	irq_set_chip_and_handler_name(irq, &falcon_gpio_irq_chip,
+			handle_simple_irq, "mux");
+	irq_set_chip_data(irq, port);
+
+	/* set to negative logic (falling edge, low level) */
+	port_w32_mask(port, 0, 1 << hw, GPIO_EXINTCR0);
+	return 0;
+}
+
+static struct irq_chip falcon_gpio_irq_chip = {
+	.name = "gpio_irq_mux",
+	.irq_mask = falcon_gpio_disable_irq,
+	.irq_unmask = falcon_gpio_enable_irq,
+	.irq_ack = falcon_gpio_ack_irq,
+	.irq_mask_ack = falcon_gpio_mask_and_ack_irq,
+	.irq_set_type = falcon_gpio_irq_type,
+};
+
+static const struct irq_domain_ops irq_domain_ops = {
+	.xlate = irq_domain_xlate_onetwocell,
+	.map = falcon_gpio_irq_map,
+};
+
+static struct irqaction gpio_cascade = {
+	.handler = no_action,
+	.flags = IRQF_DISABLED,
+	.name = "gpio_cascade",
+};
+
+static int falcon_gpio_probe(struct platform_device *pdev)
+{
+	struct pinctrl_gpio_range *gpio_range;
+	struct device_node *node = pdev->dev.of_node;
+	const __be32 *bank = of_get_property(node, "lantiq,bank", NULL);
+	struct falcon_gpio_port *gpio_port;
+	struct resource *gpiores, irqres;
+	int ret, size;
+
+	if (!bank || *bank >= MAX_PORTS)
+		return -ENODEV;
+
+	size = pinctrl_falcon_get_range_size(*bank);
+	if (size < 1) {
+		dev_err(&pdev->dev, "pad not loaded for bank %d\n", *bank);
+		return size;
+	}
+
+	gpiores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!gpiores)
+		return -ENODEV;
+
+	gpio_range = devm_kzalloc(&pdev->dev, sizeof(struct pinctrl_gpio_range),
+				GFP_KERNEL);
+	if (!gpio_range)
+		return -ENOMEM;
+
+	gpio_port = devm_kzalloc(&pdev->dev, sizeof(struct falcon_gpio_port),
+				GFP_KERNEL);
+	if (!gpio_port)
+		return -ENOMEM;
+	snprintf(gpio_port->name, 6, "gpio%d", *bank);
+	gpio_port->gpio_chip.label = gpio_port->name;
+	gpio_port->gpio_chip.direction_input = falcon_gpio_direction_input;
+	gpio_port->gpio_chip.direction_output = falcon_gpio_direction_output;
+	gpio_port->gpio_chip.get = falcon_gpio_get;
+	gpio_port->gpio_chip.set = falcon_gpio_set;
+	gpio_port->gpio_chip.request = falcon_gpio_request;
+	gpio_port->gpio_chip.free = falcon_gpio_free;
+	gpio_port->gpio_chip.base = -1;
+	gpio_port->gpio_chip.ngpio = size;
+	gpio_port->gpio_chip.dev = &pdev->dev;
+
+	gpio_port->port = devm_request_and_ioremap(&pdev->dev, gpiores);
+	if (!gpio_port->port) {
+		dev_err(&pdev->dev, "Could not map io ranges\n");
+		return -ENOMEM;
+	}
+
+	gpio_port->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(gpio_port->clk)) {
+		dev_err(&pdev->dev, "Could not get clock\n");
+		return PTR_ERR(gpio_port->clk);
+	}
+	clk_enable(gpio_port->clk);
+
+	if (of_irq_to_resource_table(node, &irqres, 1) == 1) {
+		gpio_port->irq_base = INT_NUM_EXTRA_START + (32 * *bank);
+		gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq;
+		gpio_port->chained_irq = irqres.start;
+		irq_domain_add_legacy(node, size, gpio_port->irq_base, 0,
+					&irq_domain_ops, gpio_port);
+		setup_irq(irqres.start, &gpio_cascade);
+		irq_set_handler_data(irqres.start, gpio_port);
+		irq_set_chained_handler(irqres.start, falcon_gpio_irq_handler);
+	}
+
+	ret = gpiochip_add(&gpio_port->gpio_chip);
+	if (!ret)
+		platform_set_drvdata(pdev, gpio_port);
+
+	gpio_range->name = "FALCON GPIO";
+	gpio_range->id = *bank;
+	gpio_range->base = gpio_port->gpio_chip.base;
+	gpio_range->npins = gpio_port->gpio_chip.ngpio;
+	gpio_range->gc = &gpio_port->gpio_chip;
+	pinctrl_falcon_add_gpio_range(gpio_range);
+
+	return ret;
+}
+
+static const struct of_device_id falcon_gpio_match[] = {
+	{ .compatible = "lantiq,gpio-falcon" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, falcon_gpio_match);
+
+static struct platform_driver falcon_gpio_driver = {
+	.probe = falcon_gpio_probe,
+	.driver = {
+		.name = "gpio-falcon",
+		.owner = THIS_MODULE,
+		.of_match_table = falcon_gpio_match,
+	},
+};
+
+int __init falcon_gpio_init(void)
+{
+	int ret;
+
+	pr_info("FALC(tm) ON GPIO Driver, (C) 2012 Lantiq Deutschland Gmbh\n");
+	ret = platform_driver_register(&falcon_gpio_driver);
+	if (ret)
+		pr_err("falcon_gpio: Error registering platform driver!");
+	return ret;
+}
+
+subsys_initcall(falcon_gpio_init);
-- 
1.7.9.1


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

* [PATCH 6/6] GPIO: MIPS: lantiq: fix overflow inside stp-xway driver
  2012-07-24  6:50 [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support John Crispin
                   ` (3 preceding siblings ...)
  2012-07-24  6:50 ` [PATCH 5/6] GPIO: MIPS: add gpio driver for flacon SoC John Crispin
@ 2012-07-24  6:51 ` John Crispin
  2012-07-27 23:23 ` [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support Linus Walleij
  5 siblings, 0 replies; 11+ messages in thread
From: John Crispin @ 2012-07-24  6:51 UTC (permalink / raw)
  To: Grant Likely; +Cc: John Crispin, linux-kernel

The driver was using a 16 bit field for storing the shadow value of the shift
register cascade. This resulted in only the first 2 shift registeres receiving
the correct data. The third shift register would always receive 0x00.

Fix this by using a 32bit field for the shadow value.

Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-kernel@vger.kernel.org
---
 drivers/gpio/gpio-stp-xway.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index e35096b..8bead0b 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -82,7 +82,7 @@ struct xway_stp {
 	struct gpio_chip gc;
 	void __iomem *virt;
 	u32 edge;	/* rising or falling edge triggered shift register */
-	u16 shadow;	/* shadow the shift registers state */
+	u32 shadow;	/* shadow the shift registers state */
 	u8 groups;	/* we can drive 1-3 groups of 8bit each */
 	u8 dsl;		/* the 2 LSBs can be driven by the dsl core */
 	u8 phy1;	/* 3 bits can be driven by phy1 */
-- 
1.7.9.1


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

* RE: [PATCH 5/6] GPIO: MIPS: add gpio driver for flacon SoC
  2012-07-24  6:50 ` [PATCH 5/6] GPIO: MIPS: add gpio driver for flacon SoC John Crispin
@ 2012-07-24  8:09   ` Langer Thomas (LQDE RD ST PON SW)
  2012-07-24  8:20     ` John Crispin
  0 siblings, 1 reply; 11+ messages in thread
From: Langer Thomas (LQDE RD ST PON SW) @ 2012-07-24  8:09 UTC (permalink / raw)
  To: John Crispin, Grant Likely; +Cc: linux-kernel

Hello John,

John Crispin wrote on 2012-07-24:
> Add driver for GPIO blocks found on Lantiq FALCON SoC. The SoC has 5
> banks of up to 32 pads. The GPIO blocks have a per pin IRQs.
> 
> Signed-off-by: John Crispin <blogic@openwrt.org>
> Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
> Cc: linux-kernel@vger.kernel.org
> ---
>  arch/mips/include/asm/mach-lantiq/gpio.h |    4 +
>  drivers/gpio/Kconfig                     |    5 +
>  drivers/gpio/Makefile                    |    1 +
>  drivers/gpio/gpio-falcon.c               |  355 ++++++++++++++++++++++++++++++
>  4 files changed, 365 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/gpio/gpio-falcon.c

Please fix the spelling error in the subject!

Best Regards,
Thomas



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

* Re: [PATCH 5/6] GPIO: MIPS: add gpio driver for flacon SoC
  2012-07-24  8:09   ` Langer Thomas (LQDE RD ST PON SW)
@ 2012-07-24  8:20     ` John Crispin
  0 siblings, 0 replies; 11+ messages in thread
From: John Crispin @ 2012-07-24  8:20 UTC (permalink / raw)
  To: Langer Thomas (LQDE RD ST PON SW); +Cc: Grant Likely, linux-kernel

On 24/07/12 10:09, Langer Thomas (LQDE RD ST PON SW) wrote:
> Hello John,
>
> John Crispin wrote on 2012-07-24:
>> Add driver for GPIO blocks found on Lantiq FALCON SoC. The SoC has 5
>> banks of up to 32 pads. The GPIO blocks have a per pin IRQs.
>>
>> Signed-off-by: John Crispin <blogic@openwrt.org>
>> Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
>> Cc: linux-kernel@vger.kernel.org
>> ---
>>  arch/mips/include/asm/mach-lantiq/gpio.h |    4 +
>>  drivers/gpio/Kconfig                     |    5 +
>>  drivers/gpio/Makefile                    |    1 +
>>  drivers/gpio/gpio-falcon.c               |  355 ++++++++++++++++++++++++++++++
>>  4 files changed, 365 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/gpio/gpio-falcon.c
> Please fix the spelling error in the subject!
>
> Best Regards,
> Thomas

Hi Thomas,

nice catch

thanks,
John


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

* Re: [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support
  2012-07-24  6:50 [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support John Crispin
                   ` (4 preceding siblings ...)
  2012-07-24  6:51 ` [PATCH 6/6] GPIO: MIPS: lantiq: fix overflow inside stp-xway driver John Crispin
@ 2012-07-27 23:23 ` Linus Walleij
  5 siblings, 0 replies; 11+ messages in thread
From: Linus Walleij @ 2012-07-27 23:23 UTC (permalink / raw)
  To: John Crispin; +Cc: Grant Likely, devicetree-discuss, linux-kernel

On Tue, Jul 24, 2012 at 8:50 AM, John Crispin <blogic@openwrt.org> wrote:

> Implement support for pinctrl on lantiq/xway socs. The IO core found on these
> socs has the registers for pinctrl, pinconf and gpio mixed up in the same
> register range. As the gpio_chip handling is only a few lines, the driver also
> implements the gpio functionality. This obseletes the old gpio driver that was
> located in the arch/ folder.
>
> Signed-off-by: John Crispin <blogic@openwrt.org>
> Acked-by: Linus Walleij <linus.walleij@linaro.org>

I still ACK it, just a comment:

> +/* these are the offsets to our registers */
> +#define GPIO_BASE(p)           (REG_OFF * PORT(p))
> +#define GPIO_OUT(p)            GPIO_BASE(p)
> +#define GPIO_IN(p)             (GPIO_BASE(p) + 0x04)
> +#define GPIO_DIR(p)            (GPIO_BASE(p) + 0x08)
> +#define GPIO_ALT0(p)           (GPIO_BASE(p) + 0x0C)
> +#define GPIO_ALT1(p)           (GPIO_BASE(p) + 0x10)
> +#define GPIO_OD(p)             (GPIO_BASE(p) + 0x14)
> +#define GPIO_PUDSEL(p)         (GPIO_BASE(p) + 0x1c)
> +#define GPIO_PUDEN(p)          (GPIO_BASE(p) + 0x20)
> +
> +/* the 1/2 port needs special offsets for some registers */
> +#define GPIO3_OD               (GPIO_BASE(0) + 0x24)
> +#define GPIO3_PUDSEL           (GPIO_BASE(0) + 0x28)
> +#define GPIO3_PUDEN            (GPIO_BASE(0) + 0x2C)
> +#define GPIO3_ALT1             (GPIO_BASE(PINS) + 0x24)
> +
> +/* macros to help us access the registers */
> +#define gpio_getbit(m, r, p)   (!!(ltq_r32(m + r) & BIT(p)))
> +#define gpio_setbit(m, r, p)   ltq_w32_mask(0, BIT(p), m + r)
> +#define gpio_clearbit(m, r, p) ltq_w32_mask(BIT(p), 0, m + r)

These are a bit confusing since much of this stuff is not dealing with
GPIO at all (but some pulling, open draining etc).

Consider renaming some of these some day.

Yours,
Linus Walleij

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

* Re: [PATCH 3/6] OF: pinctrl: MIPS: lantiq: adds support for FALCON SoC
  2012-07-24  6:50 ` [PATCH 3/6] OF: pinctrl: MIPS: lantiq: adds support for FALCON SoC John Crispin
@ 2012-07-27 23:23   ` Linus Walleij
  2012-07-30  9:41     ` John Crispin
  0 siblings, 1 reply; 11+ messages in thread
From: Linus Walleij @ 2012-07-27 23:23 UTC (permalink / raw)
  To: John Crispin
  Cc: Grant Likely, Thomas Langer, devicetree-discuss, linux-kernel

On Tue, Jul 24, 2012 at 8:50 AM, John Crispin <blogic@openwrt.org> wrote:

> Implement support for pinctrl on lantiq/falcon socs. The FALCON has 5 banks
> of up to 32 pins.
>
> Signed-off-by: John Crispin <blogic@openwrt.org>
> Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Cc: devicetree-discuss@lists.ozlabs.org
> Cc: linux-kernel@vger.kernel.org

No big issues and looking really sweet so:
Acked-by: Linus Walleij <linus.walleij@linaro.org>

> --- a/arch/mips/lantiq/Kconfig
> +++ b/arch/mips/lantiq/Kconfig
> @@ -20,6 +20,7 @@ config SOC_XWAY
>
>  config SOC_FALCON
>         bool "FALCON"
> +       select PINCTRL_FALCON

I think you need to add "select PINCTRL" above "select PINCTRL_FALCON"
for this to work.

Atleast I had to do that in the past to get things working.

Yours,
Linus Walleij

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

* Re: [PATCH 3/6] OF: pinctrl: MIPS: lantiq: adds support for FALCON SoC
  2012-07-27 23:23   ` Linus Walleij
@ 2012-07-30  9:41     ` John Crispin
  0 siblings, 0 replies; 11+ messages in thread
From: John Crispin @ 2012-07-30  9:41 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grant Likely, Thomas Langer, devicetree-discuss, linux-kernel

On 28/07/12 01:23, Linus Walleij wrote:
> On Tue, Jul 24, 2012 at 8:50 AM, John Crispin <blogic@openwrt.org> wrote:
>
>> Implement support for pinctrl on lantiq/falcon socs. The FALCON has 5 banks
>> of up to 32 pins.
>>
>> Signed-off-by: John Crispin <blogic@openwrt.org>
>> Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
>> Cc: Linus Walleij <linus.walleij@linaro.org>
>> Cc: devicetree-discuss@lists.ozlabs.org
>> Cc: linux-kernel@vger.kernel.org
> No big issues and looking really sweet so:
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
>
>> --- a/arch/mips/lantiq/Kconfig
>> +++ b/arch/mips/lantiq/Kconfig
>> @@ -20,6 +20,7 @@ config SOC_XWAY
>>
>>  config SOC_FALCON
>>         bool "FALCON"
>> +       select PINCTRL_FALCON
> I think you need to add "select PINCTRL" above "select PINCTRL_FALCON"
> for this to work.
>
> Atleast I had to do that in the past to get things working.

Hi Linus,

config LANTIQ selects PINCTRL  globally for all Lantiq SoC so an
explicit select can be avoided here

Thanks for the review,
John

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

end of thread, other threads:[~2012-07-30  9:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-24  6:50 [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support John Crispin
2012-07-24  6:50 ` [PATCH 2/6] Document: devicetree: add OF documents for lantiq xway pinctrl John Crispin
2012-07-24  6:50 ` [PATCH 3/6] OF: pinctrl: MIPS: lantiq: adds support for FALCON SoC John Crispin
2012-07-27 23:23   ` Linus Walleij
2012-07-30  9:41     ` John Crispin
2012-07-24  6:50 ` [PATCH 4/6] Document: devicetree: add OF documents for lantiq falcon pinctrl John Crispin
2012-07-24  6:50 ` [PATCH 5/6] GPIO: MIPS: add gpio driver for flacon SoC John Crispin
2012-07-24  8:09   ` Langer Thomas (LQDE RD ST PON SW)
2012-07-24  8:20     ` John Crispin
2012-07-24  6:51 ` [PATCH 6/6] GPIO: MIPS: lantiq: fix overflow inside stp-xway driver John Crispin
2012-07-27 23:23 ` [PATCH 1/6] OF: pinctrl: MIPS: lantiq: implement lantiq/xway pinctrl support Linus Walleij

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).