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.toms...@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.rip...@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.przyw...@arm.com> > + * > + * Based on pinctrl-sun7i-a20.c, which is: > + * Copyright (C) 2014 Maxime Ripard <maxime.rip...@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.rip...@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
signature.asc
Description: PGP signature
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot