[RFC PATCH 07/11] pinctrl: Add sun50i-a64 pinctrl driver

Jules Maselbas jmaselbas at zdiv.net
Fri May 19 03:52:01 PDT 2023


On Thu, May 18, 2023 at 09:10:27PM +0200, Ahmad Fatoum wrote:
> On 11.05.23 01:37, Jules Maselbas wrote:
> > sunxi pinctrl driver, adapted from Linux, is split in two parts:
> >  - pinctrl-sunxi.c that implement sunxi-generic gpio and function mux
> >  - pinctrl-sun50i-a64.c that only declare sun50i's pin functions
> 
> Could you describe why the pin functions is needed? Is this just sanity
> checking?
The pin functions are needed: for uart and SD/MMC.
The "only declare" part might be misleading: I meant that pinctrl-sun50i-a64.c
has no code, all logic is in the pinctrl-sunxi.c but actual pin functions
are not described in the device-tree but by structures in pinctrl-sun50i-a64.c
(which is almost a direct copy from Linux)

 
> > ---
> >  drivers/pinctrl/Kconfig                    |   2 +
> >  drivers/pinctrl/Makefile                   |   1 +
> >  drivers/pinctrl/sunxi/Kconfig              |  15 +
> >  drivers/pinctrl/sunxi/Makefile             |   3 +
> >  drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 593 +++++++++++++++++++++
> >  drivers/pinctrl/sunxi/pinctrl-sunxi.c      | 371 +++++++++++++
> >  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 2ff99a39c8..0b3d79d1cc 100644
> > --- a/drivers/pinctrl/Kconfig
> > +++ b/drivers/pinctrl/Kconfig
> > @@ -105,6 +105,8 @@ config PINCTRL_STM32
> >  	default y if ARCH_STM32
> >  	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..36168dc2bb
> > --- /dev/null
> > +++ b/drivers/pinctrl/sunxi/Kconfig
> > @@ -0,0 +1,15 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +if ARCH_SUNXI
> > +
> > +config PINCTRL_SUNXI
> > +	bool
> > +	select PINMUX
> 
> Undefined
> 
> > +	select GENERIC_PINCONF
> 
> Undefined
> 
> > +	select GPIOLIB
> > +
> > +config PINCTRL_SUN50I_A64
> > +	bool "Support for the Allwinner A64 PIO"
> > +	default ARM64 && ARCH_SUNXI
> 
> ARM64 undefined
> 
> > +	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..4a087802c8
> > --- /dev/null
> > +++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
> > @@ -0,0 +1,593 @@
> > +/*
> > + * Allwinner A64 SoCs pinctrl driver.
> > + *
> > + * Copyright (C) 2016 - ARM Ltd.
> > + * Author: Andre Przywara <andre.przywara at arm.com>
> > + *
> > + * Based on pinctrl-sun7i-a20.c, which is:
> > + * Copyright (C) 2014 Maxime Ripard <maxime.ripard at free-electrons.com>
> > + *
> > + * 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.
> 
> SPDX?
> 
> > + */
> > +
> > +#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..e2bde96c70
> > --- /dev/null
> > +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> > @@ -0,0 +1,371 @@
> > +// 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;
> > +
> > +	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 <maxime.ripard at free-electrons.com>
> > + *
> > + * 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 */
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 
> 



More information about the barebox mailing list