
On Sat, Feb 18, 2017 at 1:52 AM, Philipp Tomsich philipp.tomsich@theobroma-systems.com 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
- defines and implements a binding for sunxi-style GPIO banks (to make it easier to describe controllers like the A64 which may not start at 'A') and provide the necessary translation mechanisms:
- As all our gpio-reference point back to either <&pio ..> or <&r_pio ..> the device framework will try to access a UCLASS_GPIO device bound to the same node id as the pinctrl device to perform it's of_xlate lookup. For this, we provide a 'gpiobridge' driver (which needs to access the platdata of the pinctrl device) and which can then map accesses to an actual GPIO bank device.
- For the individual GPIO banks, we use a new driver (which shares most of its ops with the existing sunxi_gpio driver, except probe and bind) and provides configuration without any platdata structure.
Why is the new binding and driver necessary? The existing driver in U-boot is already DM enabled and properly xlates GPIO phandles to its child GPIO banks. I specifically fixed this in commit 4694dc56e974 ("sunxi: gpio: Add .xlate function for gpio phandle resolution").
You are also not using the new gpiobank nodes anywhere in your dts changes.
- 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)
The active DM tree at runtime (with this enabled) should look similar to the following:
pinctrl [ + ] | |-- pinctrl@1c20800 gpio [ + ] | | |-- gpiob@24 gpio [ + ] | | |-- gpioc@48 gpio [ + ] | | |-- gpiod@6c gpio [ + ] | | |-- gpioe@90 gpio [ + ] | | |-- gpiof@b4 gpio [ + ] | | |-- gpiog@d8 gpio [ + ] | | |-- gpioh@fc pinconfig [ + ] | | |-- uart0_pins_a pinconfig [ ] | | |-- uart0_pins_b pinconfig [ ] | | |-- uart1_2pins pinconfig [ ] | | |-- uart1_4pins pinconfig [ ] | | |-- uart2_2pins pinconfig [ ] | | |-- uart2_4 pinconfig [ ] | | |-- uart3 pinconfig [ ] | | |-- uart3_2 pinconfig [ ] | | |-- uart3_4 pinconfig [ ] | | |-- uart4_2 pinconfig [ ] | | |-- uart4_4 pinconfig [ + ] | | |-- mmc0 pinconfig [ + ] | | |-- mmc0_cd_pin pinconfig [ ] | | |-- mmc1 pinconfig [ ] | | |-- mmc2 pinconfig [ + ] | | |-- mmc2_8bit pinconfig [ ] | | |-- i2c0_pins pinconfig [ ] | | |-- i2c1_pins pinconfig [ ] | | |-- i2c2_pins pinconfig [ ] | | |-- rmii_pins pinconfig [ + ] | | |-- rgmii_pins pinconfig [ + ] | | |-- spi0_pins pinconfig [ ] | | |-- spi1_pins pinconfig [ + ] | | |-- led_pins_sdio pinconfig [ + ] | | |-- ethphy_reset_pin gpio [ + ] | | `-- gpiobridge pinctrl [ + ] | |-- pinctrl@01f02c00 gpio [ + ] | | |-- gpiol@0 pinconfig [ + ] | | |-- led_pins_power gpio [ + ] | | `-- gpiobridge
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
.../pinctrl/allwinner,pinctrl.txt | 130 +++++ drivers/gpio/sunxi_gpio.c | 97 +++- 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 | 326 ++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ 9 files changed, 1553 insertions(+), 2 deletions(-) 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/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt new file mode 100644 index 0000000..e536ea3 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt @@ -0,0 +1,130 @@ +* 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.
+The Allwinner pinctrl node contains a description of the pinctrl block +(i.e. including GPIO and external interrupt capability, if available) +and subnodes describing individual GPIO banks and pin-configuration.
+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>
+Properties for the gpio sub-nodes:
- compatible: should be "allwinner,sunxi-gpiobank"
- allwinner,gpiobank-name: the name of the bank (e.g. <'A'>, <'B'>, ...)
- reg: offsets (within the address range of the enclosing pinctrl
node's address space) and length of the registers, where
* The first entry points to the mux/gpio registers.
* An (optional) second entry points to the extint registers.
Note, that the second entry should be provided, if the
interrupt property is present.
- interrupt: the interrupt used for external interrupt signalling
(should be one of the interrupts specified in the
enclosing pinctrl node)
+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>;
/* The A64 does not have bank A and leaves a hole in the
address space where it normally would be */
gpiob: gpiob@24 {
compatible = "allwinner,sunxi-gpiobank";
allwinner,gpiobank-name = <'B'>;
reg = < 0x24 0x24 >, < 0x200 0x1c >;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
};
gpioc: gpioc@48 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x48 0x24 >;
allwinner,gpiobank-name = <'C'>;
};
gpiod: gpiod@6c {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x6c 0x24 >;
allwinner,gpiobank-name = <'D'>;
};
gpioe: gpioe@90 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x90 0x24 >;
allwinner,gpiobank-name = <'E'>;
};
gpiof: gpiof@b4 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xb4 0x24 >;
allwinner,gpiobank-name = <'F'>;
};
gpiog: gpiog@d8 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xd8 0x24 >, < 0x220 0x1c >;
allwinner,gpiobank-name = <'G'>;
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
};
gpioh: gpioh@fc {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xfc 0x24 >, < 0x220 0x1c >;
allwinner,gpiobank-name = <'H'>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
};
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..6cf2be4 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -344,36 +344,129 @@ static const struct sunxi_gpio_soc_data soc_data_l_3 = { static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun4i-a10-pinctrl", a_all), ID("allwinner,sun5i-a10s-pinctrl", a_all), ID("allwinner,sun5i-a13-pinctrl", a_all), ID("allwinner,sun6i-a31-pinctrl", a_all), ID("allwinner,sun6i-a31s-pinctrl", a_all), ID("allwinner,sun7i-a20-pinctrl", a_all), ID("allwinner,sun8i-a23-pinctrl", a_all), ID("allwinner,sun8i-a33-pinctrl", a_all), 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 { } };
U_BOOT_DRIVER(gpio_sunxi) = { .name = "gpio_sunxi", .id = UCLASS_GPIO, .ops = &gpio_sunxi_ops, .of_match = sunxi_gpio_ids, .bind = gpio_sunxi_bind, .probe = gpio_sunxi_probe, };
+#if defined(CONFIG_SUNXI_PINCTRL)
+/* When we use the sunxi pinctrl infrastructure, we have two issues that
- are resolved by the gpiobank and gpiobrige drivers:
- We need to have a UCLASS_GPIO device bound to the pinctrl-nodes for
- translating between gpio entries (e.g. <&pio 3 24 GPIO_ACTIVE_LOW>;)
- in the DT and actual gpio banks. This is done using the gpiobridge
- driver, which provides only a lookup/translation mechanism.
- This mechanism lives in pinctrl-sunxi.c
- We introduce a generic gpiobank device, which resolves the need to
- have distinct soc_data structure for each device and avoids having
- to share data structures and config data between this file and the
- sunxi pinctrl (the other option would be to have the soc_data info
- visible in pinctrl-sunxi.c (or merge it into this file) and bind a
- gpio_sunxi device that is set up with the appropriate soc_data) to
- the same node as the pinctrl device.
Pushing hardware internals into the DT is not preferred.
Since the pinctrl and gpio drivers actually driver the same hardware block, just in different ways, and there should be some locking between the two, I think it would make sense to merge the two.
You can also get away with not having soc_data by just registering the full set of GPIO banks and pins (we aren't counting extra pins anyway).
Moreover I think the gpiobank issue is just a limitation of U-boot's GPIO implementation.
Regards ChenYu
- */
+static int gpiobank_sunxi_probe(struct udevice *dev) +{
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
int bank_name;
int bank;
fdt_addr_t offset;
fdt_size_t size;
fdt_addr_t base;
debug("%s: %s", __func__, dev->name);
/* At this time we are only interested in index 0 (the PIO registers)
and we ignore index 1 (the external interrupt control), even if
present and an interrupt property exists... */
offset = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob,
dev->of_offset,
"reg", 0, &size,
false);
if (offset == FDT_ADDR_T_NONE) {
error("%s: missing 'reg' for offset into parent device\n",
dev->name);
return -EINVAL;
}
bank_name = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"allwinner,gpiobank-name", -EINVAL);
if (bank_name == -EINVAL) {
error("%s: missing 'allwinner,gpiobank-name'\n", dev->name);
return -EINVAL;
}
base = dev_get_addr(dev->parent);
if (base == FDT_ADDR_T_NONE) {
error("%s: parent '%s' does not have a valid base address\n",
dev->name, dev->parent->name);
return -EINVAL;
}
bank = bank_name - 'A';
plat->regs = (void *)(base + offset);
plat->gpio_count = SUNXI_GPIOS_PER_BANK;
plat->bank_name = gpio_bank_name(bank);
/* Tell the uclass how many GPIOs we have */
uc_priv->gpio_count = plat->gpio_count;
uc_priv->bank_name = plat->bank_name;
return 0;
+}
+static const struct udevice_id sunxi_gpiobank_ids[] = {
{ .compatible = "allwinner,sunxi-gpiobank", },
{}
+};
+U_BOOT_DRIVER(gpiobank_sunxi) = {
.name = "gpiobank_sunxi",
.id = UCLASS_GPIO,
.ops = &gpio_sunxi_ops,
.of_match = sunxi_gpiobank_ids,
.platdata_auto_alloc_size = sizeof(struct sunxi_gpio_platdata),
.probe = gpiobank_sunxi_probe,
+};
+#endif /* CONFIG_SUNXI_PINCTRL */
#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 @@ -1,18 +1,20 @@ # # SPDX-License-Identifier: GPL-2.0+ #
obj-y += pinctrl-uclass.o obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-y += nxp/ obj-$(CONFIG_ARCH_ATH79) += ath79/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ 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..36579b1 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -0,0 +1,326 @@ +/*
- (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 <dm/lists.h> +#include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> +#include <dt-bindings/gpio/gpio.h> +#include "pinctrl-sunxi.h"
+DECLARE_GLOBAL_DATA_PTR;
+struct sunxi_pctrl_priv {
void *base;
+};
+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 int sunxi_pctrl_probe(struct udevice *dev) +{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
+#if CONFIG_DM_GPIO
struct udevice *gpiobridge;
+#endif
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;
+#if CONFIG_DM_GPIO
device_bind_driver_to_node(dev, "sunxi_pctrl_gpiobridge",
"gpiobridge", dev->of_offset, &gpiobridge);
/* The new device will have been created with no driver data,
so we need to set it here, as it contains the pin_base of
the gpio-group. */
if (gpiobridge)
gpiobridge->driver_data = dev_get_driver_data(dev);
+#endif
return 0;
+}
+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,
+};
+#if defined(CONFIG_DM_GPIO) +/* The gpiobridge exists to translate <&pio 3 24 GPIO_ACTIVE_LOW> into the
- underlying GPIO bank. It needs to access/understand the driver-data for
- the pinctrl device, so it lives here instead of in sunxi_gpio.c ... */
+static int sunxi_gpiobridge_xlate(struct udevice *dev, struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
+{
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
struct udevice *gpiobank;
char name[3] = {'P', 'A', '\0' };
if (!data) {
debug("%s: no driver_data\n", dev->name);
return -ENOENT;
}
/* Naming on each pinctrl may start with an offset (e.g. R_PIO
usually starts at 'PL'). */
name[1] += data->pin_base / PINS_PER_BANK;
/* Now add the bank-number within this pinctrl */
name[1] += args->args[0];
for (uclass_first_device(UCLASS_GPIO, &gpiobank);
gpiobank;
uclass_next_device(&gpiobank)) {
int count;
const char *bank_name = gpio_get_bank_info(gpiobank, &count);
if (bank_name && !strcmp(bank_name, name)) {
desc->dev = gpiobank;
desc->offset = args->args[1];
desc->flags = args->args[2] & (GPIO_ACTIVE_LOW ?
GPIOD_ACTIVE_LOW : 0);
return 0;
}
}
return -ENOENT;
+}
+static const struct dm_gpio_ops gpiobridge_sunxi_ops = {
.xlate = sunxi_gpiobridge_xlate,
+};
+U_BOOT_DRIVER(gpiobridge_sunxi) = {
.name = "sunxi_pctrl_gpiobridge",
.id = UCLASS_GPIO,
.ops = &gpiobridge_sunxi_ops,
+}; +#endif /* DM_GPIO */ 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