[U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation

Here's v2, which incorporates the feedback from Maxime and ChenYu into a more complete and less intrusive version.
The most elegant solution to our problem with pinctrl & gpio, which will also work equally well for ccu and reset, is to have the device model bind multiple drivers to a single node: for this reason, one patch of the series touches the device-model core.
To provide a bit more context, I've also include the change showing how this is enabled in our defconfig (i.e. a diff against our defconfig, even though the defconfig has not been submitted yet).
Changes in v2: * two variants to reuse the sunxi_gpio layer: - create a matching soc_data for sunxi_gpio and rebind - have the device-model do this for us * got rid of the gpio-banks and gpiobridge drivers
Philipp Tomsich (6): sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi dm: core: Allow multiple drivers to bind for a single node sunxi: CONFIG_DM_ALLOW_MULTIPLE_DRIVERS for gpio/pinctrl binding defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS sun50i: dts: add r_pio node and pinconfig entries into r_pio and pio sun50i: dts: update DTS to avoid warnings
arch/arm/dts/sun50i-a64.dtsi | 62 ++- arch/arm/include/asm/arch-sunxi/gpio-internal.h | 19 + configs/lynx_defconfig | 1 + .../pinctrl/allwinner,pinctrl.txt | 65 +++ drivers/core/Kconfig | 14 + drivers/core/lists.c | 12 +- 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 | 321 ++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ 14 files changed, 1479 insertions(+), 32 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

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" + - 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 + +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") + - drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA + - bias-pull-up + - bias-pull-down + - bias-disable (default) + +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 */

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
+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

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

On Thu, Feb 23, 2017 at 11:54:15AM +0800, Chen-Yu Tsai wrote:
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.
Yep, that would probably be the easiest.
Maxime

Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found.
The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture: * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to bind against a single node * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to bind against a single node
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- drivers/core/Kconfig | 14 ++++++++++++++ drivers/core/lists.c | 12 +++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 8749561..913101c 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -31,6 +31,20 @@ config DM_WARN This will cause dm_warn() to be compiled out - it will do nothing when called.
+config DM_ALLOW_MULTIPLE_DRIVERS + bool "Allow multiple drivers to bind for one node" + depends on DM + default n + help + The driver model in U-Boot originally did not allow multiple + drivers to bind for a single device node. + + If enabled, multiple drivers can now bind for a single node + by using the same compatible string for matching: lists_bind_fdt() + will assume that binding multiple drivers is desirable, if the + caller does not request the pointer to the udevice structure to + be returned (i.e. if devp is NULL). + config DM_DEVICE_REMOVE bool "Support device removal" depends on DM diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 23b6ba7..52efe69 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -166,7 +166,11 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, dm_dbg(" - attempt to match compatible string '%s'\n", compat);
- for (entry = driver; entry != driver + n_ents; entry++) { + entry = driver; +#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) + allow_more_matches: +#endif + for (; entry != driver + n_ents; entry++) { ret = driver_check_compatible(entry->of_match, &id, compat); if (!ret) @@ -190,6 +194,12 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, found = true; if (devp) *devp = dev; +#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) + else { + entry++; + goto allow_more_matches; + } +#endif } break; }

Hi Philipp,
On 22 February 2017 at 13:47, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found.
The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture:
- pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to bind against a single node
- clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to bind against a single node
Does linux work this way? Another approach would be to have a separate MISC driver with two children, one pinctrl, one clk.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
drivers/core/Kconfig | 14 ++++++++++++++ drivers/core/lists.c | 12 +++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 8749561..913101c 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -31,6 +31,20 @@ config DM_WARN This will cause dm_warn() to be compiled out - it will do nothing when called.
+config DM_ALLOW_MULTIPLE_DRIVERS
bool "Allow multiple drivers to bind for one node"
depends on DM
default n
You should be able to drop this line.
help
The driver model in U-Boot originally did not allow multiple
drivers to bind for a single device node.
If enabled, multiple drivers can now bind for a single node
by using the same compatible string for matching: lists_bind_fdt()
will assume that binding multiple drivers is desirable, if the
caller does not request the pointer to the udevice structure to
be returned (i.e. if devp is NULL).
Please update the function documentation in the header file.
config DM_DEVICE_REMOVE bool "Support device removal" depends on DM diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 23b6ba7..52efe69 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -166,7 +166,11 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, dm_dbg(" - attempt to match compatible string '%s'\n", compat);
for (entry = driver; entry != driver + n_ents; entry++) {
entry = driver;
+#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS)
allow_more_matches:
+#endif
for (; entry != driver + n_ents; entry++) { ret = driver_check_compatible(entry->of_match, &id, compat); if (!ret)
@@ -190,6 +194,12 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, found = true; if (devp) *devp = dev; +#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS)
Can you make this a variable, e.g. with allow_multiple = IS_ENABLED(DM_ALLOW_MULTIPLE_DRIVERS)? I'd prefer not to add #ifdefs in this file.
else {
entry++;
goto allow_more_matches;
Is it possible to loop without using goto?
}
+#endif } break; } -- 1.9.1
Regards, Simon

Hi Simon,
On 03 Mar 2017, at 05:52, Simon Glass sjg@chromium.org wrote:
Hi Philipp,
On 22 February 2017 at 13:47, Philipp Tomsich <philipp.tomsich@theobroma-systems.com mailto:philipp.tomsich@theobroma-systems.com> wrote:
Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found.
The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture:
- pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to bind against a single node
- clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to bind against a single node
Does linux work this way? Another approach would be to have a separate MISC driver with two children, one pinctrl, one clk.
The linux CLK driver creates and registers a reset-controller; the PINCTRL driver does the same with the gpio-controller. Similar code to do this is easily possible in U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series.
However, binding multiple times makes for much simpler code and allows to keep driver data in separate drivers.
Regards, Philipp.

Hi,
On 3 March 2017 at 03:52, Dr. Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Hi Simon,
On 03 Mar 2017, at 05:52, Simon Glass sjg@chromium.org wrote:
Hi Philipp,
On 22 February 2017 at 13:47, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found.
The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture:
- pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to bind against a single node
- clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to bind against a single node
Does linux work this way? Another approach would be to have a separate MISC driver with two children, one pinctrl, one clk.
The linux CLK driver creates and registers a reset-controller; the PINCTRL driver does the same with the gpio-controller. Similar code to do this is easily possible in U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series.
However, binding multiple times makes for much simpler code and allows to keep driver data in separate drivers.
My question was more whether Linux registers multiple drivers with one device node. It's just not something I expected.
I'm not really convinced on this. It will break the current one-to-one relationship, and functions like device_get_child_by_of_offset(). I think it would be better to have a MISC driver with two children.
Regards, Simon

Hi Simon,
Am Sonntag, 12. März 2017, 14:21:35 CET schrieb Simon Glass:
On 3 March 2017 at 03:52, Dr. Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
On 03 Mar 2017, at 05:52, Simon Glass sjg@chromium.org wrote: On 22 February 2017 at 13:47, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found.
The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture:
pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to
bind against a single node
clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to
bind against a single node
Does linux work this way? Another approach would be to have a separate MISC driver with two children, one pinctrl, one clk.
The linux CLK driver creates and registers a reset-controller; the PINCTRL driver does the same with the gpio-controller. Similar code to do this is easily possible in U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series.
However, binding multiple times makes for much simpler code and allows to keep driver data in separate drivers.
My question was more whether Linux registers multiple drivers with one device node. It's just not something I expected.
I'm not really convinced on this. It will break the current one-to-one relationship, and functions like device_get_child_by_of_offset(). I think it would be better to have a MISC driver with two children.
In the regular device model the Linux kernel also generally has a one-to-one model. There are special cases, like clock and timer init using special handling, or things like "syscon" which acts like more of a flag and can live next to a regular device.
Therefore things like the Rockchip clock controller create the reset controller included in the CRU block. A behaviour the uboot clk driver mimics.
Also doesn't allowing multiple drivers to sit on top of a node create contention on who gets access to registers? At least in the kernel multiple mappings of registers are generally not favoured.
Heiko

On Sun, Mar 12, 2017 at 02:21:35PM -0600, Simon Glass wrote:
Hi,
On 3 March 2017 at 03:52, Dr. Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Hi Simon,
On 03 Mar 2017, at 05:52, Simon Glass sjg@chromium.org wrote:
Hi Philipp,
On 22 February 2017 at 13:47, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found.
The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture:
- pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to bind against a single node
- clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to bind against a single node
Does linux work this way? Another approach would be to have a separate MISC driver with two children, one pinctrl, one clk.
The linux CLK driver creates and registers a reset-controller; the PINCTRL driver does the same with the gpio-controller. Similar code to do this is easily possible in U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series.
However, binding multiple times makes for much simpler code and allows to keep driver data in separate drivers.
My question was more whether Linux registers multiple drivers with one device node. It's just not something I expected.
It does, but it's not really what we're doing in the linux driver. It has one driver, with one device, but registering into multiple frameworks.
Maxime

Hi,
On 20 March 2017 at 01:08, Maxime Ripard maxime.ripard@free-electrons.com wrote:
On Sun, Mar 12, 2017 at 02:21:35PM -0600, Simon Glass wrote:
Hi,
On 3 March 2017 at 03:52, Dr. Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Hi Simon,
On 03 Mar 2017, at 05:52, Simon Glass sjg@chromium.org wrote:
Hi Philipp,
On 22 February 2017 at 13:47, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found.
The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture:
- pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to bind against a single node
- clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to bind against a single node
Does linux work this way? Another approach would be to have a separate MISC driver with two children, one pinctrl, one clk.
The linux CLK driver creates and registers a reset-controller; the PINCTRL driver does the same with the gpio-controller. Similar code to do this is easily possible in U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series.
However, binding multiple times makes for much simpler code and allows to keep driver data in separate drivers.
My question was more whether Linux registers multiple drivers with one device node. It's just not something I expected.
It does, but it's not really what we're doing in the linux driver. It has one driver, with one device, but registering into multiple frameworks.
I believe that the U-Boot equivalent of this is to have a parent device with several children each in its own uclass.
Regards, Simon

Our gpio and pinctrl driver need to be bound against the same node. While this can be done by hand (i.e. explicitly looking up the driver, creating the driver-data and binding the device), it is much easier done when the new option for the binding of multiple drivers against a single node is configured.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- drivers/gpio/sunxi_gpio.c | 4 ++-- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index fd0c1ac..cbec1b9 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -349,7 +349,7 @@ 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) +#if !defined(CONFIG_SUNXI_PINCTRL) || defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) /* 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 @@ -362,7 +362,7 @@ static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun8i-a83t-r-pinctrl", l_1), ID("allwinner,sun8i-h3-r-pinctrl", l_1), ID("allwinner,sun9i-a80-r-pinctrl", l_3), -#if !defined(CONFIG_SUNXI_PINCTRL) +#if !defined(CONFIG_SUNXI_PINCTRL) || defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) ID("allwinner,sun50i-a64-r-pinctrl", l_1), #endif { } diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 4640cee..445707e 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -14,7 +14,9 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/gpio.h> +#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) #include <asm/arch/gpio-internal.h> +#endif #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/pinctrl.h> @@ -27,7 +29,7 @@ DECLARE_GLOBAL_DATA_PTR;
struct sunxi_pctrl_priv { void *base; -#if defined(CONFIG_DM_GPIO) +#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) struct sunxi_gpio_soc_data gpio_soc_data; struct udevice *gpio_dev; #endif @@ -217,6 +219,7 @@ static int sunxi_pctrl_set_state(struct udevice *dev, struct udevice *config) return 0; }
+#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) static inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data, struct sunxi_gpio_soc_data *soc_data) { @@ -236,10 +239,11 @@ static inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data, soc_data->start = low; soc_data->no_banks = high - low + 1; } +#endif
static int sunxi_pctrl_bind_gpio(struct udevice *dev) { -#if defined(CONFIG_DM_GPIO) +#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) struct sunxi_pctrl_priv *priv = dev_get_priv(dev); const struct sunxi_pinctrl_desc *data = (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);

Now that we have the new functionality to allow multiple drivers to bind for a single node, we want to enable it for the A64-uQ7.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- configs/lynx_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/lynx_defconfig b/configs/lynx_defconfig index 7b773f1..0fba279 100644 --- a/configs/lynx_defconfig +++ b/configs/lynx_defconfig @@ -2,6 +2,7 @@ CONFIG_ARM=y CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y CONFIG_ARCH_SUNXI=y CONFIG_MACH_SUN50I=y +CONFIG_DM_ALLOW_MULTIPLE_DRIVERS=y CONFIG_PINCTRL=y CONFIG_SUNXI_PINCTRL=y CONFIG_CLK=y

On Wed, Feb 22, 2017 at 09:47:30PM +0100, Philipp Tomsich wrote:
Now that we have the new functionality to allow multiple drivers to bind for a single node, we want to enable it for the A64-uQ7.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
configs/lynx_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/lynx_defconfig b/configs/lynx_defconfig index 7b773f1..0fba279 100644 --- a/configs/lynx_defconfig +++ b/configs/lynx_defconfig @@ -2,6 +2,7 @@ CONFIG_ARM=y CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y CONFIG_ARCH_SUNXI=y CONFIG_MACH_SUN50I=y +CONFIG_DM_ALLOW_MULTIPLE_DRIVERS=y
I guess it would be better to just put the default value in Kconfig as MACH_SUN50I or even ARCH_SUNXI to enable it for all the boards
Maxime

To sync up with use of a pinctrl-driver, this updates the DTS.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- arch/arm/dts/sun50i-a64.dtsi | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index 24406d0..54b68e0 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -376,9 +376,9 @@ gpio-controller; #gpio-cells = <3>; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <3>;
- uart0_pins_a: uart0@0 { + uart0_pins_a: uart0_pins_a { allwinner,pins = "PB8", "PB9"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; @@ -532,10 +532,9 @@ reg = <0x01f02c00 0x400>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; + #gpio-cells = <3>; interrupt-controller; #interrupt-cells = <3>; - #size-cells = <0>; - #gpio-cells = <3>; };
ahb_rst: reset@1c202c0 {

Nodes that don't contain a reg-entry should not have an @xxx name attached. To silence the dt-compiler warnings, we update the DTS.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- arch/arm/dts/sun50i-a64.dtsi | 57 ++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 21 deletions(-)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index 54b68e0..4911d6a 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -88,7 +88,7 @@ method = "smc"; };
- memory { + memory: memory@40000000 { device_type = "memory"; reg = <0x40000000 0>; }; @@ -378,84 +378,84 @@ interrupt-controller; #interrupt-cells = <3>;
- uart0_pins_a: uart0_pins_a { + 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@1 { + 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>; };
- uart1_2pins: uart1_2@0 { + uart1_2pins: uart1-2pins { allwinner,pins = "PG6", "PG7"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart1_4pins: uart1_4@0 { + uart1_4pins: uart1-4pins { allwinner,pins = "PG6", "PG7", "PG8", "PG9"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart2_2pins: uart2_2@0 { + uart2_2pins: uart2-2pins { allwinner,pins = "PB0", "PB1"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart2_4pins: uart2_4@0 { + uart2_4pins: uart2-4pins { allwinner,pins = "PB0", "PB1", "PB2", "PB3"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart3_pins_a: uart3@0 { + uart3_pins_a: uart3-pins-a { allwinner,pins = "PD0", "PD1"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart3_2pins_b: uart3_2@1 { + uart3_2pins_b: uart3-2pins-b { allwinner,pins = "PH4", "PH5"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart3_4pins_b: uart3_4@1 { + uart3_4pins_b: uart3-4pins-b { allwinner,pins = "PH4", "PH5", "PH6", "PH7"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart4_2pins: uart4_2@0 { + uart4_2pins: uart4-2pins { allwinner,pins = "PD2", "PD3"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart4_4pins: uart4_4@0 { + uart4_4pins: uart4-4pins { allwinner,pins = "PD2", "PD3", "PD4", "PD5"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- mmc0_pins: mmc0@0 { + mmc0_pins: mmc0-pins { allwinner,pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; allwinner,function = "mmc0"; @@ -463,14 +463,14 @@ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- mmc0_default_cd_pin: mmc0_cd_pin@0 { + mmc0_default_cd_pin: mmc0-cd-pin { allwinner,pins = "PF6"; allwinner,function = "gpio_in"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_PULL_UP>; };
- mmc1_pins: mmc1@0 { + mmc1_pins: mmc1-pins { allwinner,pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5"; allwinner,function = "mmc1"; @@ -478,36 +478,51 @@ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- mmc2_pins: mmc2@0 { + mmc2_pins: mmc2-pins { allwinner,pins = "PC1", "PC5", "PC6", "PC8", "PC9", "PC10"; allwinner,function = "mmc2"; +<<<<<<< HEAD allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; +======= + drive-strength = < 30 >; + bias-pull-up; };
- i2c0_pins: i2c0_pins { + mmc2_8bit_pins: mmc2-8bit { + allwinner,pins = "PC5", "PC6", "PC8", + "PC9", "PC10", "PC11", + "PC12", "PC13", "PC14", + "PC15", "PC16"; + allwinner,function = "mmc2"; + drive-strength = < 30 >; + bias-pull-up; +>>>>>>> 20221b3... [f] dts warnings + }; + + i2c0_pins: i2c0-pins { allwinner,pins = "PH0", "PH1"; allwinner,function = "i2c0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- i2c1_pins: i2c1_pins { + i2c1_pins: i2c1-pins { allwinner,pins = "PH2", "PH3"; allwinner,function = "i2c1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- i2c2_pins: i2c2_pins { + i2c2_pins: i2c2-pins { allwinner,pins = "PE14", "PE15"; allwinner,function = "i2c2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- rmii_pins: rmii_pins { + rmii_pins: rmii-pins { allwinner,pins = "PD10", "PD11", "PD13", "PD14", "PD17", "PD18", "PD19", "PD20", "PD22", "PD23"; @@ -516,7 +531,7 @@ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- rgmii_pins: rgmii_pins { + rgmii_pins: rgmii-pins { allwinner,pins = "PD8", "PD9", "PD10", "PD11", "PD12", "PD13", "PD15", "PD16", "PD17", "PD18", "PD19",

On Wed, Feb 22, 2017 at 09:47:32PM +0100, Philipp Tomsich wrote:
+<<<<<<< HEAD allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; +=======
drive-strength = < 30 >;
bias-pull-up; };
i2c0_pins: i2c0_pins {
mmc2_8bit_pins: mmc2-8bit {
allwinner,pins = "PC5", "PC6", "PC8",
"PC9", "PC10", "PC11",
"PC12", "PC13", "PC14",
"PC15", "PC16";
allwinner,function = "mmc2";
drive-strength = < 30 >;
bias-pull-up;
+>>>>>>> 20221b3... [f] dts warnings
Hmmm, are you sure about those ? :)

On 23 Feb 2017, at 00:20, Maxime Ripard maxime.ripard@free-electrons.com wrote:
On Wed, Feb 22, 2017 at 09:47:32PM +0100, Philipp Tomsich wrote:
+<<<<<<< HEAD allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; +=======
drive-strength = < 30 >;
bias-pull-up; };
i2c0_pins: i2c0_pins {
mmc2_8bit_pins: mmc2-8bit {
allwinner,pins = "PC5", "PC6", "PC8",
"PC9", "PC10", "PC11",
"PC12", "PC13", "PC14",
"PC15", "PC16";
allwinner,function = "mmc2";
drive-strength = < 30 >;
bias-pull-up;
+>>>>>>> 20221b3... [f] dts warnings
Hmmm, are you sure about those ? :)
I can’t believe this slipped through. I think I need more sleep. At least the patch-format wasn’t such a mess this time around…
Cheers, Philipp.
participants (6)
-
Chen-Yu Tsai
-
Dr. Philipp Tomsich
-
Heiko Stübner
-
Maxime Ripard
-
Philipp Tomsich
-
Simon Glass