diff mbox

pinctrl: Add initial driver data for Alphascale asm9260

Message ID 1423740753-1221-1-git-send-email-linux@rempel-privat.de
State New
Headers show

Commit Message

Oleksij Rempel Feb. 12, 2015, 11:32 a.m. UTC
This patch adds initial driver data for Alphascale asm9260 pinctrl support.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
---
 .../pinctrl/alphascale,asm9260-pinctrl.txt         |  76 +++
 drivers/pinctrl/Kconfig                            |   8 +
 drivers/pinctrl/Makefile                           |   1 +
 drivers/pinctrl/pinctrl-asm9260.c                  | 733 +++++++++++++++++++++
 4 files changed, 818 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/alphascale,asm9260-pinctrl.txt
 create mode 100644 drivers/pinctrl/pinctrl-asm9260.c

Comments

Linus Walleij March 6, 2015, 8:38 a.m. UTC | #1
Hi Oleksij,

Thanks for your patch.

On Thu, Feb 12, 2015 at 12:32 PM, Oleksij Rempel <linux@rempel-privat.de> wrote:

Also send the patch to linux-kernel@vger.kernel.org as that is the
default pin control mailing list.

Split off Device Tree bindings in its own file and send that also to
devicetree@vger.kernel.org for review.

> This patch adds initial driver data for Alphascale asm9260 pinctrl support.
>
> Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>

A bit terse description, tell us a bit more about the system in the initial
commit, and what silicon it lives in etc.

> +The pinctrl driver enables Alphascale ASM9260 to configure the multi-purpose pins
> +(MPP) to a specific function.

MPP? That is a new name again for pin multiplexing, alternate function,
mission mode etc... apparently people have a problem with what to
call this.

(...)
> +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".

Nice. Good that you use generic bindings.

> +The following generic properties as defined in pinctrl-bindings.txt are valid
> +to specify in a pin configuration subnode:
> +pins                   - the list of pins that properties in the node
> +                         apply to (either this or "group" has to be
> +                         specified)

Should be "groups" not "group". Several groups can map to one
function.

> +function               - the mux function to select
> +bias-disable           - disable any pin bias
> +bias-pull-up           - pull up the pin. Supported only on GPIO0_* pins.
> +bias-pull-down         - pull down the pin. Supported on all pins except of GPIO0_*.

Nice, good details.

(...)
> +struct asm9260_function {
> +       const char              *name;
> +       const char              **groups;
> +       unsigned int            ngroups;
> +};

Yes, see one function, many groups.

The driver looks simple and nice.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Oleksij Rempel March 27, 2015, 9:36 a.m. UTC | #2
Oleksij Rempel (2):
  pinctrl: Add driver for Alphascale asm9260 pinctrl
  pinctrl: asm9260: add pinctrl add device tree bindings documentation

 .../pinctrl/alphascale,asm9260-pinctrl.txt         |  76 +++
 drivers/pinctrl/Kconfig                            |   8 +
 drivers/pinctrl/Makefile                           |   1 +
 drivers/pinctrl/pinctrl-asm9260.c                  | 733 +++++++++++++++++++++
 4 files changed, 818 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/alphascale,asm9260-pinctrl.txt
 create mode 100644 drivers/pinctrl/pinctrl-asm9260.c
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/pinctrl/alphascale,asm9260-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/alphascale,asm9260-pinctrl.txt
new file mode 100644
index 0000000..c8b9a21
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/alphascale,asm9260-pinctrl.txt
@@ -0,0 +1,76 @@ 
+* Alphascale ASM9260 SoC pinctrl core driver
+
+The pinctrl driver enables Alphascale ASM9260 to configure the multi-purpose pins
+(MPP) to a specific function.
+
+Required properties for pinctrl driver:
+- compatible: "alphascale,asm9260-pinctrl"
+- reg: Register base of the MPP block and length.
+- clocks: clock ids.
+- clock-names:
+	* 1 "ahb" : AHB gating clock.
+
+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".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin or a list of pins. This configuration can include the
+mux function to select on those pin(s), and various pin configuration
+parameters, as listed below.
+
+SUBNODES:
+
+The name of each subnode is not important; 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.
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+pins			- the list of pins that properties in the node
+			  apply to (either this or "group" has to be
+			  specified)
+function		- the mux function to select
+bias-disable		- disable any pin bias
+bias-pull-up		- pull up the pin. Supported only on GPIO0_* pins.
+bias-pull-down		- pull down the pin. Supported on all pins except of GPIO0_*.
+
+Examples:
+
+pinctrl: pinctrl@80044000 {
+	compatible = "alphascale,asm9260-pinctrl";
+	reg = <0x80044000 0x400>;
+	clocks = <&acc CLKID_AHB_IOCONFIG>;
+	clock-names = "ahb";
+
+        nand_fc0_pins_a: nand_fc0 {
+                nand_main_gr {
+                        pins = "GPIO11_0", "GPIO11_1", "GPIO11_2",
+                               "GPIO11_3", "GPIO11_4", "GPIO11_6",
+                               "GPIO12_0", "GPIO12_1", "GPIO12_2",
+                               "GPIO12_3", "GPIO12_4", "GPIO12_5",
+                               "GPIO12_6", "GPIO12_7";
+                        function = "nand0";
+                        bias-disable;
+                };
+        };
+};
+
+nand_controller0 {
+        status = "okay";
+        #address-cells = <1>;
+        #size-cells = <1>;
+        nand-ecc-strength = <4>;
+        nand-ecc-step-size = <512>;
+        nand-max-chips = <1>;
+        nand-on-flash-bbt;
+
+        pinctrl-names = "default";
+        pinctrl-0 = <&nand_fc0_pins_a>;
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d014f22..19cd287 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -47,6 +47,14 @@  config PINCTRL_AS3722
 	  open drain configuration for the GPIO pins of AS3722 devices. It also
 	  supports the GPIO functionality through gpiolib.
 
+config PINCTRL_ASM9260
+	bool "Pinctrl driver for Alphascale asm9260"
+	depends on MACH_ASM9260
+	select PINMUX
+	select GENERIC_PINCONF
+	help
+	  Say Y here to enable the Alphascale asm9260 pinctrl driver
+
 config PINCTRL_BF54x
 	def_bool y if BF54x
 	select PINCTRL_ADI2
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c030b3d..46ba7d1c 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -11,6 +11,7 @@  endif
 obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
 obj-$(CONFIG_PINCTRL_ADI2)	+= pinctrl-adi2.o
 obj-$(CONFIG_PINCTRL_AS3722)	+= pinctrl-as3722.o
+obj-$(CONFIG_PINCTRL_ASM9260)	+= pinctrl-asm9260.o
 obj-$(CONFIG_PINCTRL_BF54x)	+= pinctrl-adi2-bf54x.o
 obj-$(CONFIG_PINCTRL_BF60x)	+= pinctrl-adi2-bf60x.o
 obj-$(CONFIG_PINCTRL_AT91)	+= pinctrl-at91.o
diff --git a/drivers/pinctrl/pinctrl-asm9260.c b/drivers/pinctrl/pinctrl-asm9260.c
new file mode 100644
index 0000000..d31d907
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-asm9260.c
@@ -0,0 +1,733 @@ 
+/*
+ * Pinctrl driver for the Alphascale ASM9260 SoC
+ *
+ * Copyright (c) 2014, Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+
+/* pinctrl register */
+#define IOCON_PIO0_0			0x0000
+/* only two modes are supported NONE and PULL UP */
+#define IOCON_MODE_SHIFT		3
+#define IOCON_MODE_MASK			(0x3 << IOCON_MODE_SHIFT)
+/* Only GPIO0_* pins support pull up. */
+#define IOCON_MODE_PULL_UP		(0x2 << IOCON_MODE_SHIFT)
+/* Only GPIO0_* pins don't support pull down. */
+#define IOCON_MODE_PULL_DOWN		(0x1 << IOCON_MODE_SHIFT)
+#define IOCON_MODE_NONE			(0x0 << IOCON_MODE_SHIFT)
+/* up to 8 functions per pin */
+#define IOCON_PINMUX_MASK		(0x7 << 0)
+
+#define MUX_OFFSET(bank, pin)		((bank) * 32 + (pin) * 4)
+
+enum asm9260_mux {
+	ASM9260_MUX_na = -1,
+
+	ASM9260_MUX_gpio0,
+	ASM9260_MUX_cam0,
+	ASM9260_MUX_can0,
+	ASM9260_MUX_can1,
+	ASM9260_MUX_ct0,
+	ASM9260_MUX_ct1,
+	ASM9260_MUX_ct2,
+	ASM9260_MUX_ct3,
+	ASM9260_MUX_i2c0,
+	ASM9260_MUX_i2c1,
+	ASM9260_MUX_i2s0,
+	ASM9260_MUX_i2s1,
+	ASM9260_MUX_jtag,
+	ASM9260_MUX_lcd0,
+	ASM9260_MUX_lcd_if0,
+	ASM9260_MUX_mc,
+	ASM9260_MUX_mc0,
+	ASM9260_MUX_mii0,
+	ASM9260_MUX_nand0,
+	ASM9260_MUX_outclk,
+	ASM9260_MUX_qei0,
+	ASM9260_MUX_qspi0,
+	ASM9260_MUX_rmii0,
+	ASM9260_MUX_sd0,
+	ASM9260_MUX_spi0,
+	ASM9260_MUX_spi1,
+	ASM9260_MUX_uart0,
+	ASM9260_MUX_uart1,
+	ASM9260_MUX_uart2,
+	ASM9260_MUX_uart3,
+	ASM9260_MUX_uart4,
+	ASM9260_MUX_uart5,
+	ASM9260_MUX_uart6,
+	ASM9260_MUX_uart7,
+	ASM9260_MUX_uart8,
+	ASM9260_MUX_uart9,
+};
+
+struct asm9260_function {
+	const char		*name;
+	const char		**groups;
+	unsigned int		ngroups;
+};
+
+#define FUNCTION(mux)			\
+	[(ASM9260_MUX_ ## mux)] = {		\
+		.name = #mux,			\
+		.groups = NULL,			\
+		.ngroups = 0,		\
+	}
+
+static struct asm9260_function asm9260_functions[] = {
+	FUNCTION(gpio0),
+	FUNCTION(cam0),
+	FUNCTION(can0),
+	FUNCTION(can1),
+	FUNCTION(ct0),
+	FUNCTION(ct1),
+	FUNCTION(ct2),
+	FUNCTION(ct3),
+	FUNCTION(i2c0),
+	FUNCTION(i2c1),
+	FUNCTION(i2s0),
+	FUNCTION(i2s1),
+	FUNCTION(jtag),
+	FUNCTION(lcd0),
+	FUNCTION(lcd_if0),
+	FUNCTION(mc),
+	FUNCTION(mc0),
+	FUNCTION(mii0),
+	FUNCTION(nand0),
+	FUNCTION(outclk),
+	FUNCTION(qei0),
+	FUNCTION(qspi0),
+	FUNCTION(rmii0),
+	FUNCTION(sd0),
+	FUNCTION(spi0),
+	FUNCTION(spi1),
+	FUNCTION(uart0),
+	FUNCTION(uart1),
+	FUNCTION(uart2),
+	FUNCTION(uart3),
+	FUNCTION(uart4),
+	FUNCTION(uart5),
+	FUNCTION(uart6),
+	FUNCTION(uart7),
+	FUNCTION(uart8),
+	FUNCTION(uart9),
+};
+
+struct asm9260_pingroup {
+	const char		*name;
+	const unsigned int	number;
+	const unsigned int	bank;
+	const unsigned int	pin;
+
+#define MAX_FUNCS_PER_PIN	8
+	const int		funcs[MAX_FUNCS_PER_PIN];
+};
+
+#define PMUX(p_number, p_bank, p_pin, p_name, f1, f2, f3, f4, f5, f6, f7) \
+	{						\
+		.number = p_number,			\
+		.bank = p_bank,				\
+		.pin = p_pin,				\
+		.name = #p_name,			\
+		.funcs = {				\
+			ASM9260_MUX_gpio0,		\
+			ASM9260_MUX_ ## f1,		\
+			ASM9260_MUX_ ## f2,		\
+			ASM9260_MUX_ ## f3,		\
+			ASM9260_MUX_ ## f4,		\
+			ASM9260_MUX_ ## f5,		\
+			ASM9260_MUX_ ## f6,		\
+			ASM9260_MUX_ ## f7,		\
+		},					\
+	}
+
+static struct asm9260_pingroup asm9260_mux_table[] = {
+	PMUX(120,	0,	0,	GPIO0_0,
+		na,	uart1,	i2s0,	spi1,	na,	jtag,	na),
+	PMUX(121,	0,	1,	GPIO0_1,
+		na,	uart1,	i2s0,	spi1,	na,	jtag,	na),
+	PMUX(122,	0,	2,	GPIO0_2,
+		na,	uart1,	i2s0,	spi1,	na,	jtag,	na),
+	PMUX(123,	0,	3,	GPIO0_3,
+		na,	uart1,	i2s0,	spi1,	na,	jtag,	na),
+	PMUX(124,	0,	4,	GPIO0_4,
+		na,	uart1,	i2s0,	spi0,	na,	jtag,	i2c0),
+	PMUX(128,	1,	4,	GPIO1_4,
+		ct0,	uart0,	lcd_if0,	spi0,	mii0,	lcd0,	na),
+	PMUX(129,	1,	5,	GPIO1_5,
+		na,	uart0,	lcd_if0,	spi0,	rmii0,	lcd0,	na),
+	PMUX(130,	1,	6,	GPIO1_6,
+		na,	uart0,	lcd_if0,	spi0,	rmii0,	lcd0,	i2c1),
+	PMUX(131,	1,	7,	GPIO1_7,
+		na,	uart0,	lcd_if0,	spi0,	rmii0,	lcd0,	i2c1),
+	PMUX(132,	2,	0,	GPIO2_0,
+		ct1,	uart2,	lcd_if0,	spi1,	mii0,	lcd0,	can0),
+	PMUX(133,	2,	1,	GPIO2_1,
+		ct1,	uart2,	lcd_if0,	spi1,	mii0,	lcd0,	can0),
+	PMUX(134,	2,	2,	GPIO2_2,
+		ct1,	uart3,	lcd_if0,	spi1,	mii0,	lcd0,	na),
+	PMUX(135,	2,	3,	GPIO2_3,
+		ct1,	uart3,	lcd_if0,	spi1,	mii0,	lcd0,	na),
+	PMUX(136,	2,	4,	GPIO2_4,
+		ct1,	uart3,	lcd_if0,	na,	mii0,	lcd0,	na),
+	PMUX(137,	2,	5,	GPIO2_5,
+		na,	uart3,	lcd_if0,	na,	mii0,	lcd0,	outclk),
+	PMUX(138,	2,	6,	GPIO2_6,
+		na,	uart3,	lcd_if0,	na,	mii0,	lcd0,	can1),
+	PMUX(139,	2,	7,	GPIO2_7,
+		na,	uart4,	lcd_if0,	na,	mii0,	lcd0,	can1),
+	PMUX(140,	3,	0,	GPIO3_0,
+		ct2,	uart4,	lcd_if0,	sd0,	rmii0,	lcd0,	na),
+	PMUX(141,	3,	1,	GPIO3_1,
+		ct2,	uart4,	lcd_if0,	sd0,	rmii0,	lcd0,	na),
+	PMUX(142,	3,	2,	GPIO3_2,
+		ct2,	uart4,	lcd_if0,	sd0,	rmii0,	lcd0,	can1),
+	PMUX(143,	3,	3,	GPIO3_3,
+		ct2,	uart4,	lcd_if0,	sd0,	rmii0,	lcd0,	can1),
+	PMUX(144,	3,	4,	GPIO3_4,
+		ct2,	uart5,	lcd_if0,	sd0,	rmii0,	lcd0,	outclk),
+	PMUX(145,	3,	5,	GPIO3_5,
+		na,	uart5,	lcd_if0,	sd0,	rmii0,	lcd0,	i2c0),
+	PMUX(146,	3,	6,	GPIO3_6,
+		na,	uart5,	lcd_if0,	na,	rmii0,	lcd0,	i2c0),
+	PMUX(147,	3,	7,	GPIO3_7,
+		na,	uart5,	lcd_if0,	na,	rmii0,	lcd0,	na),
+	PMUX(151,	4,	0,	GPIO4_0,
+		ct3,	uart5,	na,	qspi0,	mii0,	lcd0,	na),
+	PMUX(152,	4,	1,	GPIO4_1,
+		ct3,	uart6,	na,	qspi0,	mii0,	lcd0,	na),
+	PMUX(153,	4,	2,	GPIO4_2,
+		ct3,	uart6,	na,	qspi0,	mii0,	lcd0,	na),
+	PMUX(154,	4,	3,	GPIO4_3,
+		ct3,	uart6,	na,	qspi0,	mii0,	lcd0,	na),
+	PMUX(155,	4,	4,	GPIO4_4,
+		ct3,	uart6,	na,	qspi0,	mii0,	lcd0,	na),
+	PMUX(156,	4,	5,	GPIO4_5,
+		na,	uart6,	na,	qspi0,	mii0,	lcd0,	na),
+	PMUX(157,	4,	6,	GPIO4_6,
+		na,	na,	na,	na,	mii0,	lcd0,	i2c1),
+	PMUX(158,	4,	7,	GPIO4_7,
+		na,	na,	na,	na,	mii0,	lcd0,	i2c1),
+	PMUX(169,	5,	0,	GPIO5_0,
+		mc0,	uart7,	i2s1,	sd0,	rmii0,	na,	na),
+	PMUX(170,	5,	1,	GPIO5_1,
+		mc0,	uart7,	i2s1,	sd0,	rmii0,	na,	na),
+	PMUX(171,	5,	2,	GPIO5_2,
+		mc0,	uart7,	i2s1,	sd0,	rmii0,	na,	can0),
+	PMUX(172,	5,	3,	GPIO5_3,
+		mc0,	uart7,	i2s1,	sd0,	rmii0,	na,	can0),
+	PMUX(173,	5,	4,	GPIO5_4,
+		mc0,	uart8,	i2s1,	sd0,	rmii0,	na,	na),
+	PMUX(51,	8,	1,	GPIO8_1,
+		na,	uart2,	cam0,	na,	mii0,	na,	na),
+	PMUX(52,	8,	2,	GPIO8_2,
+		na,	uart2,	cam0,	na,	mii0,	na,	na),
+	PMUX(53,	8,	3,	GPIO8_3,
+		na,	uart2,	cam0,	na,	mii0,	na,	na),
+	PMUX(54,	8,	4,	GPIO8_4,
+		na,	uart2,	cam0,	na,	mii0,	na,	na),
+	PMUX(55,	8,	5,	GPIO8_5,
+		na,	uart3,	cam0,	na,	mii0,	na,	na),
+	PMUX(56,	8,	6,	GPIO8_6,
+		na,	uart3,	cam0,	na,	mii0,	na,	na),
+	PMUX(57,	8,	7,	GPIO8_7,
+		na,	uart3,	cam0,	na,	mii0,	na,	na),
+	PMUX(45,	9,	0,	GPIO9_0,
+		ct0,	uart3,	cam0,	na,	rmii0,	na,	i2c0),
+	PMUX(46,	9,	1,	GPIO9_1,
+		ct0,	uart3,	cam0,	na,	rmii0,	na,	i2c0),
+	PMUX(47,	9,	2,	GPIO9_2,
+		ct0,	uart4,	cam0,	na,	rmii0,	na,	na),
+	PMUX(48,	9,	3,	GPIO9_3,
+		ct0,	uart4,	cam0,	na,	rmii0,	na,	na),
+	PMUX(49,	9,	4,	GPIO9_4,
+		ct0,	uart4,	cam0,	na,	rmii0,	na,	na),
+	PMUX(50,	9,	5,	GPIO9_5,
+		na,	uart4,	cam0,	na,	rmii0,	na,	i2c1),
+	PMUX(4,		10,	0,	GPIO10_0,
+		ct1,	uart5,	i2s0,	spi0,	na,	na,	na),
+	PMUX(5,		10,	1,	GPIO10_1,
+		ct1,	uart5,	i2s0,	spi0,	rmii0,	na,	na),
+	PMUX(6,		10,	2,	GPIO10_2,
+		ct1,	uart5,	i2s0,	spi0,	rmii0,	na,	na),
+	PMUX(7,		10,	3,	GPIO10_3,
+		ct1,	uart5,	i2s0,	spi0,	na,	na,	can0),
+	PMUX(8,		10,	4,	GPIO10_4,
+		ct1,	uart6,	i2s0,	spi1,	rmii0,	na,	na),
+	PMUX(9,		10,	5,	GPIO10_5,
+		na,	uart6,	i2s0,	spi1,	rmii0,	na,	can1),
+	PMUX(10,	10,	6,	GPIO10_6,
+		na,	uart6,	i2s0,	spi1,	rmii0,	na,	can1),
+	PMUX(11,	10,	7,	GPIO10_7,
+		na,	uart6,	cam0,	spi1,	rmii0,	na,	na),
+	PMUX(12,	11,	0,	GPIO11_0,
+		ct2,	uart7,	i2s1,	qspi0,	nand0,	na,	na),
+	PMUX(13,	11,	1,	GPIO11_1,
+		ct2,	uart7,	i2s1,	qspi0,	nand0,	na,	na),
+	PMUX(14,	11,	2,	GPIO11_2,
+		ct2,	uart7,	i2s1,	qspi0,	nand0,	na,	na),
+	PMUX(15,	11,	3,	GPIO11_3,
+		ct2,	uart7,	i2s1,	qspi0,	nand0,	na,	na),
+	PMUX(16,	11,	4,	GPIO11_4,
+		ct2,	uart8,	i2s1,	qspi0,	nand0,	na,	na),
+	PMUX(17,	11,	5,	GPIO11_5,
+		na,	uart8,	i2s1,	qspi0,	nand0,	na,	na),
+	PMUX(18,	11,	6,	GPIO11_6,
+		na,	uart9,	i2s1,	na,	nand0,	na,	i2c0),
+	PMUX(19,	11,	7,	GPIO11_7,
+		na,	uart9,	cam0,	na,	nand0,	na,	i2c0),
+	PMUX(23,	12,	0,	GPIO12_0,
+		ct3,	uart1,	na,	sd0,	nand0,	na,	na),
+	PMUX(24,	12,	1,	GPIO12_1,
+		ct3,	uart1,	na,	sd0,	nand0,	na,	na),
+	PMUX(25,	12,	2,	GPIO12_2,
+		ct3,	uart1,	na,	sd0,	nand0,	na,	na),
+	PMUX(26,	12,	3,	GPIO12_3,
+		ct3,	uart1,	na,	sd0,	nand0,	na,	na),
+	PMUX(27,	12,	4,	GPIO12_4,
+		ct3,	uart1,	na,	sd0,	nand0,	na,	na),
+	PMUX(28,	12,	5,	GPIO12_5,
+		na,	uart8,	na,	sd0,	nand0,	na,	na),
+	PMUX(29,	12,	6,	GPIO12_6,
+		na,	uart8,	cam0,	na,	nand0,	na,	i2c1),
+	PMUX(30,	12,	7,	GPIO12_7,
+		na,	na,	cam0,	na,	nand0,	na,	i2c1),
+	PMUX(31,	13,	4,	GPIO13_4,
+		mc,	uart2,	na,	spi1,	nand0,	na,	na),
+	PMUX(32,	13,	5,	GPIO13_5,
+		mc0,	uart9,	na,	spi1,	nand0,	na,	na),
+	PMUX(33,	13,	6,	GPIO13_6,
+		mc0,	uart9,	na,	spi1,	nand0,	na,	na),
+	PMUX(34,	13,	7,	GPIO13_7,
+		mc0,	na,	na,	spi1,	nand0,	na,	na),
+	PMUX(38,	14,	0,	GPIO14_0,
+		mc0,	uart0,	i2s0,	sd0,	nand0,	na,	na),
+	PMUX(39,	14,	1,	GPIO14_1,
+		mc0,	uart0,	i2s0,	sd0,	nand0,	na,	na),
+	PMUX(40,	14,	2,	GPIO14_2,
+		na,	uart0,	i2s0,	sd0,	nand0,	na,	na),
+	PMUX(41,	14,	3,	GPIO14_3,
+		na,	uart0,	i2s0,	sd0,	nand0,	na,	na),
+	PMUX(42,	14,	4,	GPIO14_4,
+		na,	uart0,	i2s0,	sd0,	nand0,	na,	na),
+	PMUX(43,	14,	5,	GPIO14_5,
+		na,	uart0,	i2s0,	sd0,	nand0,	na,	na),
+	PMUX(44,	15,	0,	GPIO15_0,
+		na,	uart4,	i2s0,	sd0,	rmii0,	na,	na),
+	PMUX(61,	15,	1,	GPIO15_1,
+		na,	uart4,	i2s0,	sd0,	rmii0,	na,	na),
+	PMUX(62,	15,	2,	GPIO15_2,
+		na,	uart5,	i2s0,	sd0,	rmii0,	na,	na),
+	PMUX(63,	15,	3,	GPIO15_3,
+		na,	uart5,	i2s0,	sd0,	rmii0,	na,	na),
+	PMUX(64,	15,	4,	GPIO15_4,
+		na,	uart6,	i2s0,	sd0,	rmii0,	na,	na),
+	PMUX(65,	15,	5,	GPIO15_5,
+		na,	uart6,	i2s0,	sd0,	rmii0,	na,	na),
+	PMUX(66,	15,	6,	GPIO15_6,
+		na,	uart7,	i2s0,	na,	rmii0,	na,	na),
+	PMUX(67,	15,	7,	GPIO15_7,
+		na,	uart7,	na,	na,	rmii0,	na,	na),
+	PMUX(73,	16,	0,	GPIO16_0,
+		ct2,	uart4,	na,	na,	mii0,	na,	na),
+	PMUX(74,	16,	1,	GPIO16_1,
+		ct2,	uart4,	na,	na,	mii0,	na,	na),
+	PMUX(75,	16,	2,	GPIO16_2,
+		ct2,	uart5,	na,	na,	mii0,	na,	na),
+	PMUX(76,	16,	3,	GPIO16_3,
+		ct2,	uart5,	na,	na,	mii0,	na,	na),
+	PMUX(77,	16,	4,	GPIO16_4,
+		ct2,	uart6,	na,	na,	mii0,	na,	na),
+	PMUX(78,	16,	5,	GPIO16_5,
+		qei0,	uart6,	na,	na,	mii0,	na,	na),
+	PMUX(79,	16,	6,	GPIO16_6,
+		qei0,	uart6,	na,	na,	mii0,	na,	can1),
+	PMUX(80,	16,	7,	GPIO16_7,
+		qei0,	uart6,	na,	na,	mii0,	na,	can1),
+	PMUX(81,	17,	0,	GPIO17_0,
+		ct3,	uart7,	i2s1,	na,	rmii0,	na,	na),
+	PMUX(82,	17,	1,	GPIO17_1,
+		ct3,	uart7,	i2s1,	na,	na,	na,	na),
+	PMUX(83,	17,	2,	GPIO17_2,
+		ct3,	uart7,	i2s1,	na,	na,	na,	i2c1),
+	PMUX(84,	17,	3,	GPIO17_3,
+		ct3,	uart7,	i2s1,	na,	na,	na,	i2c1),
+	PMUX(85,	17,	4,	GPIO17_4,
+		ct3,	uart8,	i2s1,	na,	na,	na,	na),
+	PMUX(86,	17,	5,	GPIO17_5,
+		qei0,	uart8,	i2s1,	na,	rmii0,	na,	na),
+	PMUX(87,	17,	6,	GPIO17_6,
+		qei0,	uart9,	i2s1,	na,	mii0,	na,	na),
+	PMUX(88,	17,	7,	GPIO17_7,
+		qei0,	uart9,	na,	na,	mii0,	na,	na),
+};
+
+#define MUX_TABLE_SIZE		ARRAY_SIZE(asm9260_mux_table)
+struct asm9260_pmx_priv {
+	struct device		*dev;
+	struct pinctrl_dev	*pctl;
+	void __iomem		*iobase;
+
+	struct clk		*clk;
+	spinlock_t		lock;
+
+	struct pinctrl_pin_desc	pin_desc[MUX_TABLE_SIZE];
+};
+
+static void __init asm9260_init_mux_pins(struct asm9260_pmx_priv *priv)
+{
+	unsigned int i;
+
+	for (i = 0; i < MUX_TABLE_SIZE; i++) {
+		priv->pin_desc[i].name = asm9260_mux_table[i].name;
+		priv->pin_desc[i].number = asm9260_mux_table[i].number;
+	}
+}
+
+/*
+ * Pin control operations
+ */
+
+/* each GPIO pin has it's own pseudo pingroup containing only itself */
+static int asm9260_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	return MUX_TABLE_SIZE;
+}
+
+static const char *asm9260_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+						 unsigned int group)
+{
+	struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+	return priv->pin_desc[group].name;
+}
+
+static int asm9260_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+					 unsigned int group,
+					 const unsigned int **pins,
+					 unsigned int *num_pins)
+{
+	struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = &priv->pin_desc[group].number;
+	*num_pins = 1;
+
+	return 0;
+}
+
+static struct pinctrl_ops asm9260_pinctrl_ops = {
+	.get_groups_count	= asm9260_pinctrl_get_groups_count,
+	.get_group_name		= asm9260_pinctrl_get_group_name,
+	.get_group_pins		= asm9260_pinctrl_get_group_pins,
+	.dt_node_to_map		= pinconf_generic_dt_node_to_map_pin,
+	.dt_free_map		= pinctrl_utils_dt_free_map,
+};
+
+/*
+ * Pin mux operations
+ */
+static int asm9260_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(asm9260_functions);
+}
+
+static const char *asm9260_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+						unsigned int function)
+{
+	return asm9260_functions[function].name;
+}
+
+static int asm9260_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+					  unsigned int function,
+					  const char * const **groups,
+					  unsigned int * const num_groups)
+{
+	struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	struct asm9260_pingroup *table;
+	int a, b, count = 0, *tmp;
+	const char **gr;
+
+	if (asm9260_functions[function].groups != NULL)
+		goto done;
+
+	tmp = devm_kmalloc(priv->dev, sizeof(tmp) * MUX_TABLE_SIZE, GFP_KERNEL);
+	if (!tmp) {
+		dev_err(priv->dev, "Can't allocate func/pin array\n");
+		return PTR_ERR(tmp);
+	}
+
+	for (a = 0; a < MUX_TABLE_SIZE; a++) {
+		table = &asm9260_mux_table[a];
+
+		for (b = 0; b < MAX_FUNCS_PER_PIN; b++) {
+			if (table->funcs[b] == function) {
+				tmp[count] = a;
+				count++;
+			}
+
+		}
+
+	}
+
+	gr = devm_kmalloc(priv->dev,
+			sizeof(gr) * count, GFP_KERNEL);
+	if (!gr) {
+		dev_err(priv->dev, "Can't allocate func group\n");
+		devm_kfree(priv->dev, tmp);
+		return PTR_ERR(gr);
+	}
+
+	for (a = 0; a < count; a++)
+		gr[a] = asm9260_mux_table[tmp[a]].name;
+
+	asm9260_functions[function].groups = gr;
+	asm9260_functions[function].ngroups = count;
+done:
+	*groups = asm9260_functions[function].groups;
+	*num_groups = asm9260_functions[function].ngroups;
+	return 0;
+}
+
+static int asm9260_pinctrl_set_mux(struct pinctrl_dev *pctldev,
+				 unsigned int function, unsigned int pin)
+{
+	struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	struct asm9260_pingroup *table;
+	void __iomem            *offset;
+	int		mux;
+	u32		val;
+
+	table = &asm9260_mux_table[pin];
+	for (mux = 0; mux < MAX_FUNCS_PER_PIN; ++mux) {
+		if (table->funcs[mux] == function)
+			goto found_mux;
+	}
+
+	return -EINVAL;
+
+found_mux:
+	offset = priv->iobase + MUX_OFFSET(table->bank, table->pin);
+	spin_lock(&priv->lock);
+	val = ioread32(offset);
+	val &= ~IOCON_PINMUX_MASK;
+	val |= mux;
+	iowrite32(val, offset);
+	spin_unlock(&priv->lock);
+
+	return 0;
+}
+
+static struct pinmux_ops asm9260_pinmux_ops = {
+	.get_functions_count	= asm9260_pinctrl_get_funcs_count,
+	.get_function_name	= asm9260_pinctrl_get_func_name,
+	.get_function_groups	= asm9260_pinctrl_get_func_groups,
+	.set_mux		= asm9260_pinctrl_set_mux,
+	/* TODO: should we care about gpios here? gpio_request_enable? */
+};
+
+static int asm9260_pinconf_reg(struct pinctrl_dev *pctldev,
+			      unsigned int pin,
+			      enum pin_config_param param,
+			      void __iomem **reg, u32 *val)
+{
+	struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	struct asm9260_pingroup *table;
+	int a;
+
+	for (a = 0; a < MUX_TABLE_SIZE; a++) {
+		table = &asm9260_mux_table[a];
+		if (table->number == pin)
+			break;
+	}
+
+	*reg = priv->iobase + MUX_OFFSET(table->bank, table->pin);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		*val = IOCON_MODE_NONE;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (table->bank != 0)
+			return -ENOTSUPP;
+		*val = IOCON_MODE_PULL_UP;
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (table->bank == 0)
+			return -ENOTSUPP;
+		*val = IOCON_MODE_PULL_DOWN;
+		break;
+	default:
+		return -ENOTSUPP;
+	};
+
+	return 0;
+}
+
+static int asm9260_pinconf_get(struct pinctrl_dev *pctldev,
+			      unsigned int pin, unsigned long *config)
+{
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	void __iomem	*reg;
+	u32 val, tmp, arg;
+	int ret;
+
+	/* Get register information */
+	ret = asm9260_pinconf_reg(pctldev, pin, param,
+				 &reg, &val);
+	if (ret < 0)
+		return ret;
+
+	/* Extract field from register */
+	tmp = ioread32(reg);
+	arg = (tmp & IOCON_MODE_MASK) == val;
+	if (!arg)
+		return -EINVAL;
+
+	/* And pack config */
+	*config = pinconf_to_config_packed(param, arg);
+
+	return 0;
+}
+
+static int asm9260_pinconf_set(struct pinctrl_dev *pctldev,
+			      unsigned int pin, unsigned long *configs,
+			      unsigned num_configs)
+{
+	struct asm9260_pmx_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param;
+	unsigned int arg;
+	int ret;
+	u32 val, tmp;
+	void __iomem *reg;
+	int i;
+
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
+
+		/* Get register information */
+		ret = asm9260_pinconf_reg(pctldev, pin, param,
+					 &reg, &val);
+		if (ret < 0)
+			return ret;
+
+		spin_lock(&priv->lock);
+		tmp = ioread32(reg);
+		tmp &= ~IOCON_MODE_MASK;
+		if (arg)
+			tmp |= val;
+		iowrite32(tmp, reg);
+		spin_unlock(&priv->lock);
+	}
+
+	return 0;
+}
+
+static struct pinconf_ops asm9260_pinconf_ops = {
+	.is_generic			= true,
+	.pin_config_get			= asm9260_pinconf_get,
+	.pin_config_set			= asm9260_pinconf_set,
+};
+
+/*
+ * Pin control driver setup
+ */
+static struct pinctrl_desc asm9260_pinctrl_desc = {
+	.pctlops	= &asm9260_pinctrl_ops,
+	.pmxops		= &asm9260_pinmux_ops,
+	.confops	= &asm9260_pinconf_ops,
+	.owner		= THIS_MODULE,
+};
+
+static int asm9260_pinctrl_probe(struct platform_device *pdev)
+{
+	struct asm9260_pmx_priv *priv;
+	struct resource	*res;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "Can't alloc asm9260_priv\n");
+		return -ENOMEM;
+	}
+	priv->dev = &pdev->dev;
+	spin_lock_init(&priv->lock);
+
+	asm9260_init_mux_pins(priv);
+
+	asm9260_pinctrl_desc.name = dev_name(&pdev->dev);
+	asm9260_pinctrl_desc.pins = priv->pin_desc;
+	asm9260_pinctrl_desc.npins = MUX_TABLE_SIZE;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->iobase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->iobase))
+		return PTR_ERR(priv->iobase);
+
+	priv->clk = devm_clk_get(&pdev->dev, "ahb");
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to enable clk!\n");
+		return ret;
+	}
+
+	priv->pctl = pinctrl_register(&asm9260_pinctrl_desc, &pdev->dev, priv);
+	if (!priv->pctl) {
+		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+		ret = -ENODEV;
+		goto err_return;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	dev_info(&pdev->dev, "ASM9260 pinctrl driver initialised\n");
+
+	return 0;
+err_return:
+	clk_disable_unprepare(priv->clk);
+	return ret;
+}
+
+static int asm9260_pinctrl_remove(struct platform_device *pdev)
+{
+	struct asm9260_pmx_priv *priv = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(priv->clk);
+	pinctrl_unregister(priv->pctl);
+
+	return 0;
+}
+
+static struct of_device_id asm9260_pinctrl_of_match[] = {
+	{ .compatible = "alphascale,asm9260-pinctrl", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, asm9260_pinctrl_of_match);
+
+static struct platform_driver asm9260_pinctrl_driver = {
+	.driver = {
+		.name		= "asm9260-pinctrl",
+		.owner		= THIS_MODULE,
+		.of_match_table	= asm9260_pinctrl_of_match,
+	},
+	.probe	= asm9260_pinctrl_probe,
+	.remove	= asm9260_pinctrl_remove,
+};
+module_platform_driver(asm9260_pinctrl_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
+MODULE_DESCRIPTION("Alphascale ASM9260 pinctrl driver");
+MODULE_LICENSE("GPL");