sunxi pinctrl driver, adapted from Linux, is split in two parts:
 - pinctrl-sunxi.c that implements gpio, pinctrl and pinmux functions
 - pinctrl-sun50i-a64.c that declare sun50i pins and their functions.
   This file only require minor adaptations and be easily copied from Linux.

The pin functions are needed for uart, SD/MMC, and likely for other
controllers too.

Signed-off-by: Jules Maselbas <[email protected]>
---
 drivers/pinctrl/Kconfig                    |   2 +
 drivers/pinctrl/Makefile                   |   1 +
 drivers/pinctrl/sunxi/Kconfig              |  13 +
 drivers/pinctrl/sunxi/Makefile             |   3 +
 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 594 +++++++++++++++++++++
 drivers/pinctrl/sunxi/pinctrl-sunxi.c      | 372 +++++++++++++
 drivers/pinctrl/sunxi/pinctrl-sunxi.h      | 224 ++++++++
 7 files changed, 1209 insertions(+)
 create mode 100644 drivers/pinctrl/sunxi/Kconfig
 create mode 100644 drivers/pinctrl/sunxi/Makefile
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.h

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index ee15acdcdb..72ca79aa98 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -106,6 +106,8 @@ config PINCTRL_STM32
        select HAVE_GPIO_PINCONF
        help
          Pinmux and GPIO controller found on STM32 family
+
+source "drivers/pinctrl/sunxi/Kconfig"
 endif
 
 endmenu
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f1a5fa5715..3bc718d355 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
 obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
 
 obj-$(CONFIG_ARCH_MVEBU) += mvebu/
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
new file mode 100644
index 0000000000..38d8894a7e
--- /dev/null
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+if ARCH_SUNXI
+
+config PINCTRL_SUNXI
+       bool
+       select GPIOLIB
+
+config PINCTRL_SUN50I_A64
+       bool "Support for Allwinner A64 PIO"
+       default ARCH_SUNXI
+       select PINCTRL_SUNXI
+
+endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
new file mode 100644
index 0000000000..db0ff5b50b
--- /dev/null
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_ARCH_SUNXI)               += pinctrl-sunxi.o
+obj-$(CONFIG_PINCTRL_SUN50I_A64)       += pinctrl-sun50i-a64.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c 
b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
new file mode 100644
index 0000000000..db96cb52b9
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Allwinner A64 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2016 - ARM Ltd.
+ * Author: Andre Przywara <[email protected]>
+ *
+ * Based on pinctrl-sun7i-a20.c, which is:
+ * Copyright (C) 2014 Maxime Ripard <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <common.h>
+#include <init.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin a64_pins[] = {
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "jtag"),          /* MS0 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),  /* EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "jtag"),          /* CK0 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* VCCEN */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),          /* EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION(0x4, "jtag"),          /* DO0 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* VPPEN */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),          /* EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
+                 SUNXI_FUNCTION(0x3, "i2s0"),          /* MCLK */
+                 SUNXI_FUNCTION(0x4, "jtag"),          /* DI0 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* VPPPP */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),          /* EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif2"),          /* SYNC */
+                 SUNXI_FUNCTION(0x3, "i2s0"),          /* SYNC */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* CLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),          /* EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif2"),          /* BCLK */
+                 SUNXI_FUNCTION(0x3, "i2s0"),          /* BCLK */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* DATA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),          /* EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif2"),          /* DOUT */
+                 SUNXI_FUNCTION(0x3, "i2s0"),          /* DOUT */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* RST */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),          /* EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif2"),          /* DIN */
+                 SUNXI_FUNCTION(0x3, "i2s0"),          /* DIN */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* DET */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),          /* EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "uart0"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),          /* EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "uart0"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),          /* EINT9 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
+                 SUNXI_FUNCTION(0x4, "spi0")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
+                 SUNXI_FUNCTION(0x3, "mmc2"),          /* DS */
+                 SUNXI_FUNCTION(0x4, "spi0")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
+                 SUNXI_FUNCTION(0x4, "spi0")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE1 */
+                 SUNXI_FUNCTION(0x4, "spi0")),         /* CS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRE# */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRB1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ4 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ5 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ6 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ7 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQS */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "spi1"),          /* CS */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "spi1"),          /* CLK */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* DE */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D4 */
+                 SUNXI_FUNCTION(0x3, "uart4"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "spi1"),          /* MOSI */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* HSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D5 */
+                 SUNXI_FUNCTION(0x3, "uart4"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "spi1"),          /* MISO */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* VSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D6 */
+                 SUNXI_FUNCTION(0x3, "uart4"),         /* RTS */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D7 */
+                 SUNXI_FUNCTION(0x3, "uart4"),         /* CTS */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D10 */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D11 */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D12 */
+                 SUNXI_FUNCTION(0x4, "emac"),          /* ERXD3 */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D13 */
+                 SUNXI_FUNCTION(0x4, "emac"),          /* ERXD2 */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D14 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ERXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D15 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ERXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D18 */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VP0 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ERXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D19 */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VN0 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ERXCTL */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D20 */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VP1 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ENULL */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D21 */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VN1 */
+                 SUNXI_FUNCTION(0x4, "emac"),          /* ETXD3 */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D22 */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VP2 */
+                 SUNXI_FUNCTION(0x4, "emac"),          /* ETXD2 */
+                 SUNXI_FUNCTION(0x5, "ccir")),         /* D7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D23 */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VN2 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ETXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VPC */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ETXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* DE */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VNC */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ETXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VP3 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ETXCTL */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x3, "lvds0"),         /* VN3 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* ECLKIN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm"),           /* PWM0 */
+                 SUNXI_FUNCTION(0x4, "emac")),         /* EMDC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "emac")),         /* EMDIO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* PCK */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* CK */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* ERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* HSYNC */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* SYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* VSYNC */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* DVLD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D0 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D1 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D2 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D3 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D4 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D5 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D6 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D7 */
+                 SUNXI_FUNCTION(0x4, "ts")),           /* D7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi")),          /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi")),          /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pll"),           /* LOCK_DBG */
+                 SUNXI_FUNCTION(0x3, "i2c2")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "i2c2")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* MSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* DI1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart0")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* DO1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "uart0")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* CK1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),  /* EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)),  /* EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D0 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)),  /* EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)),  /* EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)),  /* EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)),  /* EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)),  /* EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)),  /* EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)),  /* EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)),  /* EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif3"),          /* SYNC */
+                 SUNXI_FUNCTION(0x3, "i2s1"),          /* SYNC */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 10)), /* EINT10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif3"),          /* BCLK */
+                 SUNXI_FUNCTION(0x3, "i2s1"),          /* BCLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 11)), /* EINT11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif3"),          /* DOUT */
+                 SUNXI_FUNCTION(0x3, "i2s1"),          /* DOUT */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 12)), /* EINT12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "aif3"),          /* DIN */
+                 SUNXI_FUNCTION(0x3, "i2s1"),          /* DIN */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 13)), /* EINT13 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0"),          /* SCK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)),  /* EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0"),          /* SDA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)),  /* EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1"),          /* SCK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)),  /* EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1"),          /* SDA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)),  /* EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart3"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)),  /* EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart3"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)),  /* EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart3"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)),  /* EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart3"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)),  /* EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spdif"),         /* OUT */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)),  /* EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)),  /* EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mic"),           /* CLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* EINT10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mic"),           /* DATA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* EINT11 */
+};
+
+static const struct sunxi_pinctrl_desc a64_pinctrl_data = {
+       .pins = a64_pins,
+       .npins = ARRAY_SIZE(a64_pins),
+};
+
+static const struct of_device_id a64_pinctrl_dt_match[] = {
+       {
+               .compatible = "allwinner,sun50i-a64-pinctrl",
+               .data = &a64_pinctrl_data
+       }, {
+               /* sentinel */
+       }
+};
+
+static struct driver a64_pinctrl_driver = {
+       .name           = "sun50i-a64-pinctrl",
+       .probe          = sunxi_pinctrl_probe,
+       .of_compatible  = DRV_OF_COMPAT(a64_pinctrl_dt_match),
+};
+core_platform_driver(a64_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c 
b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
new file mode 100644
index 0000000000..c52acfe140
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "pinctrl-sunxi: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <of.h>
+#include <of_address.h>
+#include <malloc.h>
+#include <linux/clk.h>
+
+#include "pinctrl-sunxi.h"
+
+/* This driver assumes the gpio function mux value will not change */
+#define FUNC_GPIO_IN   0
+#define FUNC_GPIO_OUT  1
+
+static struct sunxi_pinctrl *to_sunxi_pinctrl(struct pinctrl_device *pdev)
+{
+       return container_of(pdev, struct sunxi_pinctrl, pdev);
+}
+
+static void sunxi_pinctrl_set_pull(struct sunxi_pinctrl *pinctrl,
+                                  u16 pin, u32 pull)
+{
+       u32 reg = sunxi_pull_reg(pin);
+       u32 off = sunxi_pull_offset(pin);
+       u32 msk = MUX_PINS_MASK << off;
+       u32 val = readl(pinctrl->base + reg);
+
+       val &= ~msk;
+       val |= (pull << off) & msk;
+       writel(val, pinctrl->base + reg);
+}
+
+static void sunxi_pinctrl_set_dlevel(struct sunxi_pinctrl *pinctrl,
+                                  u16 pin, u32 lvl)
+{
+       u32 reg = sunxi_dlevel_reg(pin);
+       u32 off = sunxi_dlevel_offset(pin);
+       u32 msk = MUX_PINS_MASK << off;
+       u32 val = readl(pinctrl->base + reg);
+
+       val &= ~msk;
+       val |= (lvl << off) & msk;
+       writel(val, pinctrl->base + reg);
+}
+
+static void sunxi_pinctrl_set_mux(struct sunxi_pinctrl *pinctrl,
+                                 u16 pin, u8 mux)
+{
+       u32 reg = sunxi_mux_reg(pin);
+       u32 off = sunxi_mux_offset(pin);
+       u32 msk = MUX_PINS_MASK << off;
+       u32 val = readl(pinctrl->base + reg);
+
+       val &= ~msk;
+       val |= (mux << off) & msk;
+       writel(val, pinctrl->base + reg);
+}
+
+static u8 sunxi_pinctrl_get_mux(struct sunxi_pinctrl *pinctrl, u16 pin)
+{
+       u32 reg = sunxi_mux_reg(pin);
+       u32 off = sunxi_mux_offset(pin);
+       u32 val = readl(pinctrl->base + reg);
+
+       return (val >> off) & MUX_PINS_MASK;
+}
+
+static void sunxi_pinctrl_set_conf(struct sunxi_pinctrl *pinctrl,
+                                 u16 pin, struct device_node *node)
+{
+       u32 val;
+
+       if (of_find_property(node, "bias-pull-up", NULL))
+               sunxi_pinctrl_set_pull(pinctrl, pin, 1);
+       if (of_find_property(node, "bias-pull-down", NULL))
+               sunxi_pinctrl_set_pull(pinctrl, pin, 2);
+       if (of_find_property(node, "bias-disable", NULL))
+               sunxi_pinctrl_set_pull(pinctrl, pin, 0);
+
+       if (!of_property_read_u32(node, "drive-strength", &val)) {
+               val = rounddown(val, 10) / 10 - 1;
+               sunxi_pinctrl_set_dlevel(pinctrl, pin, val);
+       }
+}
+
+static const char *sunxi_pinctrl_parse_function_prop(struct device_node *node)
+{
+       const char *function;
+       int ret;
+
+       /* Try the generic binding */
+       ret = of_property_read_string(node, "function", &function);
+       if (!ret)
+               return function;
+
+       /* And fall back to our legacy one */
+       ret = of_property_read_string(node, "allwinner,function", &function);
+       if (!ret)
+               return function;
+
+       return NULL;
+}
+
+static struct property *sunxi_pinctrl_find_pins_prop(struct device_node *node)
+{
+       struct property *prop;
+
+       /* Try the generic binding */
+       prop = of_find_property(node, "pins", NULL);
+       if (prop)
+               return prop;
+
+       /* And fall back to our legacy one */
+       prop = of_find_property(node, "allwinner,pins", NULL);
+       if (prop)
+               return prop;
+
+       return NULL;
+}
+
+#define sunxi_pinctrl_of_pins_for_each_string(np, prop, s)     \
+       for (prop = sunxi_pinctrl_find_pins_prop(np),           \
+               s = of_prop_next_string(prop, NULL);            \
+               s;                                              \
+               s = of_prop_next_string(prop, s))
+
+
+static const struct sunxi_desc_pin *
+sunxi_pinctrl_find_pin(struct sunxi_pinctrl *pinctrl, const char *pin_name)
+{
+       const struct sunxi_desc_pin *pin;
+       int i;
+
+       for (i = 0; i < pinctrl->desc->npins; i++) {
+               pin = &pinctrl->desc->pins[i];
+               if (!strcmp(pin->pin.name, pin_name))
+                       return pin;
+       }
+
+       return NULL;
+}
+
+static const struct sunxi_desc_function *
+sunxi_pinctrl_find_func(struct sunxi_pinctrl *pinctrl,
+                       const char *pin_name, const char *func_name)
+{
+       const struct sunxi_desc_pin *pin;
+       const struct sunxi_desc_function *func;
+
+       pin = sunxi_pinctrl_find_pin(pinctrl, pin_name);
+       if (!pin)
+               return NULL;
+
+       for (func = pin->functions; func->name; func++)
+               if (!strcmp(func->name, func_name))
+                       return func;
+
+       return NULL;
+}
+
+static int sunxi_pinctrl_set_func(struct sunxi_pinctrl *pinctrl,
+                                 struct device_node *np,
+                                 const char *pin_name, const char *func_name)
+{
+       struct device *dev = pinctrl->pdev.dev;
+       const struct sunxi_desc_pin *pin;
+       const struct sunxi_desc_function *func;
+
+       dev_dbg(dev, "setfunc %s @ %s\n", func_name, pin_name);
+
+       pin = sunxi_pinctrl_find_pin(pinctrl, pin_name);
+       if (!pin) {
+               dev_err(dev, "pin %s not found\n", pin_name);
+               return -EINVAL;
+       }
+
+       func = sunxi_pinctrl_find_func(pinctrl, pin_name, func_name);
+       if (!func) {
+               dev_err(dev, "func %s not found\n", func_name);
+               return -EINVAL;
+       }
+
+       sunxi_pinctrl_set_mux(pinctrl, pin->pin.number, func->muxval);
+       sunxi_pinctrl_set_conf(pinctrl, pin->pin.number, np);
+
+       return 0;
+}
+
+static int sunxi_pinctrl_set_state(struct pinctrl_device *pdev, struct 
device_node *np)
+{
+       struct sunxi_pinctrl *pinctrl = to_sunxi_pinctrl(pdev);
+       struct device *dev = pinctrl->pdev.dev;
+       struct property *prop;
+       const char *func_name;
+       const char *pin_name;
+
+       func_name = sunxi_pinctrl_parse_function_prop(np);
+       if (!func_name) {
+               dev_err(dev, "%s: missing 'function' property\n", 
np->full_name);
+               return -EINVAL;
+       }
+
+       sunxi_pinctrl_of_pins_for_each_string(np, prop, pin_name) {
+               sunxi_pinctrl_set_func(pinctrl, np, pin_name, func_name);
+       }
+
+       return 0;
+}
+
+static int sunxi_pinctrl_set_direction(struct pinctrl_device *pdev, unsigned 
int gpio, bool in)
+{
+       struct sunxi_pinctrl *pinctrl = to_sunxi_pinctrl(pdev);
+       u32 func = in ? FUNC_GPIO_IN : FUNC_GPIO_OUT;
+
+       sunxi_pinctrl_set_mux(pinctrl, gpio, func);
+
+       return 0;
+}
+
+static int sunxi_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+       struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+       u32 reg = sunxi_data_reg(gpio);
+       u32 bit = sunxi_data_offset(gpio);
+       u32 val = readl(pinctrl->base + reg);
+
+       return val & BIT(bit);
+}
+
+static void sunxi_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
+{
+       struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+       u32 reg = sunxi_data_reg(gpio);
+       u32 bit = sunxi_data_offset(gpio);
+       u32 val = readl(pinctrl->base + reg);
+
+       if (value)
+               val |= BIT(bit);
+       else
+               val &= ~BIT(bit);
+       writel(val, pinctrl->base + reg);
+}
+
+static int sunxi_gpio_direction_output(struct gpio_chip *chip,
+                                      unsigned gpio, int value)
+{
+       struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+
+       sunxi_gpio_set(chip, gpio, value);
+       sunxi_pinctrl_set_mux(pinctrl, gpio, FUNC_GPIO_OUT);
+
+       return 0;
+}
+
+static int sunxi_gpio_direction_input(struct gpio_chip *chip,
+                                       unsigned gpio)
+{
+       struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+
+       sunxi_pinctrl_set_mux(pinctrl, gpio, FUNC_GPIO_IN);
+
+       return 0;
+}
+
+static int sunxi_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)
+{
+       struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+       u32 func = sunxi_pinctrl_get_mux(pinctrl, gpio);
+
+       if (func == FUNC_GPIO_IN)
+               return GPIOF_DIR_IN;
+       if (func == FUNC_GPIO_OUT)
+               return GPIOF_DIR_OUT;
+       return -EINVAL;
+}
+
+static int sunxi_gpio_of_xlate(struct gpio_chip *chip,
+                              const struct of_phandle_args *gpiospec,
+                              u32 *flags)
+{
+       int pin, base;
+
+       if (gpiospec->args_count != 3)
+               return -EINVAL;
+
+       base = PINS_PER_BANK * gpiospec->args[0];
+       pin = base + gpiospec->args[1];
+
+       if (pin > chip->ngpio)
+               return -EINVAL;
+
+       if (flags)
+               *flags = gpiospec->args[2];
+
+       return pin;
+}
+
+static struct pinctrl_ops sunxi_pinctrl_ops = {
+       .set_state = sunxi_pinctrl_set_state,
+       .set_direction = sunxi_pinctrl_set_direction,
+};
+
+static struct gpio_ops sunxi_gpio_ops = {
+       .request = sunxi_gpio_direction_input, /* switch to input function */
+       .direction_input = sunxi_gpio_direction_input,
+       .direction_output = sunxi_gpio_direction_output,
+       .get_direction = sunxi_gpio_get_direction,
+       .get = sunxi_gpio_get,
+       .set = sunxi_gpio_set,
+       .of_xlate = sunxi_gpio_of_xlate,
+};
+
+int sunxi_pinctrl_probe(struct device *dev)
+{
+       const struct sunxi_pinctrl_desc *desc;
+       struct sunxi_pinctrl *pinctrl;
+       struct resource *iores;
+       int ret;
+
+       if (!IS_ENABLED(CONFIG_PINCTRL))
+               return 0;
+
+       desc = device_get_match_data(dev);
+       if (!desc)
+                return -EINVAL;
+
+       iores = dev_request_mem_resource(dev, 0);
+       if (IS_ERR(iores))
+               return PTR_ERR(iores);
+
+       pinctrl = xzalloc(sizeof(*pinctrl));
+       dev->priv = pinctrl;
+       pinctrl->base = IOMEM(iores->start);
+
+       pinctrl->desc = desc;
+       pinctrl->pdev.dev = dev;
+       pinctrl->pdev.ops = &sunxi_pinctrl_ops;
+
+       ret = pinctrl_register(&pinctrl->pdev);
+       if (ret) {
+               dev_err(dev, "couldn't register %s driver\n", "pinctrl");
+               goto err;
+       }
+       dev_dbg(dev, "sunxi %s registered\n", "pinctrl");
+
+       pinctrl->chip.dev = dev;
+       pinctrl->chip.ops = &sunxi_gpio_ops;
+       /* only the first 8 bank are supported */
+       pinctrl->chip.base = 0;
+       pinctrl->chip.ngpio = 8 * PINS_PER_BANK;
+       pinctrl->chip.of_gpio_n_cells = 3;
+
+       if (of_property_read_bool(dev->of_node, "gpio-controller")) {
+               ret = gpiochip_add(&pinctrl->chip);
+               if (ret) {
+                       dev_err(dev, "couldn't register %s driver\n", 
"gpio-chip");
+                       goto pinctrl_unregister;
+               }
+               dev_dbg(dev, "sunxi %s registered\n", "gpio-chip");
+       }
+       return 0;
+
+pinctrl_unregister:
+       pinctrl_unregister(&pinctrl->pdev);
+err:
+       release_region(iores);
+       free(pinctrl);
+       return ret;
+}
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h 
b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
new file mode 100644
index 0000000000..630f1ef98e
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Allwinner A1X SoCs pinctrl driver.
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PINCTRL_SUNXI_H
+#define __PINCTRL_SUNXI_H
+
+#include <pinctrl.h>
+#include <gpio.h>
+
+#define PA_BASE        0
+#define PB_BASE        32
+#define PC_BASE        64
+#define PD_BASE        96
+#define PE_BASE        128
+#define PF_BASE        160
+#define PG_BASE        192
+#define PH_BASE        224
+#define PI_BASE        256
+#define PL_BASE        352
+#define PM_BASE        384
+#define PN_BASE        416
+
+#define SUNXI_PIN_NAME_MAX_LEN 5
+
+#define BANK_MEM_SIZE          0x24
+#define MUX_REGS_OFFSET                0x0
+#define DATA_REGS_OFFSET       0x10
+#define DLEVEL_REGS_OFFSET     0x14
+#define PULL_REGS_OFFSET       0x1c
+
+#define PINS_PER_BANK          32
+#define MUX_PINS_PER_REG       8
+#define MUX_PINS_BITS          4
+#define MUX_PINS_MASK          0x0f
+#define DATA_PINS_PER_REG      32
+#define DATA_PINS_BITS         1
+#define DATA_PINS_MASK         0x01
+#define DLEVEL_PINS_PER_REG    16
+#define DLEVEL_PINS_BITS       2
+#define DLEVEL_PINS_MASK       0x03
+#define PULL_PINS_PER_REG      16
+#define PULL_PINS_BITS         2
+#define PULL_PINS_MASK         0x03
+
+#define GRP_CFG_REG            0x300
+
+#define IO_BIAS_MASK           GENMASK(3, 0)
+
+#define SUN4I_FUNC_INPUT       0
+#define SUN4I_FUNC_IRQ         6
+
+#define PINCTRL_SUN5I_A10S     BIT(1)
+#define PINCTRL_SUN5I_A13      BIT(2)
+#define PINCTRL_SUN5I_GR8      BIT(3)
+#define PINCTRL_SUN6I_A31      BIT(4)
+#define PINCTRL_SUN6I_A31S     BIT(5)
+#define PINCTRL_SUN4I_A10      BIT(6)
+#define PINCTRL_SUN7I_A20      BIT(7)
+#define PINCTRL_SUN8I_R40      BIT(8)
+#define PINCTRL_SUN8I_V3       BIT(9)
+#define PINCTRL_SUN8I_V3S      BIT(10)
+
+#define PIO_POW_MOD_SEL_REG    0x340
+
+enum sunxi_desc_bias_voltage {
+       BIAS_VOLTAGE_NONE,
+       /*
+        * Bias voltage configuration is done through
+        * Pn_GRP_CONFIG registers, as seen on A80 SoC.
+        */
+       BIAS_VOLTAGE_GRP_CONFIG,
+       /*
+        * Bias voltage is set through PIO_POW_MOD_SEL_REG
+        * register, as seen on H6 SoC, for example.
+        */
+       BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+};
+
+struct sunxi_desc_function {
+       const char      *name;
+       u8              muxval;
+};
+
+struct sunxi_desc_pin {
+       struct {
+               const char              name[6];
+               u16                     number;
+       } pin;
+       const struct sunxi_desc_function        *functions;
+};
+
+struct sunxi_pinctrl_desc {
+       const struct sunxi_desc_pin     *pins;
+       size_t                          npins;
+       unsigned                        pin_base;
+       bool                            disable_strict_mode;
+       enum sunxi_desc_bias_voltage    io_bias_cfg_variant;
+};
+
+struct sunxi_pinctrl {
+       void __iomem                    *base;
+       struct gpio_chip                chip;
+       struct pinctrl_device           pdev;
+       const struct sunxi_pinctrl_desc *desc;
+};
+
+#define SUNXI_PIN(_pin, ...)                                   \
+       {                                                       \
+               .pin = _pin,                                    \
+               .functions = (struct sunxi_desc_function[]){    \
+                       __VA_ARGS__, { } },                     \
+       }
+
+#define SUNXI_PINCTRL_PIN(bank, pin)                           \
+       {                                                       \
+               .name = "P" #bank #pin,                         \
+               .number = P ## bank ## _BASE + (pin)            \
+       }
+
+#define SUNXI_FUNCTION(_val, _name)                            \
+       {                                                       \
+               .name = _name,                                  \
+               .muxval = _val,                                 \
+       }
+
+#define SUNXI_FUNCTION_IRQ_BANK(...)  {}
+
+/*
+ * The sunXi PIO registers are organized as is:
+ * 0x00 - 0x0c Muxing values.
+ *             8 pins per register, each pin having a 4bits value
+ * 0x10                Pin values
+ *             32 bits per register, each pin corresponding to one bit
+ * 0x14 - 0x18 Drive level
+ *             16 pins per register, each pin having a 2bits value
+ * 0x1c - 0x20 Pull-Up values
+ *             16 pins per register, each pin having a 2bits value
+ *
+ * This is for the first bank. Each bank will have the same layout,
+ * with an offset being a multiple of 0x24.
+ *
+ * The following functions calculate from the pin number the register
+ * and the bit offset that we should access.
+ */
+static inline u32 sunxi_mux_reg(u16 pin)
+{
+       u8 bank = pin / PINS_PER_BANK;
+       u32 offset = bank * BANK_MEM_SIZE;
+       offset += MUX_REGS_OFFSET;
+       offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
+       return round_down(offset, 4);
+}
+
+static inline u32 sunxi_mux_offset(u16 pin)
+{
+       u32 pin_num = pin % MUX_PINS_PER_REG;
+       return pin_num * MUX_PINS_BITS;
+}
+
+static inline u32 sunxi_data_reg(u16 pin)
+{
+       u8 bank = pin / PINS_PER_BANK;
+       u32 offset = bank * BANK_MEM_SIZE;
+       offset += DATA_REGS_OFFSET;
+       offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
+       return round_down(offset, 4);
+}
+
+static inline u32 sunxi_data_offset(u16 pin)
+{
+       u32 pin_num = pin % DATA_PINS_PER_REG;
+       return pin_num * DATA_PINS_BITS;
+}
+
+static inline u32 sunxi_dlevel_reg(u16 pin)
+{
+       u8 bank = pin / PINS_PER_BANK;
+       u32 offset = bank * BANK_MEM_SIZE;
+       offset += DLEVEL_REGS_OFFSET;
+       offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
+       return round_down(offset, 4);
+}
+
+static inline u32 sunxi_dlevel_offset(u16 pin)
+{
+       u32 pin_num = pin % DLEVEL_PINS_PER_REG;
+       return pin_num * DLEVEL_PINS_BITS;
+}
+
+static inline u32 sunxi_pull_reg(u16 pin)
+{
+       u8 bank = pin / PINS_PER_BANK;
+       u32 offset = bank * BANK_MEM_SIZE;
+       offset += PULL_REGS_OFFSET;
+       offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
+       return round_down(offset, 4);
+}
+
+static inline u32 sunxi_pull_offset(u16 pin)
+{
+       u32 pin_num = pin % PULL_PINS_PER_REG;
+       return pin_num * PULL_PINS_BITS;
+}
+
+static inline u32 sunxi_grp_config_reg(u16 pin)
+{
+       u8 bank = pin / PINS_PER_BANK;
+
+       return GRP_CFG_REG + bank * 0x4;
+}
+
+int sunxi_pinctrl_probe(struct device *dev);
+
+#endif /* __PINCTRL_SUNXI_H */
-- 
2.46.2


Reply via email to