All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mollie Wu <mollie.wu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: andy.green-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	patches-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	jaswinder.singh-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org,
	arnd-r2nGTMty4D4@public.gmane.org,
	olof-nZhT3qVonbNeoWH0uzbU5w@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	pawel.moll-5wv7dgnIgG8@public.gmane.org,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	Mollie Wu <mollie.wu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Tetsuya Takinishi
	<t.takinishi-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
Subject: [PATCH 5/8] pinctrl: add driver for MB86S7x
Date: Sun, 13 Jul 2014 14:31:07 +0800	[thread overview]
Message-ID: <1405233067-4725-1-git-send-email-mollie.wu@linaro.org> (raw)
In-Reply-To: <message-id-of-cover-letter>

The mb86s70 and mb86s73 Fujitsu SoCs differ in that the latter provide a pinmux.
GPIOs are supported on top of Pinctrl api.

Signed-off-by: Jassi Brar <jaswinder.singh-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Tetsuya Takinishi <t.takinishi-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
Signed-off-by: Mollie Wu <mollie.wu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 .../bindings/gpio/fujitsu,mb86s7x-gpio.txt         |   22 +
 .../bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt   |   30 +
 drivers/pinctrl/Kconfig                            |    5 +
 drivers/pinctrl/Makefile                           |    1 +
 drivers/pinctrl/pinctrl-mb86s7x.c                  | 1281 ++++++++++++++++++++
 5 files changed, 1339 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt
 create mode 100644 Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt
 create mode 100644 drivers/pinctrl/pinctrl-mb86s7x.c

diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt
new file mode 100644
index 0000000..c262efa
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt
@@ -0,0 +1,22 @@
+Fujitsu MB86S7x GPIO Controller
+-------------------------------
+
+Required properties:
+- compatible: Should be "fujitsu,mb86s7x-gpio"
+- gpio-controller: Marks the device node as a gpio controller.
+- #gpio-cells: Should be <2>. The first cell is the pin number and the
+  second cell is used to specify optional parameters:
+   - bit 0 specifies polarity (0 for normal, 1 for inverted).
+
+GPIO ranges are specified as described in
+Documentation/devicetree/bindings/gpio/gpio.txt
+
+Examples:
+	gpio0: mb86s70_gpio0 {
+		compatible = "fujitsu,mb86s7x-gpio";
+		reg = <0 0x31000000 0x10000>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		clocks = <&clk_alw_2_1>;
+	};
diff --git a/Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt
new file mode 100644
index 0000000..ce2011b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt
@@ -0,0 +1,30 @@
+Fujitsu MB86S7x Pin Controller
+------------------------------
+
+Required properties:
+- compatible: Should be "fujitsu,mb86s70-pinctrl" or "fujitsu,mb86s73-pinctrl"
+- reg: Should contain the register physical address and length for the
+  pin controller.
+- #gpio-range-cells: Should be 3
+
+Optional subnode-properties:
+- mb86s7x,function: String specifying the function name.
+- mb86s7x,drvst: Drive strength needed for pins to operate in that mode.
+    0 (Hi-z), 2mA, 4mA, 6mA or 8mA
+- mb86s7x,pullup: Should be 0 for Pull-Down or non-zero for Pull-Up
+
+Examples:
+	pinctrl: pinctrl@2a4d0000 {
+		compatible = "fujitsu,mb86s73-pinctrl";
+		reg = <0 0x2a4d0000 0x1000>, <0 0x312e0000 0x1000>;
+		#gpio-range-cells = <3>;
+
+		hsspi0_pins_active: hsspi0_active {
+			mb86s7x,function = "hsspi0";
+			mb86s7x,drvst = <8>; /* in mA */
+		};
+		hsspi0_pins_sleep: hsspi0_sleep {
+			mb86s7x,function = "hsspi0";
+			mb86s7x,drvst = <0>; /* Implies Hi-z */
+		};
+	};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 0042ccb..1f053fc 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -213,6 +213,11 @@ config PINCTRL_FALCON
 	depends on SOC_FALCON
 	depends on PINCTRL_LANTIQ
 
+config PINCTRL_MB86S7X
+	bool
+	select PINMUX
+	select GENERIC_PINCONF
+
 config PINCTRL_MXS
 	bool
 	select PINMUX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c4b5d40..edcb823 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q)	+= pinctrl-imx6dl.o
 obj-$(CONFIG_PINCTRL_IMX6SL)	+= pinctrl-imx6sl.o
 obj-$(CONFIG_PINCTRL_IMX6SX)	+= pinctrl-imx6sx.o
 obj-$(CONFIG_PINCTRL_FALCON)	+= pinctrl-falcon.o
+obj-$(CONFIG_PINCTRL_MB86S7X)	+= pinctrl-mb86s7x.o
 obj-$(CONFIG_PINCTRL_MXS)	+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)	+= pinctrl-imx23.o
 obj-$(CONFIG_PINCTRL_IMX25)	+= pinctrl-imx25.o
diff --git a/drivers/pinctrl/pinctrl-mb86s7x.c b/drivers/pinctrl/pinctrl-mb86s7x.c
new file mode 100644
index 0000000..74c72ec8
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-mb86s7x.c
@@ -0,0 +1,1281 @@
+/*
+ *  linux/drivers/pinctrl/pinctrl-mb86s7x.c
+ *
+ *  Copyright (C) 2014 Fujitsu Semiconductor Limited
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#define PDR(x)	(0x0 + x)
+#define DDR(x)	(0x10 + x)
+#define PFR(x)	(0x20 + x)
+
+#define CDRV_PDG(x)	(0x0 + ((x) / 16) * 4)
+#define FORCEZ_PDG(x)	(0x100 + ((x) / 16) * 4)
+#define PULL_PDG(x)	(0x200 + ((x) / 16) * 4)
+#define PIN_OFF(x)	(((x) % 16) * 2)
+
+#define PMUX_MB86S70	0
+#define PMUX_MB86S73	1
+
+/* Virtual pin numbers start so that reg offset calculations get simple */
+enum {
+	PINS_VIRT = 128,
+	PINS_PCIE0 = PINS_VIRT,
+	PINS_HOLE1,
+	PINS_USB3H0,
+	PINS_HOLE2,
+	PINS_USB2H0,
+	PINS_USB2D0,
+	PINS_SDH30,
+	PINS_HOLE3,
+	PINS_EMMC0,
+	PINS_HSSPI0,
+	PINS_GMACD0,
+	PINS_GMACM0,
+	PINS_I2S0,
+	PINS_UART0,
+	PINS_OTHER0,
+	PINS_JTAG0,
+	PINS_PCIE1,
+	PINS_HOLE4,
+	PINS_USB3H1,
+	MB86S70_PMUX_PINS,
+};
+
+struct mb86s70_gpio_chip {
+	spinlock_t lock; /* for goio regs */
+	struct clk *clk;
+	void __iomem *base;
+	struct gpio_chip gc;
+};
+
+static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned offset)
+{
+	int ret = pinctrl_request_gpio(gc->base + offset);
+
+	if (!ret) {
+		struct mb86s70_gpio_chip *gchip = container_of(gc,
+						struct mb86s70_gpio_chip, gc);
+		unsigned long flags;
+		u32 val;
+
+		spin_lock_irqsave(&gchip->lock, flags);
+		val = readl(gchip->base + PFR(offset / 8 * 4));
+		val &= ~(1 << (offset % 8)); /* as gpio-port */
+		writel(val, gchip->base + PFR(offset / 8 * 4));
+		spin_unlock_irqrestore(&gchip->lock, flags);
+	}
+
+	return ret;
+}
+
+static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+					struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	val = readl(gchip->base + PFR(offset / 8 * 4));
+	val |= (1 << (offset % 8)); /* as peri-port */
+	writel(val, gchip->base + PFR(offset / 8 * 4));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	pinctrl_free_gpio(gc->base + offset);
+}
+
+static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	unsigned char val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	val = readl(gchip->base + DDR(offset / 8 * 4));
+	val &= ~(1 << (offset % 8));
+	writel(val, gchip->base + DDR(offset / 8 * 4));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
+					 unsigned offset, int value)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	unsigned char val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+
+	val = readl(gchip->base + PDR(offset / 8 * 4));
+	if (value)
+		val |= (1 << (offset % 8));
+	else
+		val &= ~(1 << (offset % 8));
+	writel(val, gchip->base + PDR(offset / 8 * 4));
+
+	val = readl(gchip->base + DDR(offset / 8 * 4));
+	val |= (1 << (offset % 8));
+	writel(val, gchip->base + DDR(offset / 8 * 4));
+
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned char val;
+
+	val = readl(gchip->base + PDR(offset / 8 * 4));
+	val &= (1 << (offset % 8));
+	return val ? 1 : 0;
+}
+
+static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	unsigned char val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+
+	val = readl(gchip->base + PDR(offset / 8 * 4));
+	if (value)
+		val |= (1 << (offset % 8));
+	else
+		val &= ~(1 << (offset % 8));
+	writel(val, gchip->base + PDR(offset / 8 * 4));
+
+	spin_unlock_irqrestore(&gchip->lock, flags);
+}
+
+static int mb86s70_gpio_probe(struct platform_device *pdev)
+{
+	struct mb86s70_gpio_chip *gchip;
+	struct resource *res;
+	int ret;
+
+	gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
+	if (gchip == NULL)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, gchip);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	gchip->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gchip->base))
+		return PTR_ERR(gchip->base);
+
+	gchip->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(gchip->clk))
+		return PTR_ERR(gchip->clk);
+
+	clk_prepare_enable(gchip->clk);
+
+	spin_lock_init(&gchip->lock);
+
+	gchip->gc.direction_output = mb86s70_gpio_direction_output;
+	gchip->gc.direction_input = mb86s70_gpio_direction_input;
+	gchip->gc.request = mb86s70_gpio_request;
+	gchip->gc.free = mb86s70_gpio_free;
+	gchip->gc.get = mb86s70_gpio_get;
+	gchip->gc.set = mb86s70_gpio_set;
+	gchip->gc.label = dev_name(&pdev->dev);
+	gchip->gc.ngpio = 32;
+	gchip->gc.owner = THIS_MODULE;
+	gchip->gc.dev = &pdev->dev;
+	gchip->gc.base = -1;
+
+	ret = gpiochip_add(&gchip->gc);
+	if (ret) {
+		dev_err(&pdev->dev, "couldn't register gpio driver\n");
+		clk_disable_unprepare(gchip->clk);
+	}
+
+	return ret;
+}
+
+struct mb86s70_pmux_chip {
+	spinlock_t lock; /* mux regs */
+	struct device *dev;
+	void __iomem *base;
+	void __iomem *conf_base;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_desc desc;
+	bool pin_busy[MB86S70_PMUX_PINS];
+	char pin_names[5 * MB86S70_PMUX_PINS];
+	struct pinctrl_pin_desc pins[MB86S70_PMUX_PINS];
+};
+
+struct mb86s70_pmx_grp {
+	const char *name;
+	const unsigned *pins;
+	const unsigned num_pins;
+};
+
+struct mb86s70_pmx_function {
+	const unsigned num_groups;
+	unsigned prog_val;
+	const char *name;
+
+	const char *const *groups;
+};
+
+static const unsigned extint16_s70[] = {0};
+static const unsigned tsif0_s70[] = {16, 17, 18, 19};
+static const unsigned tsif1_s70[] = {16, 17, 18, 19};
+static const unsigned uart1_s70[] = {56, 57, 58, 59};
+static const unsigned uart2_s70[] = {60, 61, 62, 63};
+static const unsigned pl244_s70[] = {40, 41, 42, 43, 44, 45, 46, 47, 48,
+					49, 50, 51, 52, 53, 54, 55, 56, 57,
+					58, 59, 60, 61, 62};
+static const unsigned trace_s70[] = {24, 25, 26, 27, 28, 29, 30, 31, 32,
+					33, 34, 35, 36, 37, 38, 39, 64, 65};
+static const unsigned memcs_s70[] = {16, 17, 18, 19, 20, 21, 22, 23, 24,
+					25, 26, 27, 28, 29, 30, 31, 32, 33,
+					34, 35, 36, 37, 38, 39, 40, 41, 42,
+					43, 44, 45, 46, 47, 48, 49, 50, 51,
+					52, 53, 54, 55, 56, 57, 58, 59, 60,
+					61, 62, 63, 64, 65};
+static const unsigned cap_s70[] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+					26, 27, 28, 29, 30, 31, 32, 33, 34,
+					35, 36, 37, 38, 39, 40, 41, 42, 43,
+					44, 45, 46, 47};
+
+static const struct mb86s70_pmx_grp mb86s70_pgrps[] = {
+	{
+		.name = "extint16_grp",
+		.pins = extint16_s70,
+		.num_pins = ARRAY_SIZE(extint16_s70),
+	},
+	{
+		.name = "tsif0_grp",
+		.pins = tsif0_s70,
+		.num_pins = ARRAY_SIZE(tsif0_s70),
+	},
+	{
+		.name = "tsif1_grp",
+		.pins = tsif1_s70,
+		.num_pins = ARRAY_SIZE(tsif1_s70),
+	},
+	{
+		.name = "uart1_grp",
+		.pins = uart1_s70,
+		.num_pins = ARRAY_SIZE(uart1_s70),
+	},
+	{
+		.name = "uart2_grp",
+		.pins = uart2_s70,
+		.num_pins = ARRAY_SIZE(uart2_s70),
+	},
+	{
+		.name = "pl244_grp",
+		.pins = pl244_s70,
+		.num_pins = ARRAY_SIZE(pl244_s70),
+	},
+	{
+		.name = "trace_grp",
+		.pins = trace_s70,
+		.num_pins = ARRAY_SIZE(trace_s70),
+	},
+	{
+		.name = "memcs_grp",
+		.pins = memcs_s70,
+		.num_pins = ARRAY_SIZE(memcs_s70),
+	},
+	{
+		.name = "cap_grp",
+		.pins = cap_s70,
+		.num_pins = ARRAY_SIZE(cap_s70),
+	}
+};
+
+static const unsigned pcie0_s73[] = {PINS_PCIE0};
+static const unsigned usb3h0_s73[] = {PINS_USB3H0};
+static const unsigned usb2h0_s73[] = {PINS_USB2H0};
+static const unsigned usb2d0_s73[] = {PINS_USB2D0};
+static const unsigned sdh30_s73[] = {PINS_SDH30};
+static const unsigned emmc0_s73[] = {PINS_EMMC0};
+static const unsigned hsspi0_s73[] = {PINS_HSSPI0};
+static const unsigned gmacd0_s73[] = {PINS_GMACD0};
+static const unsigned gmacm0_s73[] = {PINS_GMACM0};
+static const unsigned i2s0_s73[] = {PINS_I2S0};
+static const unsigned other0_s73[] = {PINS_OTHER0};
+static const unsigned jtag0_s73[] = {PINS_JTAG0};
+static const unsigned pcie1_s73[] = {PINS_PCIE1};
+static const unsigned usb3h1_s73[] = {PINS_USB3H1};
+static const unsigned extint5_s73[] = {37};
+static const unsigned cfg_s73[] = {56, 57, 58, 59, 60, 61, 62, 63};
+static const unsigned uart0_s73[] = {8, 11, 12, 15};
+static const unsigned uart1_s73[] = {16, 17, 18, 19, 20, 21, 22, 23};
+static const unsigned uart2_s73[] = {24, 25, 26, 27, 28, 29, 30, 31};
+static const unsigned trace_s73[] = {44, 45, 46, 47, 48, 49, 50,
+					51, 52, 53, 54, 55, 56, 57,
+					58, 59, 60, 61};
+static const unsigned smt_s73[] = {56, 57, 58, 59, 60, 61};
+static const unsigned memcs_s73[] = {8, 9, 10, 11, 12, 13, 14, 15,
+					16, 17, 18, 19, 20, 21, 22,
+					23, 24, 25, 26, 27, 28, 29,
+					30, 31, 32, 33, 34, 35, 36,
+					37, 38, 39, 40, 41, 42, 43,
+					44, 45, 46, 47, 48, 49, 50,
+					51, 52, 53, 54, 55};
+static const unsigned pl244_s73[] = {8, 9, 10, 11, 12, 13, 14, 15,
+					16, 17, 18, 19, 20, 21, 22,
+					23, 24, 25, 26, 27, 28, 29,
+					30, 31};
+
+static const struct mb86s70_pmx_grp mb86s73_pgrps[] = {
+	{
+		.name = "extint5_grp",
+		.pins = extint5_s73,
+		.num_pins = ARRAY_SIZE(extint5_s73),
+	},
+	{
+		.name = "pcie0_grp",
+		.pins = pcie0_s73,
+		.num_pins = ARRAY_SIZE(pcie0_s73),
+	},
+	{
+		.name = "usb3h0_grp",
+		.pins = usb3h0_s73,
+		.num_pins = ARRAY_SIZE(usb3h0_s73),
+	},
+	{
+		.name = "usb2h0_grp",
+		.pins = usb2h0_s73,
+		.num_pins = ARRAY_SIZE(usb2h0_s73),
+	},
+	{
+		.name = "usb2d0_grp",
+		.pins = usb2d0_s73,
+		.num_pins = ARRAY_SIZE(usb2d0_s73),
+	},
+	{
+		.name = "sdh30_grp",
+		.pins = sdh30_s73,
+		.num_pins = ARRAY_SIZE(sdh30_s73),
+	},
+	{
+		.name = "emmc0_grp",
+		.pins = emmc0_s73,
+		.num_pins = ARRAY_SIZE(emmc0_s73),
+	},
+	{
+		.name = "hsspi0_grp",
+		.pins = hsspi0_s73,
+		.num_pins = ARRAY_SIZE(hsspi0_s73),
+	},
+	{
+		.name = "gmacd0_grp",
+		.pins = gmacd0_s73,
+		.num_pins = ARRAY_SIZE(gmacd0_s73),
+	},
+	{
+		.name = "gmacm0_grp",
+		.pins = gmacm0_s73,
+		.num_pins = ARRAY_SIZE(gmacm0_s73),
+	},
+	{
+		.name = "i2s0_grp",
+		.pins = i2s0_s73,
+		.num_pins = ARRAY_SIZE(i2s0_s73),
+	},
+	{
+		.name = "other0_grp",
+		.pins = other0_s73,
+		.num_pins = ARRAY_SIZE(other0_s73),
+	},
+	{
+		.name = "jtag0_grp",
+		.pins = jtag0_s73,
+		.num_pins = ARRAY_SIZE(jtag0_s73),
+	},
+	{
+		.name = "pcie1_grp",
+		.pins = pcie1_s73,
+		.num_pins = ARRAY_SIZE(pcie1_s73),
+	},
+	{
+		.name = "usb3h1_grp",
+		.pins = usb3h1_s73,
+		.num_pins = ARRAY_SIZE(usb3h1_s73),
+	},
+	{
+		.name = "cfg_grp",
+		.pins = cfg_s73,
+		.num_pins = ARRAY_SIZE(cfg_s73),
+	},
+	{
+		.name = "uart0_grp",
+		.pins = uart0_s73,
+		.num_pins = ARRAY_SIZE(uart0_s73),
+	},
+	{
+		.name = "uart1_grp",
+		.pins = uart1_s73,
+		.num_pins = ARRAY_SIZE(uart1_s73),
+	},
+	{
+		.name = "uart2_grp",
+		.pins = uart2_s73,
+		.num_pins = ARRAY_SIZE(uart2_s73),
+	},
+	{
+		.name = "trace_grp",
+		.pins = trace_s73,
+		.num_pins = ARRAY_SIZE(trace_s73),
+	},
+	{
+		.name = "smt_grp",
+		.pins = smt_s73,
+		.num_pins = ARRAY_SIZE(smt_s73),
+	},
+	{
+		.name = "memcs_grp",
+		.pins = memcs_s73,
+		.num_pins = ARRAY_SIZE(memcs_s73),
+	},
+	{
+		.name = "pl244_grp",
+		.pins = pl244_s73,
+		.num_pins = ARRAY_SIZE(pl244_s73),
+	},
+};
+
+static int func_count, grp_count;
+static const struct mb86s70_pmx_grp *mb86s7x_pgrps;
+static const struct mb86s70_pmx_function *mb86s7x_pmx_funcs;
+
+static int mb86s70_pctrl_get_groups_count(struct pinctrl_dev *pctl)
+{
+	return grp_count;
+}
+
+static const char *
+mb86s70_pctrl_get_group_name(struct pinctrl_dev *pctl, unsigned selector)
+{
+	return mb86s7x_pgrps[selector].name;
+}
+
+static int
+mb86s70_pctrl_get_group_pins(struct pinctrl_dev *pctl, unsigned selector,
+			     const unsigned **pins, unsigned *num_pins)
+{
+	*pins = mb86s7x_pgrps[selector].pins;
+	*num_pins = mb86s7x_pgrps[selector].num_pins;
+
+	return 0;
+}
+
+static int
+mb86s70_pctrl_dt_node_to_map(struct pinctrl_dev *pctl,
+			     struct device_node *node,
+			     struct pinctrl_map **map, unsigned *num_maps)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	int ret, i, configlen = 0;
+	unsigned long *pinconfig;
+	const char *function;
+	const char *group;
+	u32 val;
+
+	*map = NULL;
+	*num_maps = 0;
+
+	ret = of_property_read_string(node, "mb86s7x,function", &function);
+	if (ret) {
+		dev_err(pchip->dev,
+			"missing mb86s7x,function property in node %s\n",
+			node->name);
+		return -EINVAL;
+	}
+
+	*map = devm_kzalloc(pchip->dev,
+			    2 * sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (!*map)
+		return -ENOMEM;
+
+	for (i = 0; i < func_count; i++)
+		if (!strcmp(mb86s7x_pmx_funcs[i].name, function))
+			break;
+
+	if (i == func_count) {
+		dev_err(pchip->dev, "function(%s) not found!\n", function);
+		return -EINVAL;
+	}
+	group = mb86s7x_pmx_funcs[i].groups[0];
+
+	(*map)[0].type = PIN_MAP_TYPE_MUX_GROUP;
+	(*map)[0].data.mux.group = group;
+	(*map)[0].data.mux.function = function;
+	*num_maps = 1;
+
+	if (of_find_property(node, "mb86s7x,drvst", NULL))
+		configlen++;
+	if (of_find_property(node, "mb86s7x,pullup", NULL))
+		configlen++;
+
+	if (configlen == 0) /* For S70 */
+		return 0;
+
+	i = 0;
+	pinconfig = devm_kzalloc(pchip->dev,
+				 configlen * sizeof(*pinconfig), GFP_KERNEL);
+
+	if (!of_property_read_u32(node, "mb86s7x,drvst", &val))
+		pinconfig[i++] =
+			pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
+						 val);
+
+	if (!of_property_read_u32(node, "mb86s7x,pullup", &val)) {
+		enum pin_config_param pull;
+
+		if (val)
+			pull = PIN_CONFIG_BIAS_PULL_UP;
+		else
+			pull = PIN_CONFIG_BIAS_PULL_DOWN;
+		pinconfig[i++] = pinconf_to_config_packed(pull, 0);
+	}
+
+	(*map)[1].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+	(*map)[1].data.configs.group_or_pin = group;
+	(*map)[1].data.configs.configs = pinconfig;
+	(*map)[1].data.configs.num_configs = configlen;
+
+	*num_maps = 2;
+
+	return 0;
+}
+
+static void
+mb86s70_pctrl_dt_free_map(struct pinctrl_dev *pctl,
+			  struct pinctrl_map *map, unsigned num_maps)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	int i;
+
+	for (i = 0; i < num_maps; i++)
+		if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+			devm_kfree(pchip->dev, map[i].data.configs.configs);
+
+	devm_kfree(pchip->dev, map);
+}
+
+static const struct pinctrl_ops mb86s70_pctrl_ops = {
+	.get_groups_count	= mb86s70_pctrl_get_groups_count,
+	.get_group_name		= mb86s70_pctrl_get_group_name,
+	.get_group_pins		= mb86s70_pctrl_get_group_pins,
+	.dt_node_to_map		= mb86s70_pctrl_dt_node_to_map,
+	.dt_free_map		= mb86s70_pctrl_dt_free_map,
+};
+
+static const char * const pcie0_groups[] = {"pcie0_grp"};
+static const char * const usb3h0_groups[] = {"usb3h0_grp"};
+static const char * const usb2h0_groups[] = {"usb2h0_grp"};
+static const char * const usb2d0_groups[] = {"usb2d0_grp"};
+static const char * const sdh30_groups[] = {"sdh30_grp"};
+static const char * const emmc0_groups[] = {"emmc0_grp"};
+static const char * const hsspi0_groups[] = {"hsspi0_grp"};
+static const char * const gmacd0_groups[] = {"gmacd0_grp"};
+static const char * const gmacm0_groups[] = {"gmacm0_grp"};
+static const char * const i2s0_groups[] = {"i2s0_grp"};
+static const char * const other0_groups[] = {"other0_grp"};
+static const char * const jtag0_groups[] = {"jtag0_grp"};
+static const char * const pcie1_groups[] = {"pcie1_grp"};
+static const char * const usb3h1_groups[] = {"usb3h1_grp"};
+static const char * const extint16_groups[] = {"extint16_grp"};
+static const char * const extint5_groups[] = {"extint5_grp"};
+static const char * const tsif0_groups[] = {"tsif0_grp"};
+static const char * const tsif1_groups[] = {"tsif1_grp"};
+static const char * const cfg_groups[] = {"cfg_grp"};
+static const char * const uart0_groups[] = {"uart0_grp"};
+static const char * const uart1_groups[] = {"uart1_grp"};
+static const char * const uart2_groups[] = {"uart2_grp"};
+static const char * const pl244_groups[] = {"pl244_grp"};
+static const char * const trace_groups[] = {"trace_grp"};
+static const char * const memcs_groups[] = {"memcs_grp"};
+static const char * const cap_groups[] = {"cap_grp"};
+static const char * const smt_groups[] = {"smt_grp"};
+
+static const struct mb86s70_pmx_function mb86s73_pmx_funcs[] = {
+	{
+		.prog_val = 0x1,
+		.name = "extint5",
+		.groups = extint5_groups,
+		.num_groups = ARRAY_SIZE(extint5_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "pcie0",
+		.groups = pcie0_groups,
+		.num_groups = ARRAY_SIZE(pcie0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb3h0",
+		.groups = usb3h0_groups,
+		.num_groups = ARRAY_SIZE(usb3h0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb2h0",
+		.groups = usb2h0_groups,
+		.num_groups = ARRAY_SIZE(usb2h0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb2d0",
+		.groups = usb2d0_groups,
+		.num_groups = ARRAY_SIZE(usb2d0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "sdh30",
+		.groups = sdh30_groups,
+		.num_groups = ARRAY_SIZE(sdh30_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "emmc0",
+		.groups = emmc0_groups,
+		.num_groups = ARRAY_SIZE(emmc0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "hsspi0",
+		.groups = hsspi0_groups,
+		.num_groups = ARRAY_SIZE(hsspi0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "gmacd0",
+		.groups = gmacd0_groups,
+		.num_groups = ARRAY_SIZE(gmacd0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "gmacm0",
+		.groups = gmacm0_groups,
+		.num_groups = ARRAY_SIZE(gmacm0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "i2s0",
+		.groups = i2s0_groups,
+		.num_groups = ARRAY_SIZE(i2s0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "other0",
+		.groups = other0_groups,
+		.num_groups = ARRAY_SIZE(other0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "jtag0",
+		.groups = jtag0_groups,
+		.num_groups = ARRAY_SIZE(jtag0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "pcie1",
+		.groups = pcie1_groups,
+		.num_groups = ARRAY_SIZE(pcie1_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb3h1",
+		.groups = usb3h1_groups,
+		.num_groups = ARRAY_SIZE(usb3h1_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "cfg",
+		.groups = cfg_groups,
+		.num_groups = ARRAY_SIZE(cfg_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "uart0",
+		.groups = uart0_groups,
+		.num_groups = ARRAY_SIZE(uart0_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "uart1",
+		.groups = uart1_groups,
+		.num_groups = ARRAY_SIZE(uart1_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "uart2",
+		.groups = uart2_groups,
+		.num_groups = ARRAY_SIZE(uart2_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "trace",
+		.groups = trace_groups,
+		.num_groups = ARRAY_SIZE(trace_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "pl244",
+		.groups = pl244_groups,
+		.num_groups = ARRAY_SIZE(pl244_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "smt",
+		.groups = smt_groups,
+		.num_groups = ARRAY_SIZE(smt_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "memcs",
+		.groups = memcs_groups,
+		.num_groups = ARRAY_SIZE(memcs_groups),
+	},
+};
+
+static const struct mb86s70_pmx_function mb86s70_pmx_funcs[] = {
+	{
+		.prog_val = 0x2,
+		.name = "extint16",
+		.groups = extint16_groups,
+		.num_groups = ARRAY_SIZE(extint16_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "tsif0",
+		.groups = tsif0_groups,
+		.num_groups = ARRAY_SIZE(tsif0_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "tsif1",
+		.groups = tsif1_groups,
+		.num_groups = ARRAY_SIZE(tsif1_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "uart1",
+		.groups = uart1_groups,
+		.num_groups = ARRAY_SIZE(uart1_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "uart2",
+		.groups = uart2_groups,
+		.num_groups = ARRAY_SIZE(uart2_groups),
+	},
+	{
+		.prog_val = 0x5,
+		.name = "pl244",
+		.groups = pl244_groups,
+		.num_groups = ARRAY_SIZE(pl244_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "trace",
+		.groups = trace_groups,
+		.num_groups = ARRAY_SIZE(trace_groups),
+	},
+	{
+		.prog_val = 0x4,
+		.name = "memcs",
+		.groups = memcs_groups,
+		.num_groups = ARRAY_SIZE(memcs_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "capture",
+		.groups = cap_groups,
+		.num_groups = ARRAY_SIZE(cap_groups),
+	}
+};
+
+static int
+mb86s70_pmx_get_functions_count(struct pinctrl_dev *pctl)
+{
+	return func_count;
+}
+
+static const char *
+mb86s70_pmx_get_function_name(struct pinctrl_dev *pctl, unsigned selector)
+{
+	return mb86s7x_pmx_funcs[selector].name;
+}
+
+static int
+mb86s70_pmx_get_function_groups(struct pinctrl_dev *pctl,
+				unsigned selector, const char * const **groups,
+				unsigned * const num_groups)
+{
+	*groups = mb86s7x_pmx_funcs[selector].groups;
+	*num_groups = mb86s7x_pmx_funcs[selector].num_groups;
+
+	return 0;
+}
+
+static int
+mb86s70_pmx_enable(struct pinctrl_dev *pctl,
+		   unsigned func_selector, unsigned group_selector)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	unsigned long flags;
+	const unsigned *pins;
+	int i, j;
+
+	if (group_selector >= grp_count) {
+		pr_err("%s:%d\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	j = mb86s7x_pgrps[group_selector].num_pins;
+	pins = mb86s7x_pgrps[group_selector].pins;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+
+	/* Busy if any pin in the same 'bunch' is taken */
+	for (i = 0; i < j; i++) {
+		u32 val;
+		int p = pins[i] / 4 * 4;
+
+		if (pins[i] >= PINS_VIRT) /* Not for virtual pins */
+			continue;
+
+		val = readl(pchip->base + p);
+		/* skip if no change needed */
+		if (val == mb86s7x_pmx_funcs[func_selector].prog_val)
+			continue;
+
+		if (pchip->pin_busy[p]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p);
+			goto busy_exit;
+		}
+
+		if (pchip->pin_busy[p + 1]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p+1);
+			goto busy_exit;
+		}
+
+		if (p == 64)
+			continue;
+
+		if (pchip->pin_busy[p + 2]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p+2);
+			goto busy_exit;
+		}
+
+		if (pchip->pin_busy[p + 3]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p+3);
+			goto busy_exit;
+		}
+
+		continue;
+busy_exit:
+		spin_unlock_irqrestore(&pchip->lock, flags);
+		pr_err("%s:%d Take a look!\n", __func__, __LINE__);
+		return -EBUSY;
+	}
+
+	pr_debug("Going to enable %s on pins -",
+		 mb86s7x_pmx_funcs[func_selector].name);
+	for (i = 0; i < j; i++) {
+		int p = pins[i];
+
+		pr_debug(" %d", p);
+		pchip->pin_busy[p] = true;
+		if (p < PINS_VIRT) /* Not for virtual pins */
+			writel(mb86s7x_pmx_funcs[func_selector].prog_val,
+			       pchip->base + p / 4 * 4);
+	}
+
+	spin_unlock_irqrestore(&pchip->lock, flags);
+	pr_debug("\n");
+
+	return 0;
+}
+
+static void
+mb86s70_pmx_disable(struct pinctrl_dev *pctl,
+		    unsigned func_selector, unsigned group_selector)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	unsigned long flags;
+	const unsigned *pins;
+	int i, j;
+
+	if (group_selector >= grp_count) {
+		pr_err("%s:%d\n", __func__, __LINE__);
+		return;
+	}
+
+	j = mb86s7x_pgrps[group_selector].num_pins;
+	pins = mb86s7x_pgrps[group_selector].pins;
+
+	pr_debug("Going to disable %s on pins -",
+		 mb86s7x_pmx_funcs[func_selector].name);
+	spin_lock_irqsave(&pchip->lock, flags);
+	for (i = 0; i < j; i++) {
+		pr_debug(" %d", pins[i]);
+		pchip->pin_busy[pins[i]] = false;
+	}
+	spin_unlock_irqrestore(&pchip->lock, flags);
+	pr_debug("\n");
+}
+
+static int
+mb86s70_pmx_gpio_set_direction(struct pinctrl_dev *pctl,
+			       struct pinctrl_gpio_range *range,
+			       unsigned pin, bool input)
+{
+	struct gpio_chip *gc = range->gc;
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+						struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	u32 off, bit, val;
+
+	if (pin >= 64)
+		return -EINVAL;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	bit = (pin - gc->base) % 8;
+	off = (pin - gc->base) / 8 * 4;
+	val = readl(gchip->base + DDR(off));
+	if (input)
+		val &= ~(1 << bit);
+	else
+		val |= (1 << bit);
+	writel(val, gchip->base + DDR(off));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static int
+mb86s70_pmx_gpio_request_enable(struct pinctrl_dev *pctl,
+				struct pinctrl_gpio_range *range, unsigned pin)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	struct gpio_chip *gc = range->gc;
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+						 struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	int p = pin / 4 * 4;
+	u32 val, off, bit;
+
+	if (p == 64)
+		return -ENODEV;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+	if (pchip->pin_busy[p] || pchip->pin_busy[p + 1] ||
+			pchip->pin_busy[p + 2] || pchip->pin_busy[p + 3]) {
+		val = readl(pchip->base + p);
+		if (val != 0x1) {
+			spin_unlock_irqrestore(&pchip->lock, flags);
+			return -EBUSY;
+		}
+	}
+
+	pchip->pin_busy[pin] = true;
+	writel(0x1, pchip->base + p);
+	spin_unlock_irqrestore(&pchip->lock, flags);
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	bit = (pin - range->pin_base) % 8;
+	off = (pin - range->pin_base) / 8 * 4;
+	val = readl(gchip->base + PFR(off));
+	val &= ~(1 << bit);
+	writel(val, gchip->base + PFR(off));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static void
+mb86s70_pmx_gpio_disable_free(struct pinctrl_dev *pctl,
+			      struct pinctrl_gpio_range *range, unsigned pin)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	struct gpio_chip *gc = range->gc;
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+						struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	u32 off, bit, val;
+
+	if (pin >= 64)
+		return;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+	pchip->pin_busy[pin] = false;
+	spin_unlock_irqrestore(&pchip->lock, flags);
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	bit = (pin - range->pin_base) % 8;
+	off = (pin - range->pin_base) / 8 * 4;
+	val = readl(gchip->base + PFR(off));
+	val |= (1 << bit);
+	writel(val, gchip->base + PFR(off));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+}
+
+static const struct pinmux_ops mb86s70_pmx_ops = {
+	.get_functions_count	= mb86s70_pmx_get_functions_count,
+	.get_function_name	= mb86s70_pmx_get_function_name,
+	.get_function_groups	= mb86s70_pmx_get_function_groups,
+	.enable			= mb86s70_pmx_enable,
+	.disable		= mb86s70_pmx_disable,
+	.gpio_set_direction	= mb86s70_pmx_gpio_set_direction,
+	.gpio_request_enable	= mb86s70_pmx_gpio_request_enable,
+	.gpio_disable_free	= mb86s70_pmx_gpio_disable_free,
+};
+
+static int
+mb86s70_pin_config_group_get(struct pinctrl_dev *pctl, unsigned group,
+			     unsigned long *config)
+{
+	return -EINVAL;
+}
+
+static int
+mb86s70_pin_config_group_set(struct pinctrl_dev *pctl, unsigned group,
+			     unsigned long *configs, unsigned num_configs)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	unsigned long flags;
+	const unsigned *pin;
+	int i, j, p;
+	u32 val, ds;
+
+	p = mb86s7x_pgrps[group].num_pins;
+	pin = mb86s7x_pgrps[group].pins;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+
+	for (i = 0; i < num_configs; i++) {
+		switch (pinconf_to_config_param(configs[i])) {
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			/* Drive Strength should be 2, 4, 6 or 8 mA */
+			ds = pinconf_to_config_argument(configs[i]);
+			ds = (ds - 2) / 2;
+			for (j = 0; j < p; j++) {
+				/* Clear the Hi-z */
+				val = readl_relaxed(pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+				val = readl_relaxed(pchip->conf_base +
+							CDRV_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				val |= (ds << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							CDRV_PDG(pin[j]));
+			}
+			break;
+		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+			for (j = 0; j < p; j++) {
+				val = readl_relaxed(pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				val |= (0x1 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+			}
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			for (j = 0; j < p; j++) {
+				val = readl_relaxed(pchip->conf_base +
+							PULL_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							PULL_PDG(pin[j]));
+			}
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			for (j = 0; j < p; j++) {
+				val = readl_relaxed(pchip->conf_base +
+							PULL_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				val |= (1 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							PULL_PDG(pin[j]));
+			}
+			break;
+		default:
+			pr_err("%s:%d!!\n", __func__, __LINE__);
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&pchip->lock, flags);
+
+	return 0;
+}
+
+static const struct pinconf_ops mb86s70_conf_ops = {
+	.pin_config_group_get = mb86s70_pin_config_group_get,
+	.pin_config_group_set = mb86s70_pin_config_group_set,
+};
+
+static const struct of_device_id mb86s70_pinmux_dt_ids[] = {
+	{.compatible = "fujitsu,mb86s70-pinctrl", .data = (void *)PMUX_MB86S70},
+	{.compatible = "fujitsu,mb86s73-pinctrl", .data = (void *)PMUX_MB86S73},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mb86s70_pinmux_dt_ids);
+
+static int mb86s70_pinmux_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	struct mb86s70_pmux_chip *pchip;
+	struct resource *res;
+	int i, type;
+
+	device = of_match_device(mb86s70_pinmux_dt_ids, &pdev->dev);
+	if (!device)
+		return -ENODEV;
+
+	type = (int)device->data;
+
+	/* reserve memory space for pmux chip */
+	pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL);
+	if (pchip == NULL) {
+		dev_err(&pdev->dev, "can't allocate pinmux chip data.\n");
+		return -ENOMEM;
+	}
+	pchip->dev = &pdev->dev;
+
+	/* initiate pmux chip structure */
+	platform_set_drvdata(pdev, pchip);
+
+	/* IO resource */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pchip->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pchip->base))
+		return PTR_ERR(pchip->base);
+
+	/* initiate lock */
+	spin_lock_init(&pchip->lock);
+
+	pchip->desc.name = dev_name(&pdev->dev);
+	pchip->desc.npins = MB86S70_PMUX_PINS;
+	pchip->desc.pins = pchip->pins;
+	pchip->desc.pctlops = &mb86s70_pctrl_ops;
+	pchip->desc.pmxops = &mb86s70_pmx_ops;
+	pchip->desc.owner = THIS_MODULE;
+	if (type == PMUX_MB86S73) {
+		pchip->desc.confops = &mb86s70_conf_ops;
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		pchip->conf_base = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(pchip->conf_base))
+			return PTR_ERR(pchip->conf_base);
+		mb86s7x_pmx_funcs = mb86s73_pmx_funcs;
+		func_count = ARRAY_SIZE(mb86s73_pmx_funcs);
+		mb86s7x_pgrps = mb86s73_pgrps;
+		grp_count = ARRAY_SIZE(mb86s73_pgrps);
+	} else {
+		mb86s7x_pmx_funcs = mb86s70_pmx_funcs;
+		func_count = ARRAY_SIZE(mb86s70_pmx_funcs);
+		mb86s7x_pgrps = mb86s70_pgrps;
+		grp_count = ARRAY_SIZE(mb86s70_pgrps);
+	}
+
+	for (i = 0; i < MB86S70_PMUX_PINS; i++) {
+		pchip->pin_busy[i] = false;
+		pchip->pins[i].number = i;
+		pchip->pins[i].name = &pchip->pin_names[5 * i];
+		snprintf(&pchip->pin_names[5 * i], 5, "PD%d", i);
+	}
+
+	pchip->pctl = pinctrl_register(&pchip->desc, &pdev->dev, pchip);
+	if (!pchip->pctl) {
+		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mb86s70_gpio_dt_ids[] = {
+	{ .compatible = "fujitsu,mb86s7x-gpio" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
+
+static struct platform_driver mb86s70_gpio_driver = {
+	.probe     = mb86s70_gpio_probe,
+	.driver    = {
+		.name  = "mb86s70-gpio",
+		.owner = THIS_MODULE,
+		.of_match_table = mb86s70_gpio_dt_ids,
+	},
+};
+
+static struct platform_driver mb86s70_pinmux_driver = {
+	.probe     = mb86s70_pinmux_probe,
+	.driver    = {
+		.name  = "mb86s70-pinmux",
+		.owner = THIS_MODULE,
+		.of_match_table = mb86s70_pinmux_dt_ids,
+	},
+};
+
+static int __init mb86s70_pins_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&mb86s70_pinmux_driver);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&mb86s70_gpio_driver);
+}
+subsys_initcall(mb86s70_pins_init);
+
+MODULE_DESCRIPTION("MB86S7x PinCtrl Driver");
+MODULE_ALIAS("platform:mb86s70-pinmux");
+MODULE_ALIAS("platform:mb86s70-gpio");
+MODULE_LICENSE("GPL");
-- 
1.8.1.2

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

WARNING: multiple messages have this Message-ID (diff)
From: mollie.wu@linaro.org (Mollie Wu)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 5/8] pinctrl: add driver for MB86S7x
Date: Sun, 13 Jul 2014 14:31:07 +0800	[thread overview]
Message-ID: <1405233067-4725-1-git-send-email-mollie.wu@linaro.org> (raw)
In-Reply-To: <message-id-of-cover-letter>

The mb86s70 and mb86s73 Fujitsu SoCs differ in that the latter provide a pinmux.
GPIOs are supported on top of Pinctrl api.

Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Tetsuya Takinishi <t.takinishi@jp.fujitsu.com>
Signed-off-by: Mollie Wu <mollie.wu@linaro.org>
---
 .../bindings/gpio/fujitsu,mb86s7x-gpio.txt         |   22 +
 .../bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt   |   30 +
 drivers/pinctrl/Kconfig                            |    5 +
 drivers/pinctrl/Makefile                           |    1 +
 drivers/pinctrl/pinctrl-mb86s7x.c                  | 1281 ++++++++++++++++++++
 5 files changed, 1339 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt
 create mode 100644 Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt
 create mode 100644 drivers/pinctrl/pinctrl-mb86s7x.c

diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt
new file mode 100644
index 0000000..c262efa
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s7x-gpio.txt
@@ -0,0 +1,22 @@
+Fujitsu MB86S7x GPIO Controller
+-------------------------------
+
+Required properties:
+- compatible: Should be "fujitsu,mb86s7x-gpio"
+- gpio-controller: Marks the device node as a gpio controller.
+- #gpio-cells: Should be <2>. The first cell is the pin number and the
+  second cell is used to specify optional parameters:
+   - bit 0 specifies polarity (0 for normal, 1 for inverted).
+
+GPIO ranges are specified as described in
+Documentation/devicetree/bindings/gpio/gpio.txt
+
+Examples:
+	gpio0: mb86s70_gpio0 {
+		compatible = "fujitsu,mb86s7x-gpio";
+		reg = <0 0x31000000 0x10000>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		clocks = <&clk_alw_2_1>;
+	};
diff --git a/Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt
new file mode 100644
index 0000000..ce2011b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fujitsu,mb86s7x-pinctrl.txt
@@ -0,0 +1,30 @@
+Fujitsu MB86S7x Pin Controller
+------------------------------
+
+Required properties:
+- compatible: Should be "fujitsu,mb86s70-pinctrl" or "fujitsu,mb86s73-pinctrl"
+- reg: Should contain the register physical address and length for the
+  pin controller.
+- #gpio-range-cells: Should be 3
+
+Optional subnode-properties:
+- mb86s7x,function: String specifying the function name.
+- mb86s7x,drvst: Drive strength needed for pins to operate in that mode.
+    0 (Hi-z), 2mA, 4mA, 6mA or 8mA
+- mb86s7x,pullup: Should be 0 for Pull-Down or non-zero for Pull-Up
+
+Examples:
+	pinctrl: pinctrl at 2a4d0000 {
+		compatible = "fujitsu,mb86s73-pinctrl";
+		reg = <0 0x2a4d0000 0x1000>, <0 0x312e0000 0x1000>;
+		#gpio-range-cells = <3>;
+
+		hsspi0_pins_active: hsspi0_active {
+			mb86s7x,function = "hsspi0";
+			mb86s7x,drvst = <8>; /* in mA */
+		};
+		hsspi0_pins_sleep: hsspi0_sleep {
+			mb86s7x,function = "hsspi0";
+			mb86s7x,drvst = <0>; /* Implies Hi-z */
+		};
+	};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 0042ccb..1f053fc 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -213,6 +213,11 @@ config PINCTRL_FALCON
 	depends on SOC_FALCON
 	depends on PINCTRL_LANTIQ
 
+config PINCTRL_MB86S7X
+	bool
+	select PINMUX
+	select GENERIC_PINCONF
+
 config PINCTRL_MXS
 	bool
 	select PINMUX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c4b5d40..edcb823 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q)	+= pinctrl-imx6dl.o
 obj-$(CONFIG_PINCTRL_IMX6SL)	+= pinctrl-imx6sl.o
 obj-$(CONFIG_PINCTRL_IMX6SX)	+= pinctrl-imx6sx.o
 obj-$(CONFIG_PINCTRL_FALCON)	+= pinctrl-falcon.o
+obj-$(CONFIG_PINCTRL_MB86S7X)	+= pinctrl-mb86s7x.o
 obj-$(CONFIG_PINCTRL_MXS)	+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)	+= pinctrl-imx23.o
 obj-$(CONFIG_PINCTRL_IMX25)	+= pinctrl-imx25.o
diff --git a/drivers/pinctrl/pinctrl-mb86s7x.c b/drivers/pinctrl/pinctrl-mb86s7x.c
new file mode 100644
index 0000000..74c72ec8
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-mb86s7x.c
@@ -0,0 +1,1281 @@
+/*
+ *  linux/drivers/pinctrl/pinctrl-mb86s7x.c
+ *
+ *  Copyright (C) 2014 Fujitsu Semiconductor Limited
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#define PDR(x)	(0x0 + x)
+#define DDR(x)	(0x10 + x)
+#define PFR(x)	(0x20 + x)
+
+#define CDRV_PDG(x)	(0x0 + ((x) / 16) * 4)
+#define FORCEZ_PDG(x)	(0x100 + ((x) / 16) * 4)
+#define PULL_PDG(x)	(0x200 + ((x) / 16) * 4)
+#define PIN_OFF(x)	(((x) % 16) * 2)
+
+#define PMUX_MB86S70	0
+#define PMUX_MB86S73	1
+
+/* Virtual pin numbers start so that reg offset calculations get simple */
+enum {
+	PINS_VIRT = 128,
+	PINS_PCIE0 = PINS_VIRT,
+	PINS_HOLE1,
+	PINS_USB3H0,
+	PINS_HOLE2,
+	PINS_USB2H0,
+	PINS_USB2D0,
+	PINS_SDH30,
+	PINS_HOLE3,
+	PINS_EMMC0,
+	PINS_HSSPI0,
+	PINS_GMACD0,
+	PINS_GMACM0,
+	PINS_I2S0,
+	PINS_UART0,
+	PINS_OTHER0,
+	PINS_JTAG0,
+	PINS_PCIE1,
+	PINS_HOLE4,
+	PINS_USB3H1,
+	MB86S70_PMUX_PINS,
+};
+
+struct mb86s70_gpio_chip {
+	spinlock_t lock; /* for goio regs */
+	struct clk *clk;
+	void __iomem *base;
+	struct gpio_chip gc;
+};
+
+static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned offset)
+{
+	int ret = pinctrl_request_gpio(gc->base + offset);
+
+	if (!ret) {
+		struct mb86s70_gpio_chip *gchip = container_of(gc,
+						struct mb86s70_gpio_chip, gc);
+		unsigned long flags;
+		u32 val;
+
+		spin_lock_irqsave(&gchip->lock, flags);
+		val = readl(gchip->base + PFR(offset / 8 * 4));
+		val &= ~(1 << (offset % 8)); /* as gpio-port */
+		writel(val, gchip->base + PFR(offset / 8 * 4));
+		spin_unlock_irqrestore(&gchip->lock, flags);
+	}
+
+	return ret;
+}
+
+static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+					struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	val = readl(gchip->base + PFR(offset / 8 * 4));
+	val |= (1 << (offset % 8)); /* as peri-port */
+	writel(val, gchip->base + PFR(offset / 8 * 4));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	pinctrl_free_gpio(gc->base + offset);
+}
+
+static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	unsigned char val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	val = readl(gchip->base + DDR(offset / 8 * 4));
+	val &= ~(1 << (offset % 8));
+	writel(val, gchip->base + DDR(offset / 8 * 4));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
+					 unsigned offset, int value)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	unsigned char val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+
+	val = readl(gchip->base + PDR(offset / 8 * 4));
+	if (value)
+		val |= (1 << (offset % 8));
+	else
+		val &= ~(1 << (offset % 8));
+	writel(val, gchip->base + PDR(offset / 8 * 4));
+
+	val = readl(gchip->base + DDR(offset / 8 * 4));
+	val |= (1 << (offset % 8));
+	writel(val, gchip->base + DDR(offset / 8 * 4));
+
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned char val;
+
+	val = readl(gchip->base + PDR(offset / 8 * 4));
+	val &= (1 << (offset % 8));
+	return val ? 1 : 0;
+}
+
+static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+	struct mb86s70_gpio_chip *gchip =
+			container_of(gc, struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	unsigned char val;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+
+	val = readl(gchip->base + PDR(offset / 8 * 4));
+	if (value)
+		val |= (1 << (offset % 8));
+	else
+		val &= ~(1 << (offset % 8));
+	writel(val, gchip->base + PDR(offset / 8 * 4));
+
+	spin_unlock_irqrestore(&gchip->lock, flags);
+}
+
+static int mb86s70_gpio_probe(struct platform_device *pdev)
+{
+	struct mb86s70_gpio_chip *gchip;
+	struct resource *res;
+	int ret;
+
+	gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
+	if (gchip == NULL)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, gchip);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	gchip->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gchip->base))
+		return PTR_ERR(gchip->base);
+
+	gchip->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(gchip->clk))
+		return PTR_ERR(gchip->clk);
+
+	clk_prepare_enable(gchip->clk);
+
+	spin_lock_init(&gchip->lock);
+
+	gchip->gc.direction_output = mb86s70_gpio_direction_output;
+	gchip->gc.direction_input = mb86s70_gpio_direction_input;
+	gchip->gc.request = mb86s70_gpio_request;
+	gchip->gc.free = mb86s70_gpio_free;
+	gchip->gc.get = mb86s70_gpio_get;
+	gchip->gc.set = mb86s70_gpio_set;
+	gchip->gc.label = dev_name(&pdev->dev);
+	gchip->gc.ngpio = 32;
+	gchip->gc.owner = THIS_MODULE;
+	gchip->gc.dev = &pdev->dev;
+	gchip->gc.base = -1;
+
+	ret = gpiochip_add(&gchip->gc);
+	if (ret) {
+		dev_err(&pdev->dev, "couldn't register gpio driver\n");
+		clk_disable_unprepare(gchip->clk);
+	}
+
+	return ret;
+}
+
+struct mb86s70_pmux_chip {
+	spinlock_t lock; /* mux regs */
+	struct device *dev;
+	void __iomem *base;
+	void __iomem *conf_base;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_desc desc;
+	bool pin_busy[MB86S70_PMUX_PINS];
+	char pin_names[5 * MB86S70_PMUX_PINS];
+	struct pinctrl_pin_desc pins[MB86S70_PMUX_PINS];
+};
+
+struct mb86s70_pmx_grp {
+	const char *name;
+	const unsigned *pins;
+	const unsigned num_pins;
+};
+
+struct mb86s70_pmx_function {
+	const unsigned num_groups;
+	unsigned prog_val;
+	const char *name;
+
+	const char *const *groups;
+};
+
+static const unsigned extint16_s70[] = {0};
+static const unsigned tsif0_s70[] = {16, 17, 18, 19};
+static const unsigned tsif1_s70[] = {16, 17, 18, 19};
+static const unsigned uart1_s70[] = {56, 57, 58, 59};
+static const unsigned uart2_s70[] = {60, 61, 62, 63};
+static const unsigned pl244_s70[] = {40, 41, 42, 43, 44, 45, 46, 47, 48,
+					49, 50, 51, 52, 53, 54, 55, 56, 57,
+					58, 59, 60, 61, 62};
+static const unsigned trace_s70[] = {24, 25, 26, 27, 28, 29, 30, 31, 32,
+					33, 34, 35, 36, 37, 38, 39, 64, 65};
+static const unsigned memcs_s70[] = {16, 17, 18, 19, 20, 21, 22, 23, 24,
+					25, 26, 27, 28, 29, 30, 31, 32, 33,
+					34, 35, 36, 37, 38, 39, 40, 41, 42,
+					43, 44, 45, 46, 47, 48, 49, 50, 51,
+					52, 53, 54, 55, 56, 57, 58, 59, 60,
+					61, 62, 63, 64, 65};
+static const unsigned cap_s70[] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+					26, 27, 28, 29, 30, 31, 32, 33, 34,
+					35, 36, 37, 38, 39, 40, 41, 42, 43,
+					44, 45, 46, 47};
+
+static const struct mb86s70_pmx_grp mb86s70_pgrps[] = {
+	{
+		.name = "extint16_grp",
+		.pins = extint16_s70,
+		.num_pins = ARRAY_SIZE(extint16_s70),
+	},
+	{
+		.name = "tsif0_grp",
+		.pins = tsif0_s70,
+		.num_pins = ARRAY_SIZE(tsif0_s70),
+	},
+	{
+		.name = "tsif1_grp",
+		.pins = tsif1_s70,
+		.num_pins = ARRAY_SIZE(tsif1_s70),
+	},
+	{
+		.name = "uart1_grp",
+		.pins = uart1_s70,
+		.num_pins = ARRAY_SIZE(uart1_s70),
+	},
+	{
+		.name = "uart2_grp",
+		.pins = uart2_s70,
+		.num_pins = ARRAY_SIZE(uart2_s70),
+	},
+	{
+		.name = "pl244_grp",
+		.pins = pl244_s70,
+		.num_pins = ARRAY_SIZE(pl244_s70),
+	},
+	{
+		.name = "trace_grp",
+		.pins = trace_s70,
+		.num_pins = ARRAY_SIZE(trace_s70),
+	},
+	{
+		.name = "memcs_grp",
+		.pins = memcs_s70,
+		.num_pins = ARRAY_SIZE(memcs_s70),
+	},
+	{
+		.name = "cap_grp",
+		.pins = cap_s70,
+		.num_pins = ARRAY_SIZE(cap_s70),
+	}
+};
+
+static const unsigned pcie0_s73[] = {PINS_PCIE0};
+static const unsigned usb3h0_s73[] = {PINS_USB3H0};
+static const unsigned usb2h0_s73[] = {PINS_USB2H0};
+static const unsigned usb2d0_s73[] = {PINS_USB2D0};
+static const unsigned sdh30_s73[] = {PINS_SDH30};
+static const unsigned emmc0_s73[] = {PINS_EMMC0};
+static const unsigned hsspi0_s73[] = {PINS_HSSPI0};
+static const unsigned gmacd0_s73[] = {PINS_GMACD0};
+static const unsigned gmacm0_s73[] = {PINS_GMACM0};
+static const unsigned i2s0_s73[] = {PINS_I2S0};
+static const unsigned other0_s73[] = {PINS_OTHER0};
+static const unsigned jtag0_s73[] = {PINS_JTAG0};
+static const unsigned pcie1_s73[] = {PINS_PCIE1};
+static const unsigned usb3h1_s73[] = {PINS_USB3H1};
+static const unsigned extint5_s73[] = {37};
+static const unsigned cfg_s73[] = {56, 57, 58, 59, 60, 61, 62, 63};
+static const unsigned uart0_s73[] = {8, 11, 12, 15};
+static const unsigned uart1_s73[] = {16, 17, 18, 19, 20, 21, 22, 23};
+static const unsigned uart2_s73[] = {24, 25, 26, 27, 28, 29, 30, 31};
+static const unsigned trace_s73[] = {44, 45, 46, 47, 48, 49, 50,
+					51, 52, 53, 54, 55, 56, 57,
+					58, 59, 60, 61};
+static const unsigned smt_s73[] = {56, 57, 58, 59, 60, 61};
+static const unsigned memcs_s73[] = {8, 9, 10, 11, 12, 13, 14, 15,
+					16, 17, 18, 19, 20, 21, 22,
+					23, 24, 25, 26, 27, 28, 29,
+					30, 31, 32, 33, 34, 35, 36,
+					37, 38, 39, 40, 41, 42, 43,
+					44, 45, 46, 47, 48, 49, 50,
+					51, 52, 53, 54, 55};
+static const unsigned pl244_s73[] = {8, 9, 10, 11, 12, 13, 14, 15,
+					16, 17, 18, 19, 20, 21, 22,
+					23, 24, 25, 26, 27, 28, 29,
+					30, 31};
+
+static const struct mb86s70_pmx_grp mb86s73_pgrps[] = {
+	{
+		.name = "extint5_grp",
+		.pins = extint5_s73,
+		.num_pins = ARRAY_SIZE(extint5_s73),
+	},
+	{
+		.name = "pcie0_grp",
+		.pins = pcie0_s73,
+		.num_pins = ARRAY_SIZE(pcie0_s73),
+	},
+	{
+		.name = "usb3h0_grp",
+		.pins = usb3h0_s73,
+		.num_pins = ARRAY_SIZE(usb3h0_s73),
+	},
+	{
+		.name = "usb2h0_grp",
+		.pins = usb2h0_s73,
+		.num_pins = ARRAY_SIZE(usb2h0_s73),
+	},
+	{
+		.name = "usb2d0_grp",
+		.pins = usb2d0_s73,
+		.num_pins = ARRAY_SIZE(usb2d0_s73),
+	},
+	{
+		.name = "sdh30_grp",
+		.pins = sdh30_s73,
+		.num_pins = ARRAY_SIZE(sdh30_s73),
+	},
+	{
+		.name = "emmc0_grp",
+		.pins = emmc0_s73,
+		.num_pins = ARRAY_SIZE(emmc0_s73),
+	},
+	{
+		.name = "hsspi0_grp",
+		.pins = hsspi0_s73,
+		.num_pins = ARRAY_SIZE(hsspi0_s73),
+	},
+	{
+		.name = "gmacd0_grp",
+		.pins = gmacd0_s73,
+		.num_pins = ARRAY_SIZE(gmacd0_s73),
+	},
+	{
+		.name = "gmacm0_grp",
+		.pins = gmacm0_s73,
+		.num_pins = ARRAY_SIZE(gmacm0_s73),
+	},
+	{
+		.name = "i2s0_grp",
+		.pins = i2s0_s73,
+		.num_pins = ARRAY_SIZE(i2s0_s73),
+	},
+	{
+		.name = "other0_grp",
+		.pins = other0_s73,
+		.num_pins = ARRAY_SIZE(other0_s73),
+	},
+	{
+		.name = "jtag0_grp",
+		.pins = jtag0_s73,
+		.num_pins = ARRAY_SIZE(jtag0_s73),
+	},
+	{
+		.name = "pcie1_grp",
+		.pins = pcie1_s73,
+		.num_pins = ARRAY_SIZE(pcie1_s73),
+	},
+	{
+		.name = "usb3h1_grp",
+		.pins = usb3h1_s73,
+		.num_pins = ARRAY_SIZE(usb3h1_s73),
+	},
+	{
+		.name = "cfg_grp",
+		.pins = cfg_s73,
+		.num_pins = ARRAY_SIZE(cfg_s73),
+	},
+	{
+		.name = "uart0_grp",
+		.pins = uart0_s73,
+		.num_pins = ARRAY_SIZE(uart0_s73),
+	},
+	{
+		.name = "uart1_grp",
+		.pins = uart1_s73,
+		.num_pins = ARRAY_SIZE(uart1_s73),
+	},
+	{
+		.name = "uart2_grp",
+		.pins = uart2_s73,
+		.num_pins = ARRAY_SIZE(uart2_s73),
+	},
+	{
+		.name = "trace_grp",
+		.pins = trace_s73,
+		.num_pins = ARRAY_SIZE(trace_s73),
+	},
+	{
+		.name = "smt_grp",
+		.pins = smt_s73,
+		.num_pins = ARRAY_SIZE(smt_s73),
+	},
+	{
+		.name = "memcs_grp",
+		.pins = memcs_s73,
+		.num_pins = ARRAY_SIZE(memcs_s73),
+	},
+	{
+		.name = "pl244_grp",
+		.pins = pl244_s73,
+		.num_pins = ARRAY_SIZE(pl244_s73),
+	},
+};
+
+static int func_count, grp_count;
+static const struct mb86s70_pmx_grp *mb86s7x_pgrps;
+static const struct mb86s70_pmx_function *mb86s7x_pmx_funcs;
+
+static int mb86s70_pctrl_get_groups_count(struct pinctrl_dev *pctl)
+{
+	return grp_count;
+}
+
+static const char *
+mb86s70_pctrl_get_group_name(struct pinctrl_dev *pctl, unsigned selector)
+{
+	return mb86s7x_pgrps[selector].name;
+}
+
+static int
+mb86s70_pctrl_get_group_pins(struct pinctrl_dev *pctl, unsigned selector,
+			     const unsigned **pins, unsigned *num_pins)
+{
+	*pins = mb86s7x_pgrps[selector].pins;
+	*num_pins = mb86s7x_pgrps[selector].num_pins;
+
+	return 0;
+}
+
+static int
+mb86s70_pctrl_dt_node_to_map(struct pinctrl_dev *pctl,
+			     struct device_node *node,
+			     struct pinctrl_map **map, unsigned *num_maps)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	int ret, i, configlen = 0;
+	unsigned long *pinconfig;
+	const char *function;
+	const char *group;
+	u32 val;
+
+	*map = NULL;
+	*num_maps = 0;
+
+	ret = of_property_read_string(node, "mb86s7x,function", &function);
+	if (ret) {
+		dev_err(pchip->dev,
+			"missing mb86s7x,function property in node %s\n",
+			node->name);
+		return -EINVAL;
+	}
+
+	*map = devm_kzalloc(pchip->dev,
+			    2 * sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (!*map)
+		return -ENOMEM;
+
+	for (i = 0; i < func_count; i++)
+		if (!strcmp(mb86s7x_pmx_funcs[i].name, function))
+			break;
+
+	if (i == func_count) {
+		dev_err(pchip->dev, "function(%s) not found!\n", function);
+		return -EINVAL;
+	}
+	group = mb86s7x_pmx_funcs[i].groups[0];
+
+	(*map)[0].type = PIN_MAP_TYPE_MUX_GROUP;
+	(*map)[0].data.mux.group = group;
+	(*map)[0].data.mux.function = function;
+	*num_maps = 1;
+
+	if (of_find_property(node, "mb86s7x,drvst", NULL))
+		configlen++;
+	if (of_find_property(node, "mb86s7x,pullup", NULL))
+		configlen++;
+
+	if (configlen == 0) /* For S70 */
+		return 0;
+
+	i = 0;
+	pinconfig = devm_kzalloc(pchip->dev,
+				 configlen * sizeof(*pinconfig), GFP_KERNEL);
+
+	if (!of_property_read_u32(node, "mb86s7x,drvst", &val))
+		pinconfig[i++] =
+			pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
+						 val);
+
+	if (!of_property_read_u32(node, "mb86s7x,pullup", &val)) {
+		enum pin_config_param pull;
+
+		if (val)
+			pull = PIN_CONFIG_BIAS_PULL_UP;
+		else
+			pull = PIN_CONFIG_BIAS_PULL_DOWN;
+		pinconfig[i++] = pinconf_to_config_packed(pull, 0);
+	}
+
+	(*map)[1].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+	(*map)[1].data.configs.group_or_pin = group;
+	(*map)[1].data.configs.configs = pinconfig;
+	(*map)[1].data.configs.num_configs = configlen;
+
+	*num_maps = 2;
+
+	return 0;
+}
+
+static void
+mb86s70_pctrl_dt_free_map(struct pinctrl_dev *pctl,
+			  struct pinctrl_map *map, unsigned num_maps)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	int i;
+
+	for (i = 0; i < num_maps; i++)
+		if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+			devm_kfree(pchip->dev, map[i].data.configs.configs);
+
+	devm_kfree(pchip->dev, map);
+}
+
+static const struct pinctrl_ops mb86s70_pctrl_ops = {
+	.get_groups_count	= mb86s70_pctrl_get_groups_count,
+	.get_group_name		= mb86s70_pctrl_get_group_name,
+	.get_group_pins		= mb86s70_pctrl_get_group_pins,
+	.dt_node_to_map		= mb86s70_pctrl_dt_node_to_map,
+	.dt_free_map		= mb86s70_pctrl_dt_free_map,
+};
+
+static const char * const pcie0_groups[] = {"pcie0_grp"};
+static const char * const usb3h0_groups[] = {"usb3h0_grp"};
+static const char * const usb2h0_groups[] = {"usb2h0_grp"};
+static const char * const usb2d0_groups[] = {"usb2d0_grp"};
+static const char * const sdh30_groups[] = {"sdh30_grp"};
+static const char * const emmc0_groups[] = {"emmc0_grp"};
+static const char * const hsspi0_groups[] = {"hsspi0_grp"};
+static const char * const gmacd0_groups[] = {"gmacd0_grp"};
+static const char * const gmacm0_groups[] = {"gmacm0_grp"};
+static const char * const i2s0_groups[] = {"i2s0_grp"};
+static const char * const other0_groups[] = {"other0_grp"};
+static const char * const jtag0_groups[] = {"jtag0_grp"};
+static const char * const pcie1_groups[] = {"pcie1_grp"};
+static const char * const usb3h1_groups[] = {"usb3h1_grp"};
+static const char * const extint16_groups[] = {"extint16_grp"};
+static const char * const extint5_groups[] = {"extint5_grp"};
+static const char * const tsif0_groups[] = {"tsif0_grp"};
+static const char * const tsif1_groups[] = {"tsif1_grp"};
+static const char * const cfg_groups[] = {"cfg_grp"};
+static const char * const uart0_groups[] = {"uart0_grp"};
+static const char * const uart1_groups[] = {"uart1_grp"};
+static const char * const uart2_groups[] = {"uart2_grp"};
+static const char * const pl244_groups[] = {"pl244_grp"};
+static const char * const trace_groups[] = {"trace_grp"};
+static const char * const memcs_groups[] = {"memcs_grp"};
+static const char * const cap_groups[] = {"cap_grp"};
+static const char * const smt_groups[] = {"smt_grp"};
+
+static const struct mb86s70_pmx_function mb86s73_pmx_funcs[] = {
+	{
+		.prog_val = 0x1,
+		.name = "extint5",
+		.groups = extint5_groups,
+		.num_groups = ARRAY_SIZE(extint5_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "pcie0",
+		.groups = pcie0_groups,
+		.num_groups = ARRAY_SIZE(pcie0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb3h0",
+		.groups = usb3h0_groups,
+		.num_groups = ARRAY_SIZE(usb3h0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb2h0",
+		.groups = usb2h0_groups,
+		.num_groups = ARRAY_SIZE(usb2h0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb2d0",
+		.groups = usb2d0_groups,
+		.num_groups = ARRAY_SIZE(usb2d0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "sdh30",
+		.groups = sdh30_groups,
+		.num_groups = ARRAY_SIZE(sdh30_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "emmc0",
+		.groups = emmc0_groups,
+		.num_groups = ARRAY_SIZE(emmc0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "hsspi0",
+		.groups = hsspi0_groups,
+		.num_groups = ARRAY_SIZE(hsspi0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "gmacd0",
+		.groups = gmacd0_groups,
+		.num_groups = ARRAY_SIZE(gmacd0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "gmacm0",
+		.groups = gmacm0_groups,
+		.num_groups = ARRAY_SIZE(gmacm0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "i2s0",
+		.groups = i2s0_groups,
+		.num_groups = ARRAY_SIZE(i2s0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "other0",
+		.groups = other0_groups,
+		.num_groups = ARRAY_SIZE(other0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "jtag0",
+		.groups = jtag0_groups,
+		.num_groups = ARRAY_SIZE(jtag0_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "pcie1",
+		.groups = pcie1_groups,
+		.num_groups = ARRAY_SIZE(pcie1_groups),
+	},
+	{
+		.prog_val = 0x0,
+		.name = "usb3h1",
+		.groups = usb3h1_groups,
+		.num_groups = ARRAY_SIZE(usb3h1_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "cfg",
+		.groups = cfg_groups,
+		.num_groups = ARRAY_SIZE(cfg_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "uart0",
+		.groups = uart0_groups,
+		.num_groups = ARRAY_SIZE(uart0_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "uart1",
+		.groups = uart1_groups,
+		.num_groups = ARRAY_SIZE(uart1_groups),
+	},
+	{
+		.prog_val = 0x1,
+		.name = "uart2",
+		.groups = uart2_groups,
+		.num_groups = ARRAY_SIZE(uart2_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "trace",
+		.groups = trace_groups,
+		.num_groups = ARRAY_SIZE(trace_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "pl244",
+		.groups = pl244_groups,
+		.num_groups = ARRAY_SIZE(pl244_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "smt",
+		.groups = smt_groups,
+		.num_groups = ARRAY_SIZE(smt_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "memcs",
+		.groups = memcs_groups,
+		.num_groups = ARRAY_SIZE(memcs_groups),
+	},
+};
+
+static const struct mb86s70_pmx_function mb86s70_pmx_funcs[] = {
+	{
+		.prog_val = 0x2,
+		.name = "extint16",
+		.groups = extint16_groups,
+		.num_groups = ARRAY_SIZE(extint16_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "tsif0",
+		.groups = tsif0_groups,
+		.num_groups = ARRAY_SIZE(tsif0_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "tsif1",
+		.groups = tsif1_groups,
+		.num_groups = ARRAY_SIZE(tsif1_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "uart1",
+		.groups = uart1_groups,
+		.num_groups = ARRAY_SIZE(uart1_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "uart2",
+		.groups = uart2_groups,
+		.num_groups = ARRAY_SIZE(uart2_groups),
+	},
+	{
+		.prog_val = 0x5,
+		.name = "pl244",
+		.groups = pl244_groups,
+		.num_groups = ARRAY_SIZE(pl244_groups),
+	},
+	{
+		.prog_val = 0x3,
+		.name = "trace",
+		.groups = trace_groups,
+		.num_groups = ARRAY_SIZE(trace_groups),
+	},
+	{
+		.prog_val = 0x4,
+		.name = "memcs",
+		.groups = memcs_groups,
+		.num_groups = ARRAY_SIZE(memcs_groups),
+	},
+	{
+		.prog_val = 0x2,
+		.name = "capture",
+		.groups = cap_groups,
+		.num_groups = ARRAY_SIZE(cap_groups),
+	}
+};
+
+static int
+mb86s70_pmx_get_functions_count(struct pinctrl_dev *pctl)
+{
+	return func_count;
+}
+
+static const char *
+mb86s70_pmx_get_function_name(struct pinctrl_dev *pctl, unsigned selector)
+{
+	return mb86s7x_pmx_funcs[selector].name;
+}
+
+static int
+mb86s70_pmx_get_function_groups(struct pinctrl_dev *pctl,
+				unsigned selector, const char * const **groups,
+				unsigned * const num_groups)
+{
+	*groups = mb86s7x_pmx_funcs[selector].groups;
+	*num_groups = mb86s7x_pmx_funcs[selector].num_groups;
+
+	return 0;
+}
+
+static int
+mb86s70_pmx_enable(struct pinctrl_dev *pctl,
+		   unsigned func_selector, unsigned group_selector)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	unsigned long flags;
+	const unsigned *pins;
+	int i, j;
+
+	if (group_selector >= grp_count) {
+		pr_err("%s:%d\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	j = mb86s7x_pgrps[group_selector].num_pins;
+	pins = mb86s7x_pgrps[group_selector].pins;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+
+	/* Busy if any pin in the same 'bunch' is taken */
+	for (i = 0; i < j; i++) {
+		u32 val;
+		int p = pins[i] / 4 * 4;
+
+		if (pins[i] >= PINS_VIRT) /* Not for virtual pins */
+			continue;
+
+		val = readl(pchip->base + p);
+		/* skip if no change needed */
+		if (val == mb86s7x_pmx_funcs[func_selector].prog_val)
+			continue;
+
+		if (pchip->pin_busy[p]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p);
+			goto busy_exit;
+		}
+
+		if (pchip->pin_busy[p + 1]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p+1);
+			goto busy_exit;
+		}
+
+		if (p == 64)
+			continue;
+
+		if (pchip->pin_busy[p + 2]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p+2);
+			goto busy_exit;
+		}
+
+		if (pchip->pin_busy[p + 3]) {
+			pr_err("%s:%d:%d %d busy\n",
+			       __func__, __LINE__, pins[i], p+3);
+			goto busy_exit;
+		}
+
+		continue;
+busy_exit:
+		spin_unlock_irqrestore(&pchip->lock, flags);
+		pr_err("%s:%d Take a look!\n", __func__, __LINE__);
+		return -EBUSY;
+	}
+
+	pr_debug("Going to enable %s on pins -",
+		 mb86s7x_pmx_funcs[func_selector].name);
+	for (i = 0; i < j; i++) {
+		int p = pins[i];
+
+		pr_debug(" %d", p);
+		pchip->pin_busy[p] = true;
+		if (p < PINS_VIRT) /* Not for virtual pins */
+			writel(mb86s7x_pmx_funcs[func_selector].prog_val,
+			       pchip->base + p / 4 * 4);
+	}
+
+	spin_unlock_irqrestore(&pchip->lock, flags);
+	pr_debug("\n");
+
+	return 0;
+}
+
+static void
+mb86s70_pmx_disable(struct pinctrl_dev *pctl,
+		    unsigned func_selector, unsigned group_selector)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	unsigned long flags;
+	const unsigned *pins;
+	int i, j;
+
+	if (group_selector >= grp_count) {
+		pr_err("%s:%d\n", __func__, __LINE__);
+		return;
+	}
+
+	j = mb86s7x_pgrps[group_selector].num_pins;
+	pins = mb86s7x_pgrps[group_selector].pins;
+
+	pr_debug("Going to disable %s on pins -",
+		 mb86s7x_pmx_funcs[func_selector].name);
+	spin_lock_irqsave(&pchip->lock, flags);
+	for (i = 0; i < j; i++) {
+		pr_debug(" %d", pins[i]);
+		pchip->pin_busy[pins[i]] = false;
+	}
+	spin_unlock_irqrestore(&pchip->lock, flags);
+	pr_debug("\n");
+}
+
+static int
+mb86s70_pmx_gpio_set_direction(struct pinctrl_dev *pctl,
+			       struct pinctrl_gpio_range *range,
+			       unsigned pin, bool input)
+{
+	struct gpio_chip *gc = range->gc;
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+						struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	u32 off, bit, val;
+
+	if (pin >= 64)
+		return -EINVAL;
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	bit = (pin - gc->base) % 8;
+	off = (pin - gc->base) / 8 * 4;
+	val = readl(gchip->base + DDR(off));
+	if (input)
+		val &= ~(1 << bit);
+	else
+		val |= (1 << bit);
+	writel(val, gchip->base + DDR(off));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static int
+mb86s70_pmx_gpio_request_enable(struct pinctrl_dev *pctl,
+				struct pinctrl_gpio_range *range, unsigned pin)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	struct gpio_chip *gc = range->gc;
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+						 struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	int p = pin / 4 * 4;
+	u32 val, off, bit;
+
+	if (p == 64)
+		return -ENODEV;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+	if (pchip->pin_busy[p] || pchip->pin_busy[p + 1] ||
+			pchip->pin_busy[p + 2] || pchip->pin_busy[p + 3]) {
+		val = readl(pchip->base + p);
+		if (val != 0x1) {
+			spin_unlock_irqrestore(&pchip->lock, flags);
+			return -EBUSY;
+		}
+	}
+
+	pchip->pin_busy[pin] = true;
+	writel(0x1, pchip->base + p);
+	spin_unlock_irqrestore(&pchip->lock, flags);
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	bit = (pin - range->pin_base) % 8;
+	off = (pin - range->pin_base) / 8 * 4;
+	val = readl(gchip->base + PFR(off));
+	val &= ~(1 << bit);
+	writel(val, gchip->base + PFR(off));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+
+	return 0;
+}
+
+static void
+mb86s70_pmx_gpio_disable_free(struct pinctrl_dev *pctl,
+			      struct pinctrl_gpio_range *range, unsigned pin)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	struct gpio_chip *gc = range->gc;
+	struct mb86s70_gpio_chip *gchip = container_of(gc,
+						struct mb86s70_gpio_chip, gc);
+	unsigned long flags;
+	u32 off, bit, val;
+
+	if (pin >= 64)
+		return;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+	pchip->pin_busy[pin] = false;
+	spin_unlock_irqrestore(&pchip->lock, flags);
+
+	spin_lock_irqsave(&gchip->lock, flags);
+	bit = (pin - range->pin_base) % 8;
+	off = (pin - range->pin_base) / 8 * 4;
+	val = readl(gchip->base + PFR(off));
+	val |= (1 << bit);
+	writel(val, gchip->base + PFR(off));
+	spin_unlock_irqrestore(&gchip->lock, flags);
+}
+
+static const struct pinmux_ops mb86s70_pmx_ops = {
+	.get_functions_count	= mb86s70_pmx_get_functions_count,
+	.get_function_name	= mb86s70_pmx_get_function_name,
+	.get_function_groups	= mb86s70_pmx_get_function_groups,
+	.enable			= mb86s70_pmx_enable,
+	.disable		= mb86s70_pmx_disable,
+	.gpio_set_direction	= mb86s70_pmx_gpio_set_direction,
+	.gpio_request_enable	= mb86s70_pmx_gpio_request_enable,
+	.gpio_disable_free	= mb86s70_pmx_gpio_disable_free,
+};
+
+static int
+mb86s70_pin_config_group_get(struct pinctrl_dev *pctl, unsigned group,
+			     unsigned long *config)
+{
+	return -EINVAL;
+}
+
+static int
+mb86s70_pin_config_group_set(struct pinctrl_dev *pctl, unsigned group,
+			     unsigned long *configs, unsigned num_configs)
+{
+	struct mb86s70_pmux_chip *pchip	= pinctrl_dev_get_drvdata(pctl);
+	unsigned long flags;
+	const unsigned *pin;
+	int i, j, p;
+	u32 val, ds;
+
+	p = mb86s7x_pgrps[group].num_pins;
+	pin = mb86s7x_pgrps[group].pins;
+
+	spin_lock_irqsave(&pchip->lock, flags);
+
+	for (i = 0; i < num_configs; i++) {
+		switch (pinconf_to_config_param(configs[i])) {
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			/* Drive Strength should be 2, 4, 6 or 8 mA */
+			ds = pinconf_to_config_argument(configs[i]);
+			ds = (ds - 2) / 2;
+			for (j = 0; j < p; j++) {
+				/* Clear the Hi-z */
+				val = readl_relaxed(pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+				val = readl_relaxed(pchip->conf_base +
+							CDRV_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				val |= (ds << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							CDRV_PDG(pin[j]));
+			}
+			break;
+		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+			for (j = 0; j < p; j++) {
+				val = readl_relaxed(pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				val |= (0x1 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							FORCEZ_PDG(pin[j]));
+			}
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			for (j = 0; j < p; j++) {
+				val = readl_relaxed(pchip->conf_base +
+							PULL_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							PULL_PDG(pin[j]));
+			}
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			for (j = 0; j < p; j++) {
+				val = readl_relaxed(pchip->conf_base +
+							PULL_PDG(pin[j]));
+				val &= ~(0x3 << PIN_OFF(pin[j]));
+				val |= (1 << PIN_OFF(pin[j]));
+				writel_relaxed(val, pchip->conf_base +
+							PULL_PDG(pin[j]));
+			}
+			break;
+		default:
+			pr_err("%s:%d!!\n", __func__, __LINE__);
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&pchip->lock, flags);
+
+	return 0;
+}
+
+static const struct pinconf_ops mb86s70_conf_ops = {
+	.pin_config_group_get = mb86s70_pin_config_group_get,
+	.pin_config_group_set = mb86s70_pin_config_group_set,
+};
+
+static const struct of_device_id mb86s70_pinmux_dt_ids[] = {
+	{.compatible = "fujitsu,mb86s70-pinctrl", .data = (void *)PMUX_MB86S70},
+	{.compatible = "fujitsu,mb86s73-pinctrl", .data = (void *)PMUX_MB86S73},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mb86s70_pinmux_dt_ids);
+
+static int mb86s70_pinmux_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	struct mb86s70_pmux_chip *pchip;
+	struct resource *res;
+	int i, type;
+
+	device = of_match_device(mb86s70_pinmux_dt_ids, &pdev->dev);
+	if (!device)
+		return -ENODEV;
+
+	type = (int)device->data;
+
+	/* reserve memory space for pmux chip */
+	pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL);
+	if (pchip == NULL) {
+		dev_err(&pdev->dev, "can't allocate pinmux chip data.\n");
+		return -ENOMEM;
+	}
+	pchip->dev = &pdev->dev;
+
+	/* initiate pmux chip structure */
+	platform_set_drvdata(pdev, pchip);
+
+	/* IO resource */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pchip->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pchip->base))
+		return PTR_ERR(pchip->base);
+
+	/* initiate lock */
+	spin_lock_init(&pchip->lock);
+
+	pchip->desc.name = dev_name(&pdev->dev);
+	pchip->desc.npins = MB86S70_PMUX_PINS;
+	pchip->desc.pins = pchip->pins;
+	pchip->desc.pctlops = &mb86s70_pctrl_ops;
+	pchip->desc.pmxops = &mb86s70_pmx_ops;
+	pchip->desc.owner = THIS_MODULE;
+	if (type == PMUX_MB86S73) {
+		pchip->desc.confops = &mb86s70_conf_ops;
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		pchip->conf_base = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(pchip->conf_base))
+			return PTR_ERR(pchip->conf_base);
+		mb86s7x_pmx_funcs = mb86s73_pmx_funcs;
+		func_count = ARRAY_SIZE(mb86s73_pmx_funcs);
+		mb86s7x_pgrps = mb86s73_pgrps;
+		grp_count = ARRAY_SIZE(mb86s73_pgrps);
+	} else {
+		mb86s7x_pmx_funcs = mb86s70_pmx_funcs;
+		func_count = ARRAY_SIZE(mb86s70_pmx_funcs);
+		mb86s7x_pgrps = mb86s70_pgrps;
+		grp_count = ARRAY_SIZE(mb86s70_pgrps);
+	}
+
+	for (i = 0; i < MB86S70_PMUX_PINS; i++) {
+		pchip->pin_busy[i] = false;
+		pchip->pins[i].number = i;
+		pchip->pins[i].name = &pchip->pin_names[5 * i];
+		snprintf(&pchip->pin_names[5 * i], 5, "PD%d", i);
+	}
+
+	pchip->pctl = pinctrl_register(&pchip->desc, &pdev->dev, pchip);
+	if (!pchip->pctl) {
+		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mb86s70_gpio_dt_ids[] = {
+	{ .compatible = "fujitsu,mb86s7x-gpio" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
+
+static struct platform_driver mb86s70_gpio_driver = {
+	.probe     = mb86s70_gpio_probe,
+	.driver    = {
+		.name  = "mb86s70-gpio",
+		.owner = THIS_MODULE,
+		.of_match_table = mb86s70_gpio_dt_ids,
+	},
+};
+
+static struct platform_driver mb86s70_pinmux_driver = {
+	.probe     = mb86s70_pinmux_probe,
+	.driver    = {
+		.name  = "mb86s70-pinmux",
+		.owner = THIS_MODULE,
+		.of_match_table = mb86s70_pinmux_dt_ids,
+	},
+};
+
+static int __init mb86s70_pins_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&mb86s70_pinmux_driver);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&mb86s70_gpio_driver);
+}
+subsys_initcall(mb86s70_pins_init);
+
+MODULE_DESCRIPTION("MB86S7x PinCtrl Driver");
+MODULE_ALIAS("platform:mb86s70-pinmux");
+MODULE_ALIAS("platform:mb86s70-gpio");
+MODULE_LICENSE("GPL");
-- 
1.8.1.2

  parent reply	other threads:[~2014-07-13  6:31 UTC|newest]

Thread overview: 88+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <message-id-of-cover-letter>
2014-07-13  6:28 ` [PATCH 1/8] ARM: Add platform support for Fujitsu MB86S7X SoCs Mollie Wu
2014-07-13  6:28   ` Mollie Wu
     [not found]   ` <1405232911-4569-1-git-send-email-mollie.wu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-07-14 13:33     ` Arnd Bergmann
2014-07-14 13:33       ` Arnd Bergmann
2014-07-15 17:37       ` Jassi Brar
2014-07-15 17:37         ` Jassi Brar
     [not found]         ` <CAJe_Zhc9MVrX_Yi_u91qeSCWdO65MqEro=eQ1U_nWPfzM0ayjw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-15 20:09           ` Arnd Bergmann
2014-07-15 20:09             ` Arnd Bergmann
2014-07-17 13:32             ` Jassi Brar
2014-07-17 13:32               ` Jassi Brar
     [not found]               ` <CAJe_Zhc91g1=CTJUBaFaqk9Np4u4oEqddZEx_zeVxn7EdMEjmw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-17 13:48                 ` Arnd Bergmann
2014-07-17 13:48                   ` Arnd Bergmann
2014-07-17 16:54                   ` Jassi Brar
2014-07-17 16:54                     ` Jassi Brar
2014-07-17 17:12                     ` Arnd Bergmann
2014-07-17 17:12                       ` Arnd Bergmann
2014-07-15 15:11     ` Rob Herring
2014-07-15 15:11       ` Rob Herring
     [not found]       ` <CAL_JsqKvwxjEDZPVwL646PhPKr7oemBzxr6cZ+X=uJQ2u_XZ8g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-15 16:11         ` Nicolas Pitre
2014-07-15 16:11           ` Nicolas Pitre
2014-07-15 18:03         ` Jassi Brar
2014-07-15 18:03           ` Jassi Brar
2014-07-16  5:52         ` Andy Green
2014-07-16  5:52           ` Andy Green
2014-07-15 17:05   ` Nicolas Pitre
2014-07-15 17:05     ` Nicolas Pitre
     [not found]     ` <alpine.LFD.2.11.1407151214070.3647-fMhRO7WWcppj+hNMo8g0rg@public.gmane.org>
2014-07-15 18:16       ` Jassi Brar
2014-07-15 18:16         ` Jassi Brar
2014-07-13  6:29 ` [PATCH 2/8] mmc: sdhci: host: add new f_sdh30 Mollie Wu
2014-07-13  6:29   ` Mollie Wu
2014-07-14 14:04   ` Arnd Bergmann
2014-07-14 14:04     ` Arnd Bergmann
2014-07-16  9:35     ` Vincent.Yang
2014-07-16  9:35       ` Vincent.Yang
2014-07-16 10:10       ` Arnd Bergmann
2014-07-16 10:10         ` Arnd Bergmann
2014-07-16 11:07         ` Vincent.Yang
2014-07-16 11:07           ` Vincent.Yang
2014-07-13  6:30 ` [PATCH 3/8] mmc: core: add manual resume capability Mollie Wu
2014-07-13  6:30   ` Mollie Wu
2014-07-13  6:30 ` [PATCH 4/8] clk: Add clock driver for mb86s7x Mollie Wu
2014-07-13  6:30   ` Mollie Wu
     [not found]   ` <1405233052-4688-1-git-send-email-mollie.wu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-07-14 14:08     ` Arnd Bergmann
2014-07-14 14:08       ` Arnd Bergmann
2014-07-16  7:09       ` Jassi Brar
2014-07-16  7:09         ` Jassi Brar
2014-07-13  6:31 ` Mollie Wu [this message]
2014-07-13  6:31   ` [PATCH 5/8] pinctrl: add driver for MB86S7x Mollie Wu
     [not found]   ` <1405233067-4725-1-git-send-email-mollie.wu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-07-22 16:11     ` Linus Walleij
2014-07-22 16:11       ` Linus Walleij
     [not found]       ` <CACRpkdb_NC7j=XkbMPv8YYLSeEd1AOpFqmD8x+ohC7ds3cPCfg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-24 18:04         ` Jassi Brar
2014-07-24 18:04           ` Jassi Brar
     [not found]           ` <CAJe_Zhc2gz8DZjzo-4YAucAZ2P=UamZ2MtTP1fHmxC0vspZJDw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-08-08 12:42             ` Linus Walleij
2014-08-08 12:42               ` Linus Walleij
2014-08-22  7:46         ` Jassi Brar
2014-08-22  7:46           ` Jassi Brar
     [not found]           ` <CAJe_Zhe2VuzHtkojm9nxvDTjT4AL7Znvma+5T7JTadvFJ1vAJQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-08-27 16:58             ` Jassi Brar
2014-08-27 16:58               ` Jassi Brar
2014-09-03  9:17             ` Linus Walleij
2014-09-03  9:17               ` Linus Walleij
2014-07-13  6:31 ` [PATCH 6/8] net: ethernet driver: Fujitsu OGMA Mollie Wu
2014-07-13  6:31   ` Mollie Wu
2014-07-14  9:06   ` Tobias Klauser
2014-07-14  9:06     ` Tobias Klauser
2014-07-14 10:36     ` Andy Green
2014-07-14 10:36       ` Andy Green
2014-07-14 13:50   ` Arnd Bergmann
2014-07-14 13:50     ` Arnd Bergmann
2014-07-14 14:00     ` Andy Green
2014-07-13  6:32 ` [PATCH 7/8] mailbox: f_mhu: add driver for Fujitsu MHU controller Mollie Wu
2014-07-13  6:32   ` Mollie Wu
     [not found]   ` <1405233128-4799-1-git-send-email-mollie.wu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-07-16 17:37     ` Sudeep Holla
2014-07-16 17:37       ` Sudeep Holla
     [not found]       ` <53C6B83D.80602-5wv7dgnIgG8@public.gmane.org>
2014-07-17  6:25         ` Jassi Brar
2014-07-17  6:25           ` Jassi Brar
2014-07-17 10:31           ` Sudeep Holla
2014-07-17 10:31             ` Sudeep Holla
     [not found]             ` <53C7A5F1.30209-5wv7dgnIgG8@public.gmane.org>
2014-07-17 12:56               ` Jassi Brar
2014-07-17 12:56                 ` Jassi Brar
     [not found]                 ` <CAJe_ZhegVczzcRVikt=nWnwU3nGx2G2mNg9nGR3bF4FfHnPeEg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-17 15:09                   ` Sudeep Holla
2014-07-17 15:09                     ` Sudeep Holla
     [not found]                     ` <53C7E71C.8020501-5wv7dgnIgG8@public.gmane.org>
2014-07-17 17:07                       ` Jassi Brar
2014-07-17 17:07                         ` Jassi Brar
     [not found]                         ` <CAJe_ZhcROjhXebJetyJus43jNKoBU60jXXRLwnHwMdPJ7LPq7Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-17 18:51                           ` Sudeep Holla
2014-07-17 18:51                             ` Sudeep Holla
     [not found]                             ` <53C81B3E.2020503-5wv7dgnIgG8@public.gmane.org>
2014-07-18  9:06                               ` Jassi Brar
2014-07-18  9:06                                 ` Jassi Brar
2014-07-13  6:32 ` =?y?q?=5BPATCH=208/8=5D=20of=3A=20add=20Fujitsu=20vendor=20prefix?= Mollie Wu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1405233067-4725-1-git-send-email-mollie.wu@linaro.org \
    --to=mollie.wu-qsej5fyqhm4dnm+yrofe0a@public.gmane.org \
    --cc=andy.green-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=arnd-r2nGTMty4D4@public.gmane.org \
    --cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=jaswinder.singh-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org \
    --cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
    --cc=olof-nZhT3qVonbNeoWH0uzbU5w@public.gmane.org \
    --cc=patches-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=pawel.moll-5wv7dgnIgG8@public.gmane.org \
    --cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=t.takinishi-+CUm20s59erQFUHtdCDX3A@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.