
On Thu, Feb 23, 2017 at 7:18 AM, Maxime Ripard maxime.ripard@free-electrons.com wrote:
On Wed, Feb 22, 2017 at 09:47:27PM +0100, Philipp Tomsich wrote:
This change adds a full device-model pinctrl driver for sunxi (tested with sun50iw1p1) based on the support available in Linux.
Details are:
- implements a driver for pinctrl devices and assigns sun50i-a64-pinctrl and sun50i-a64-r-pinctrl to it
- dynamically creates the driver_data for a sunxi_gpio (see sunxi_gpio.c) driver and binds it to the same device-tree node
- lifts and reuses the pinctrl-sunxi.h and pinctrl-sun50i-a64.c files from Linux (thanks to Maxime and Andre) and adds a pinctrl-sun50i-a64-r.c (to be picked up for inclusion into Linux again)
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
arch/arm/include/asm/arch-sunxi/gpio-internal.h | 19 + .../pinctrl/allwinner,pinctrl.txt | 65 +++ drivers/gpio/sunxi_gpio.c | 15 +- drivers/pinctrl/Kconfig | 10 + drivers/pinctrl/Makefile | 2 + drivers/pinctrl/sunxi/Makefile | 10 + drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c | 92 ++++ drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 577 +++++++++++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 317 +++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ 10 files changed, 1411 insertions(+), 7 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/gpio-internal.h create mode 100644 doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt create mode 100644 drivers/pinctrl/sunxi/Makefile create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c 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/arch/arm/include/asm/arch-sunxi/gpio-internal.h b/arch/arm/include/asm/arch-sunxi/gpio-internal.h new file mode 100644 index 0000000..4dcdd34 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/gpio-internal.h @@ -0,0 +1,19 @@ +/*
- (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _SUNXI_GPIO_INTERNAL_H +#define _SUNXI_GPIO_INTERNAL_H
+/* This data structure is shared between the sunxi_gpio driver and
- the sunxi_pinctrl driver.
- */
+struct sunxi_gpio_soc_data {
int start;
int no_banks;
+};
+#endif diff --git a/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt new file mode 100644 index 0000000..946831f --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt @@ -0,0 +1,65 @@ +* Allwinner Pinmux Controller
+Allwinner integrates multiple banks (of 32 pins each) of pin-muxing, +GPIO functionality and (optional) external interrupt functionality +into a single controller.
+For each configurable pad (certain driver-cells, such as the IO from +integrated USB PHYs or DRAM, have a fixed function and can not be +configured), the muxing options (input, output or one of the several +functions) can be selected.
+Properties for the pinctrl node:
- compatible: should be "allwinner,sun50i-pinctrl"
There's a typo here, the compatible is sun50i-a64-pinctrl
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
- clocks: A phandle to the reference clock for this device
(and ideally, this would take three clocks: the bus gate + the two oscillators).
+Properties for the pinconfig sub-nodes:
- allwinner,pins: a list of pins (e.g. "PH2", "PH3") to configure
- allwinner,function: the name of pinmux function (e.g. "mmc2")
allwinner,pins and allwinner,function are also deprecated in favour of pins and function.
- drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA
- bias-pull-up
- bias-pull-down
- bias-disable (default)
The default is not bias-disable, but to keep the current configuration
Shouldn't we just copy the binding docs from the Linux kernel? Afterall they are supposed to be the same.
ChenYu
+Deprecated properties for the pinconfig sub-nodes:
- allwinner,drive: one of <SUN4I_PINCTRL_10_MA>, <SUN4I_PINCTRL_20_MA>,
<SUN4I_PINCTRL_30_MA> or <SUN4I_PINCTRL_40_MA>
- allwinner,pull: one of <SUN4I_PINCTRL_NO_PULL>, <SUN4I_PINCTRL_PULL_UP>
or <SUN4I_PINCTRL_PULL_DOWN>
+Example:
pio: pinctrl@1c20800 {
compatible = "allwinner,sun50i-a64-pinctrl";
reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bus_gates 69>;
gpio-controller;
#gpio-cells = <3>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <1>;
uart0_pins_a: uart0_pins_a {
allwinner,pins = "PB8", "PB9";
allwinner,function = "uart0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
uart0_pins_b: uart0_pins_b {
allwinner,pins = "PF2", "PF3";
allwinner,function = "uart0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 2b7bc7f..fd0c1ac 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -16,6 +16,7 @@ #include <fdtdec.h> #include <malloc.h> #include <asm/arch/gpio.h> +#include <asm/arch/gpio-internal.h> #include <asm/io.h> #include <asm/gpio.h> #include <dm/device-internal.h> @@ -275,11 +276,6 @@ static int gpio_sunxi_probe(struct udevice *dev) return 0; }
-struct sunxi_gpio_soc_data {
int start;
int no_banks;
-};
/**
- We have a top-level GPIO device with no actual GPIOs. It has a child
- device for each Sunxi bank.
@@ -353,18 +349,22 @@ static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun8i-a83t-pinctrl", a_all), ID("allwinner,sun8i-h3-pinctrl", a_all), ID("allwinner,sun9i-a80-pinctrl", a_all), +#if !defined(CONFIG_SUNXI_PINCTRL) /* This is not strictly correct for the A64, as it is missing * bank 'A'. Yet, the register layout in the pinctrl block is * backward compatible and any accesses to the registers that * normally control bank 'A' will have no adverse effect. */
ID("allwinner,sun50i-a64-pinctrl", a_all),
ID("allwinner,sun50i-a64-pinctrl", a_all),
+#endif ID("allwinner,sun6i-a31-r-pinctrl", l_2), ID("allwinner,sun8i-a23-r-pinctrl", l_1), ID("allwinner,sun8i-a83t-r-pinctrl", l_1), ID("allwinner,sun8i-h3-r-pinctrl", l_1), ID("allwinner,sun9i-a80-r-pinctrl", l_3),
ID("allwinner,sun50i-a64-r-pinctrl", l_1),
+#if !defined(CONFIG_SUNXI_PINCTRL)
ID("allwinner,sun50i-a64-r-pinctrl", l_1),
+#endif { } };
@@ -376,4 +376,5 @@ U_BOOT_DRIVER(gpio_sunxi) = { .bind = gpio_sunxi_bind, .probe = gpio_sunxi_probe, };
#endif diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index efcb4c0..064a682 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -175,6 +175,16 @@ config PIC32_PINCTRL by a device tree node which contains both GPIO defintion and pin control functions.
+config SUNXI_PINCTRL
bool "Allwinner Axx pin-control and pin-mux driver"
depends on DM && ARCH_SUNXI
default y
help
Supports pin multiplexing control, drive-strength and bias control on
Allwinner Axx SoCs. The driver is controlled by a device tree node which
contains both the GPIO definitions and the pin control functions for
each multiplex function.
endif
source "drivers/pinctrl/meson/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 512112a..da27a91 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/ \ No newline at end of file diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile new file mode 100644 index 0000000..11549ec --- /dev/null +++ b/drivers/pinctrl/sunxi/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_SUNXI_PINCTRL) += pinctrl-sunxi.o +ifdef CONFIG_SUNXI_PINCTRL +obj-$(CONFIG_MACH_SUN50I) += pinctrl-sun50i-a64.o pinctrl-sun50i-a64-r.o +endif diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c new file mode 100644 index 0000000..864d1ec --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c @@ -0,0 +1,92 @@ +/*
- Allwinner A64 SoCs pinctrl driver.
- Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH.
- Based on pinctrl-sun7i-a20.c, which is:
- Copyright (C) 2014 Maxime Ripard maxime.ripard@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.
- */
+#include <common.h>
+#include "pinctrl-sunxi.h"
+static const struct sunxi_desc_pin a64_r_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_rsb"), /* SCK */
SUNXI_FUNCTION(0x3, "s_i2c"), /* SCK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* EINT0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_rsb"), /* SDA */
SUNXI_FUNCTION(0x3, "s_i2c"), /* SDA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* EINT1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_uart"), /* TX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* EINT2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_uart"), /* RX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* EINT3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* MS */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* EINT4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* CK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* EINT5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* DO */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* EINT6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* DI */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* EINT7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_i2c"), /* SCK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* EINT8 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_i2c"), /* SDA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* EINT9 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_pwm"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* EINT10 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_cir"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* EINT11 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* EINT12 */
+};
+const struct sunxi_pinctrl_desc a64_r_pinctrl_data = {
.pins = a64_r_pins,
.npins = ARRAY_SIZE(a64_r_pins),
.pin_base = PL_BASE,
.irq_banks = 1,
+}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c new file mode 100644 index 0000000..7abea03 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c @@ -0,0 +1,577 @@ +/*
- Allwinner A64 SoCs pinctrl driver.
- Copyright (C) 2016 - ARM Ltd.
- Author: Andre Przywara andre.przywara@arm.com
- Based on pinctrl-sun7i-a20.c, which is:
- Copyright (C) 2014 Maxime Ripard maxime.ripard@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.
- */
+#include <common.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, "csi0"), /* PCK */
SUNXI_FUNCTION(0x4, "ts0")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* CK */
SUNXI_FUNCTION(0x4, "ts0")), /* ERR */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* HSYNC */
SUNXI_FUNCTION(0x4, "ts0")), /* SYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* VSYNC */
SUNXI_FUNCTION(0x4, "ts0")), /* DVLD */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D0 */
SUNXI_FUNCTION(0x4, "ts0")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D1 */
SUNXI_FUNCTION(0x4, "ts0")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D2 */
SUNXI_FUNCTION(0x4, "ts0")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D3 */
SUNXI_FUNCTION(0x4, "ts0")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D4 */
SUNXI_FUNCTION(0x4, "ts0")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D5 */
SUNXI_FUNCTION(0x4, "ts0")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D6 */
SUNXI_FUNCTION(0x4, "ts0")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D7 */
SUNXI_FUNCTION(0x4, "ts0")), /* D7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0")), /* 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(0x4, "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 */
+};
+const struct sunxi_pinctrl_desc a64_pinctrl_data = {
.pins = a64_pins,
.npins = ARRAY_SIZE(a64_pins),
.irq_banks = 3,
+}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c new file mode 100644 index 0000000..4640cee --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -0,0 +1,317 @@ +/*
- (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
- In parts based on linux/drivers/pinctrl/pinctrl-sunxi.c, which is
- Copyright (C) 2012 Maxime Ripard
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/gpio.h> +#include <asm/arch/gpio-internal.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> +#include <dt-bindings/gpio/gpio.h> +#include <linux/kernel.h> +#include "pinctrl-sunxi.h"
+DECLARE_GLOBAL_DATA_PTR;
+struct sunxi_pctrl_priv {
void *base;
+#if defined(CONFIG_DM_GPIO)
struct sunxi_gpio_soc_data gpio_soc_data;
struct udevice *gpio_dev;
+#endif +};
+static int sunxi_pctrl_parse_drive_prop(const void *blob, int node) +{
int val;
/* Try the new style binding */
val = fdtdec_get_int(blob, node, "drive-strength", -EINVAL);
if (val >= 0) {
/* We can't go below 10mA ... */
if (val < 10)
return -EINVAL;
/* ... and only up to 40 mA ... */
if (val > 40)
val = 40;
/* by steps of 10 mA */
return rounddown(val, 10);
}
/* And then fall back to the old binding */
val = fdtdec_get_int(blob, node, "allwinner,drive", -EINVAL);
if (val < 0)
return -EINVAL;
return (val + 1) * 10;
+}
+static int sunxi_pctrl_parse_bias_prop(const void *blob, int node) +{
/* Try the new style binding */
if (fdtdec_get_bool(blob, node, "bias-pull-up"))
return SUN4I_PINCTRL_PULL_UP;
if (fdtdec_get_bool(blob, node, "bias-pull-down"))
return SUN4I_PINCTRL_PULL_DOWN;
if (fdtdec_get_bool(blob, node, "bias-disable"))
return SUN4I_PINCTRL_NO_PULL;
/* And fall back to the old binding */
return fdtdec_get_int(blob, node, "allwinner,pull", -EINVAL);
+}
+static const struct sunxi_desc_pin *sunxi_pctrl_pin_by_name(struct udevice *dev,
const char *name)
+{
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
int i;
for (i = 0; i < data->npins; ++i)
if (!strcmp(data->pins[i].pin.name, name))
return &data->pins[i];
return NULL;
+}
+static int sunxi_pctrl_muxval_by_name(const struct sunxi_desc_pin *pin,
const char *name)
+{
const struct sunxi_desc_function *func;
if (!pin)
return -EINVAL;
for (func = pin->functions; func->name; func++)
if (!strcmp(func->name, name))
return func->muxval;
return -ENOENT;
+}
+static void sunxi_pctrl_set_function(struct udevice *dev,
unsigned pin, int function)
+{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
u32 val, mask;
if (function < 0)
return;
pin -= data->pin_base;
mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
val = function << sunxi_mux_offset(pin);
clrsetbits_le32(priv->base + sunxi_mux_reg(pin), mask, val);
+}
+static void sunxi_pctrl_set_dlevel(struct udevice *dev,
unsigned pin, int dlevel)
+{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
u32 val, mask;
if (dlevel < 0)
return;
pin -= data->pin_base;
mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(pin);
val = dlevel << sunxi_dlevel_offset(pin);
clrsetbits_le32(priv->base + sunxi_dlevel_reg(pin), mask, val);
+}
+static void sunxi_pctrl_set_bias(struct udevice *dev,
unsigned pin, int bias)
+{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
u32 val, mask;
if (bias < 0)
return;
pin -= data->pin_base;
mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
val = bias << sunxi_pull_offset(pin);
clrsetbits_le32(priv->base + sunxi_pull_reg(pin), mask, val);
+}
+static int sunxi_pctrl_set_state(struct udevice *dev, struct udevice *config) +{
const char *pins;
const char *function;
int flen;
int len, curr_len;
int drive, bias;
int muxval;
debug("%s: %s %s\n", __func__, dev->name, config->name);
pins = fdt_getprop(gd->fdt_blob, config->of_offset,
"allwinner,pins", &len);
if (!pins) {
debug("%s: missing allwinner,pins property in node %s\n",
dev->name, config->name);
return -EINVAL;
}
function = fdt_getprop(gd->fdt_blob, config->of_offset,
"allwinner,function", &flen);
if (!function) {
debug("%s: missing allwinner,function property in node %s\n",
dev->name, config->name);
return -EINVAL;
}
drive = sunxi_pctrl_parse_drive_prop(gd->fdt_blob, config->of_offset);
bias = sunxi_pctrl_parse_bias_prop(gd->fdt_blob, config->of_offset);
debug("%s: function %s, drive %d, bias %d\n",
config->name, function, drive, bias);
/* Iterate through the pins and configure each */
while (len && (curr_len = strnlen(pins, len))) {
const struct sunxi_desc_pin *pin;
if (curr_len == len) {
error("%s: unterminated string?", __func__);
break;
}
pin = sunxi_pctrl_pin_by_name(dev, pins);
if (pin) {
muxval = sunxi_pctrl_muxval_by_name(pin, function);
sunxi_pctrl_set_function(dev, pin->pin.number, muxval);
sunxi_pctrl_set_dlevel(dev, pin->pin.number, drive);
sunxi_pctrl_set_bias(dev, pin->pin.number, bias);
} else {
debug("%s: could not find pin %s\n", dev->name, pins);
}
/* advance */
pins += (curr_len + 1);
len -= (curr_len + 1);
}
return 0;
+}
+static inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data,
struct sunxi_gpio_soc_data *soc_data)
+{
int i;
unsigned pinnum;
unsigned low = data->pin_base / PINS_PER_BANK;
unsigned high = data->pin_base;
for (i = 0; i < data->npins; ++i) {
pinnum = data->pins[i].pin.number;
high = max(high, pinnum);
}
/* convert pin-numbers to bank numbers */
high /= PINS_PER_BANK;
soc_data->start = low;
soc_data->no_banks = high - low + 1;
+}
+static int sunxi_pctrl_bind_gpio(struct udevice *dev) +{ +#if defined(CONFIG_DM_GPIO)
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
struct driver *gpio_driver;
char name[20];
int ret;
/* Fill the soc_data for the gpio driver from the pinctrl_desc */
soc_data_from_desc(data, &priv->gpio_soc_data);
gpio_driver = lists_driver_lookup_name("gpio_sunxi");
if (!gpio_driver)
return -ENOENT;
ret = device_bind_with_driver_data(dev, gpio_driver, "sunxi_gpio",
(ulong)&priv->gpio_soc_data,
dev->of_offset, &priv->gpio_dev);
if (ret < 0)
return ret;
snprintf(name, sizeof(name), "sunxi_gpio@%x", (uint32_t)priv->base);
device_set_name(priv->gpio_dev, name);
+#endif
return 0;
+}
+static int sunxi_pctrl_probe(struct udevice *dev) +{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
fdt_addr_t addr_base;
fdt_size_t size;
addr_base = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob,
dev->of_offset,
"reg", 0, &size,
false);
if (addr_base == FDT_ADDR_T_NONE)
return -EINVAL;
priv->base = (void *)addr_base;
return sunxi_pctrl_bind_gpio(dev);
+}
+static struct pinctrl_ops sunxi_pctrl_ops = {
.set_state = sunxi_pctrl_set_state,
+};
+#if defined(CONFIG_MACH_SUN50I) +extern const struct sunxi_pinctrl_desc a64_pinctrl_data; +extern const struct sunxi_pinctrl_desc a64_r_pinctrl_data; +#endif
+static const struct udevice_id sunxi_pctrl_ids[] = { +#if defined(CONFIG_MACH_SUN50I)
{ .compatible = "allwinner,sun50i-a64-pinctrl",
.data = (ulong)&a64_pinctrl_data },
{ .compatible = "allwinner,sun50i-a64-r-pinctrl",
.data = (ulong)&a64_r_pinctrl_data },
+#endif
{ }
+};
+U_BOOT_DRIVER(pinctrl_sunxi) = {
.name = "sunxi_pctrl",
.id = UCLASS_PINCTRL,
.of_match = sunxi_pctrl_ids,
.priv_auto_alloc_size = sizeof(struct sunxi_pctrl_priv),
.ops = &sunxi_pctrl_ops,
.bind = dm_scan_fdt_dev,
.probe = sunxi_pctrl_probe,
+};
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h new file mode 100644 index 0000000..8508626 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -0,0 +1,311 @@ +/*
- Allwinner A1X SoCs pinctrl driver.
- Copyright (C) 2012 Maxime Ripard
- Maxime Ripard maxime.ripard@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
+#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
+#ifdef __UBOOT__ +/* Convenience macro to define a single named or anonymous pin descriptor */ +#define PINCTRL_PIN(a, b) { .number = a, .name = b }
+/**
- struct pinctrl_pin_desc - boards/machines provide information on their
- pins, pads or other muxable units in this struct
- @number: unique pin number from the global pin number space
- @name: a name for this pin
- @drv_data: driver-defined per-pin data. pinctrl core does not touch this
- */
+struct pinctrl_pin_desc {
unsigned number;
const char *name;
+#ifndef __UBOOT__
void *drv_data;
+#endif +}; +#endif
+#define SUNXI_PINCTRL_PIN(bank, pin) \
PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin)
+#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 IRQ_PER_BANK 32
+#define IRQ_CFG_REG 0x200 +#define IRQ_CFG_IRQ_PER_REG 8 +#define IRQ_CFG_IRQ_BITS 4 +#define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1) +#define IRQ_CTRL_REG 0x210 +#define IRQ_CTRL_IRQ_PER_REG 32 +#define IRQ_CTRL_IRQ_BITS 1 +#define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1) +#define IRQ_STATUS_REG 0x214 +#define IRQ_STATUS_IRQ_PER_REG 32 +#define IRQ_STATUS_IRQ_BITS 1 +#define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1)
+#define IRQ_MEM_SIZE 0x20
+#define IRQ_EDGE_RISING 0x00 +#define IRQ_EDGE_FALLING 0x01 +#define IRQ_LEVEL_HIGH 0x02 +#define IRQ_LEVEL_LOW 0x03 +#define IRQ_EDGE_BOTH 0x04
+#define SUN4I_FUNC_INPUT 0 +#define SUN4I_FUNC_IRQ 6
+struct sunxi_desc_function {
const char *name;
u8 muxval;
u8 irqbank;
u8 irqnum;
+};
+struct sunxi_desc_pin {
struct pinctrl_pin_desc pin;
struct sunxi_desc_function *functions;
+};
+struct sunxi_pinctrl_desc {
const struct sunxi_desc_pin *pins;
int npins;
unsigned pin_base;
unsigned irq_banks;
unsigned irq_bank_base;
bool irq_read_needs_mux;
+};
+struct sunxi_pinctrl_function {
const char *name;
const char **groups;
unsigned ngroups;
+};
+struct sunxi_pinctrl_group {
const char *name;
unsigned long config;
unsigned pin;
+};
+#ifndef __UBOOT__ +struct sunxi_pinctrl {
void __iomem *membase;
struct gpio_chip *chip;
const struct sunxi_pinctrl_desc *desc;
struct device *dev;
struct irq_domain *domain;
struct sunxi_pinctrl_function *functions;
unsigned nfunctions;
struct sunxi_pinctrl_group *groups;
unsigned ngroups;
int *irq;
unsigned *irq_array;
spinlock_t lock;
struct pinctrl_dev *pctl_dev;
+}; +#endif
+#define SUNXI_PIN(_pin, ...) \
{ \
.pin = _pin, \
.functions = (struct sunxi_desc_function[]){ \
__VA_ARGS__, { } }, \
}
+#define SUNXI_FUNCTION(_val, _name) \
{ \
.name = _name, \
.muxval = _val, \
}
+#define SUNXI_FUNCTION_IRQ(_val, _irq) \
{ \
.name = "irq", \
.muxval = _val, \
.irqnum = _irq, \
}
+#define SUNXI_FUNCTION_IRQ_BANK(_val, _bank, _irq) \
{ \
.name = "irq", \
.muxval = _val, \
.irqbank = _bank, \
.irqnum = _irq, \
}
+/*
- 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_irq_cfg_reg(u16 irq, unsigned bank_base) +{
u8 bank = irq / IRQ_PER_BANK;
u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04;
return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg;
+}
+static inline u32 sunxi_irq_cfg_offset(u16 irq) +{
u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG;
return irq_num * IRQ_CFG_IRQ_BITS;
+}
+static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank, unsigned bank_base) +{
return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE;
+}
+static inline u32 sunxi_irq_ctrl_reg(u16 irq, unsigned bank_base) +{
u8 bank = irq / IRQ_PER_BANK;
return sunxi_irq_ctrl_reg_from_bank(bank, bank_base);
+}
+static inline u32 sunxi_irq_ctrl_offset(u16 irq) +{
u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG;
return irq_num * IRQ_CTRL_IRQ_BITS;
+}
+static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base) +{
return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;
+}
+static inline u32 sunxi_irq_status_reg(u16 irq, unsigned bank_base) +{
u8 bank = irq / IRQ_PER_BANK;
return sunxi_irq_status_reg_from_bank(bank, bank_base);
+}
+static inline u32 sunxi_irq_status_offset(u16 irq) +{
u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG;
return irq_num * IRQ_STATUS_IRQ_BITS;
+}
+#ifndef __UBOOT__ +int sunxi_pinctrl_init(struct platform_device *pdev,
const struct sunxi_pinctrl_desc *desc);
+#endif
+#endif /* __PINCTRL_SUNXI_H */
1.9.1
-- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com