From: Stephen Warren Date: Wed, 25 May 2016 20:38:51 +0000 (-0600) Subject: gpio: add Tegra186 GPIO driver X-Git-Tag: KARO-TXSD-2017-03-15~866^2~3 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=074a1fdd27953aacb59346c83baaf443335ea04e;p=karo-tx-uboot.git gpio: add Tegra186 GPIO driver Tegra186's GPIO controller register layout is significantly different from previous chips, so add a new driver for it. In fact, there are two different GPIO controllers in Tegra186 that share a similar register layout, but very different port mapping. This driver covers both. The DT binding is already present in the Linux kernel (in linux-next via the Tegra tree so far). Signed-off-by: Stephen Warren Reviewed-by: Simon Glass # v1 Signed-off-by: Tom Warren --- diff --git a/doc/device-tree-bindings/gpio/nvidia,tegra186-gpio.txt b/doc/device-tree-bindings/gpio/nvidia,tegra186-gpio.txt new file mode 100644 index 0000000000..c82a2e221b --- /dev/null +++ b/doc/device-tree-bindings/gpio/nvidia,tegra186-gpio.txt @@ -0,0 +1,161 @@ +NVIDIA Tegra186 GPIO controllers + +Tegra186 contains two GPIO controllers; a main controller and an "AON" +controller. This binding document applies to both controllers. The register +layouts for the controllers share many similarities, but also some significant +differences. Hence, this document describes closely related but different +bindings and compatible values. + +The Tegra186 GPIO controller allows software to set the IO direction of, and +read/write the value of, numerous GPIO signals. Routing of GPIO signals to +package balls is under the control of a separate pin controller HW block. Two +major sets of registers exist: + +a) Security registers, which allow configuration of allowed access to the GPIO +register set. These registers exist in a single contiguous block of physical +address space. The size of this block, and the security features available, +varies between the different GPIO controllers. + +Access to this set of registers is not necessary in all circumstances. Code +that wishes to configure access to the GPIO registers needs access to these +registers to do so. Code which simply wishes to read or write GPIO data does not +need access to these registers. + +b) GPIO registers, which allow manipulation of the GPIO signals. In some GPIO +controllers, these registers are exposed via multiple "physical aliases" in +address space, each of which access the same underlying state. See the hardware +documentation for rationale. Any particular GPIO client is expected to access +just one of these physical aliases. + +Tegra HW documentation describes a unified naming convention for all GPIOs +implemented by the SoC. Each GPIO is assigned to a port, and a port may control +a number of GPIOs. Thus, each GPIO is named according to an alphabetical port +name and an integer GPIO name within the port. For example, GPIO_PA0, GPIO_PN6, +or GPIO_PCC3. + +The number of ports implemented by each GPIO controller varies. The number of +implemented GPIOs within each port varies. GPIO registers within a controller +are grouped and laid out according to the port they affect. + +The mapping from port name to the GPIO controller that implements that port, and +the mapping from port name to register offset within a controller, are both +extremely non-linear. The header file +describes the port-level mapping. In that file, the naming convention for ports +matches the HW documentation. The values chosen for the names are alphabetically +sorted within a particular controller. Drivers need to map between the DT GPIO +IDs and HW register offsets using a lookup table. + +Each GPIO controller can generate a number of interrupt signals. Each signal +represents the aggregate status for all GPIOs within a set of ports. Thus, the +number of interrupt signals generated by a controller varies as a rough function +of the number of ports it implements. Note that the HW documentation refers to +both the overall controller HW module and the sets-of-ports as "controllers". + +Each GPIO controller in fact generates multiple interrupts signals for each set +of ports. Each GPIO may be configured to feed into a specific one of the +interrupt signals generated by a set-of-ports. The intent is for each generated +signal to be routed to a different CPU, thus allowing different CPUs to each +handle subsets of the interrupts within a port. The status of each of these +per-port-set signals is reported via a separate register. Thus, a driver needs +to know which status register to observe. This binding currently defines no +configuration mechanism for this. By default, drivers should use register +GPIO_${port}_INTERRUPT_STATUS_G1_0. Future revisions to the binding could +define a property to configure this. + +Required properties: +- compatible + Array of strings. + One of: + - "nvidia,tegra186-gpio". + - "nvidia,tegra186-gpio-aon". +- reg-names + Array of strings. + Contains a list of names for the register spaces described by the reg + property. May contain the following entries, in any order: + - "gpio": Mandatory. GPIO control registers. This may cover either: + a) The single physical alias that this OS should use. + b) All physical aliases that exist in the controller. This is + appropriate when the OS is responsible for managing assignment of + the physical aliases. + - "security": Optional. Security configuration registers. + Users of this binding MUST look up entries in the reg property by name, + using this reg-names property to do so. +- reg + Array of (physical base address, length) tuples. + Must contain one entry per entry in the reg-names property, in a matching + order. +- interrupts + Array of interrupt specifiers. + The interrupt outputs from the HW block, one per set of ports, in the + order the HW manual describes them. The number of entries required varies + depending on compatible value: + - "nvidia,tegra186-gpio": 6 entries. + - "nvidia,tegra186-gpio-aon": 1 entry. +- gpio-controller + Boolean. + Marks the device node as a GPIO controller/provider. +- #gpio-cells + Single-cell integer. + Must be <2>. + Indicates how many cells are used in a consumer's GPIO specifier. + In the specifier: + - The first cell is the pin number. + See . + - The second cell contains flags: + - Bit 0 specifies polarity + - 0: Active-high (normal). + - 1: Active-low (inverted). +- interrupt-controller + Boolean. + Marks the device node as an interrupt controller/provider. +- #interrupt-cells + Single-cell integer. + Must be <2>. + Indicates how many cells are used in a consumer's interrupt specifier. + In the specifier: + - The first cell is the GPIO number. + See . + - The second cell is contains flags: + - Bits [3:0] indicate trigger type and level: + - 1: Low-to-high edge triggered. + - 2: High-to-low edge triggered. + - 4: Active high level-sensitive. + - 8: Active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. + +Example: + +#include + +gpio@2200000 { + compatible = "nvidia,tegra186-gpio"; + reg-names = "security", "gpio"; + reg = + <0x0 0x2200000 0x0 0x10000>, + <0x0 0x2210000 0x0 0x10000>; + interrupts = + <0 47 IRQ_TYPE_LEVEL_HIGH>, + <0 50 IRQ_TYPE_LEVEL_HIGH>, + <0 53 IRQ_TYPE_LEVEL_HIGH>, + <0 56 IRQ_TYPE_LEVEL_HIGH>, + <0 59 IRQ_TYPE_LEVEL_HIGH>, + <0 180 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; + +gpio@c2f0000 { + compatible = "nvidia,tegra186-gpio-aon"; + reg-names = "security", "gpio"; + reg = + <0x0 0xc2f0000 0x0 0x1000>, + <0x0 0xc2f1000 0x0 0x1000>; + interrupts = + <0 60 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f730744214..32219ed478 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -116,6 +116,14 @@ config TEGRA_GPIO Support for the GPIO controller contained in NVIDIA Tegra20 through Tegra210. +config TEGRA186_GPIO + bool "Tegra186 GPIO driver" + depends on DM_GPIO + help + Support for the GPIO controller contained in NVIDIA Tegra186. This + covers both the "main" and "AON" controller instances, even though + they have slightly different register layout. + config GPIO_UNIPHIER bool "UniPhier GPIO" depends on ARCH_UNIPHIER diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ddec1ef8de..3c4310176d 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_S5P) += s5p_gpio.o obj-$(CONFIG_SANDBOX_GPIO) += sandbox.o obj-$(CONFIG_SPEAR_GPIO) += spear_gpio.o obj-$(CONFIG_TEGRA_GPIO) += tegra_gpio.o +obj-$(CONFIG_TEGRA186_GPIO) += tegra186_gpio.o obj-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o obj-$(CONFIG_DM644X_GPIO) += da8xx_gpio.o obj-$(CONFIG_ALTERA_PIO) += altera_pio.o diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c index fefe3ca203..64abcbaa0a 100644 --- a/drivers/gpio/rk_gpio.c +++ b/drivers/gpio/rk_gpio.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpio/tegra186_gpio.c b/drivers/gpio/tegra186_gpio.c new file mode 100644 index 0000000000..1c681514db --- /dev/null +++ b/drivers/gpio/tegra186_gpio.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2010-2016, NVIDIA CORPORATION. + * (based on tegra_gpio.c) + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tegra186_gpio_priv.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct tegra186_gpio_port_data { + const char *name; + uint32_t offset; +}; + +struct tegra186_gpio_ctlr_data { + const struct tegra186_gpio_port_data *ports; + uint32_t port_count; +}; + +struct tegra186_gpio_platdata { + const char *name; + uint32_t *regs; +}; + +static uint32_t *tegra186_gpio_reg(struct udevice *dev, uint32_t reg, + uint32_t gpio) +{ + struct tegra186_gpio_platdata *plat = dev->platdata; + uint32_t index = (reg + (gpio * TEGRA186_GPIO_PER_GPIO_STRIDE)) / 4; + + return &(plat->regs[index]); +} + +static int tegra186_gpio_set_out(struct udevice *dev, unsigned offset, + bool output) +{ + uint32_t *reg; + uint32_t rval; + + reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_CONTROL, offset); + rval = readl(reg); + if (output) + rval &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED; + else + rval |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED; + writel(rval, reg); + + reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset); + rval = readl(reg); + if (output) + rval |= TEGRA186_GPIO_ENABLE_CONFIG_OUT; + else + rval &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT; + rval |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE; + writel(rval, reg); + + return 0; +} + +static int tegra186_gpio_set_val(struct udevice *dev, unsigned offset, bool val) +{ + uint32_t *reg; + uint32_t rval; + + reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE, offset); + rval = readl(reg); + if (val) + rval |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH; + else + rval &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH; + writel(rval, reg); + + return 0; +} + +static int tegra186_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + return tegra186_gpio_set_out(dev, offset, false); +} + +static int tegra186_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + int ret; + + ret = tegra186_gpio_set_val(dev, offset, value != 0); + if (ret) + return ret; + return tegra186_gpio_set_out(dev, offset, true); +} + +static int tegra186_gpio_get_value(struct udevice *dev, unsigned offset) +{ + uint32_t *reg; + uint32_t rval; + + reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset); + rval = readl(reg); + + if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT) + reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE, + offset); + else + reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_INPUT, offset); + + rval = readl(reg); + return !!rval; +} + +static int tegra186_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + return tegra186_gpio_set_val(dev, offset, value != 0); +} + +static int tegra186_gpio_get_function(struct udevice *dev, unsigned offset) +{ + uint32_t *reg; + uint32_t rval; + + reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset); + rval = readl(reg); + if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int tegra186_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct fdtdec_phandle_args *args) +{ + int gpio, port, ret; + + gpio = args->args[0]; + port = gpio / TEGRA186_GPIO_PER_GPIO_COUNT; + ret = device_get_child(dev, port, &desc->dev); + if (ret) + return ret; + desc->offset = gpio % TEGRA186_GPIO_PER_GPIO_COUNT; + desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; + + return 0; +} + +static const struct dm_gpio_ops tegra186_gpio_ops = { + .direction_input = tegra186_gpio_direction_input, + .direction_output = tegra186_gpio_direction_output, + .get_value = tegra186_gpio_get_value, + .set_value = tegra186_gpio_set_value, + .get_function = tegra186_gpio_get_function, + .xlate = tegra186_gpio_xlate, +}; + +/** + * We have a top-level GPIO device with no actual GPIOs. It has a child device + * for each port within the controller. + */ +static int tegra186_gpio_bind(struct udevice *parent) +{ + struct tegra186_gpio_platdata *parent_plat = parent->platdata; + struct tegra186_gpio_ctlr_data *ctlr_data = + (struct tegra186_gpio_ctlr_data *)dev_get_driver_data(parent); + uint32_t *regs; + int port, ret; + + /* If this is a child device, there is nothing to do here */ + if (parent_plat) + return 0; + + regs = (uint32_t *)dev_get_addr_name(parent, "gpio"); + if (regs == (uint32_t *)FDT_ADDR_T_NONE) + return -ENODEV; + + for (port = 0; port < ctlr_data->port_count; port++) { + struct tegra186_gpio_platdata *plat; + struct udevice *dev; + + plat = calloc(1, sizeof(*plat)); + if (!plat) + return -ENOMEM; + plat->name = ctlr_data->ports[port].name; + plat->regs = &(regs[ctlr_data->ports[port].offset / 4]); + + ret = device_bind(parent, parent->driver, plat->name, plat, + -1, &dev); + if (ret) + return ret; + dev->of_offset = parent->of_offset; + } + + return 0; +} + +static int tegra186_gpio_probe(struct udevice *dev) +{ + struct tegra186_gpio_platdata *plat = dev->platdata; + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + /* Only child devices have ports */ + if (!plat) + return 0; + + uc_priv->gpio_count = TEGRA186_GPIO_PER_GPIO_COUNT; + uc_priv->bank_name = plat->name; + + return 0; +} + +static const struct tegra186_gpio_port_data tegra186_gpio_main_ports[] = { + {"A", 0x2000}, + {"B", 0x3000}, + {"C", 0x3200}, + {"D", 0x3400}, + {"E", 0x2200}, + {"F", 0x2400}, + {"G", 0x4200}, + {"H", 0x1000}, + {"I", 0x0800}, + {"J", 0x5000}, + {"K", 0x5200}, + {"L", 0x1200}, + {"M", 0x5600}, + {"N", 0x0000}, + {"O", 0x0200}, + {"P", 0x4000}, + {"Q", 0x0400}, + {"R", 0x0a00}, + {"T", 0x0600}, + {"X", 0x1400}, + {"Y", 0x1600}, + {"BB", 0x2600}, + {"CC", 0x5400}, +}; + +static const struct tegra186_gpio_ctlr_data tegra186_gpio_main_data = { + .ports = tegra186_gpio_main_ports, + .port_count = ARRAY_SIZE(tegra186_gpio_main_ports), +}; + +static const struct tegra186_gpio_port_data tegra186_gpio_aon_ports[] = { + {"S", 0x0200}, + {"U", 0x0400}, + {"V", 0x0800}, + {"W", 0x0a00}, + {"Z", 0x0e00}, + {"AA", 0x0c00}, + {"EE", 0x0600}, + {"FF", 0x0000}, +}; + +static const struct tegra186_gpio_ctlr_data tegra186_gpio_aon_data = { + .ports = tegra186_gpio_aon_ports, + .port_count = ARRAY_SIZE(tegra186_gpio_aon_ports), +}; + +static const struct udevice_id tegra186_gpio_ids[] = { + { + .compatible = "nvidia,tegra186-gpio", + .data = (ulong)&tegra186_gpio_main_data, + }, + { + .compatible = "nvidia,tegra186-gpio-aon", + .data = (ulong)&tegra186_gpio_aon_data, + }, + { } +}; + +U_BOOT_DRIVER(tegra186_gpio) = { + .name = "tegra186_gpio", + .id = UCLASS_GPIO, + .of_match = tegra186_gpio_ids, + .bind = tegra186_gpio_bind, + .probe = tegra186_gpio_probe, + .ops = &tegra186_gpio_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/gpio/tegra186_gpio_priv.h b/drivers/gpio/tegra186_gpio_priv.h new file mode 100644 index 0000000000..9e85a4343b --- /dev/null +++ b/drivers/gpio/tegra186_gpio_priv.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _TEGRA186_GPIO_PRIV_H_ +#define _TEGRA186_GPIO_PRIV_H_ + +/* + * For each GPIO, there are a set of registers than affect it, all packed + * back-to-back. + */ +#define TEGRA186_GPIO_ENABLE_CONFIG 0x00 +#define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) +#define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1) +#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SHIFT 2 +#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK 3 +#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_NONE 0 +#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL 1 +#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE 2 +#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE 3 +#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL_HIGH_RISING BIT(4) +#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE_ENABLE BIT(5) +#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT_ENABLE BIT(6) +#define TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMPING_ENABLE BIT(7) + +#define TEGRA186_GPIO_DEBOUNCE_THRESHOLD 0x04 + +#define TEGRA186_GPIO_INPUT 0x08 + +#define TEGRA186_GPIO_OUTPUT_CONTROL 0x0c +#define TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED BIT(0) + +#define TEGRA186_GPIO_OUTPUT_VALUE 0x10 +#define TEGRA186_GPIO_OUTPUT_VALUE_HIGH 1 + +#define TEGRA186_GPIO_INTERRUPT_CLEAR 0x14 + +/* + * 8 GPIOs are packed into a port. Their registers appear back-to-back in the + * port's address space. + */ +#define TEGRA186_GPIO_PER_GPIO_STRIDE 0x20 +#define TEGRA186_GPIO_PER_GPIO_COUNT 8 + +/* + * Per-port registers are packed immediately following all of a port's + * per-GPIO registers. + */ +#define TEGRA186_GPIO_INTERRUPT_STATUS_G 0x100 +#define TEGRA186_GPIO_INTERRUPT_STATUS_G_STRIDE 4 +#define TEGRA186_GPIO_INTERRUPT_STATUS_G_COUNT 8 + +/* + * The registers for multiple ports are packed together back-to-back to form + * the overall controller. + */ +#define TEGRA186_GPIO_PER_PORT_STRIDE 0x200 + +#endif diff --git a/include/dt-bindings/gpio/tegra186-gpio.h b/include/dt-bindings/gpio/tegra186-gpio.h new file mode 100644 index 0000000000..7e6fb95da1 --- /dev/null +++ b/include/dt-bindings/gpio/tegra186-gpio.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + * + * This header provides constants for binding nvidia,tegra186-gpio*. + * + * The first cell in Tegra's GPIO specifier is the GPIO ID. The macros below + * provide names for this. + * + * The second cell contains standard flag values specified in gpio.h. + */ + +#ifndef _DT_BINDINGS_GPIO_TEGRA186_GPIO_H +#define _DT_BINDINGS_GPIO_TEGRA186_GPIO_H + +#include + +/* GPIOs implemented by main GPIO controller */ +#define TEGRA_MAIN_GPIO_PORT_A 0 +#define TEGRA_MAIN_GPIO_PORT_B 1 +#define TEGRA_MAIN_GPIO_PORT_C 2 +#define TEGRA_MAIN_GPIO_PORT_D 3 +#define TEGRA_MAIN_GPIO_PORT_E 4 +#define TEGRA_MAIN_GPIO_PORT_F 5 +#define TEGRA_MAIN_GPIO_PORT_G 6 +#define TEGRA_MAIN_GPIO_PORT_H 7 +#define TEGRA_MAIN_GPIO_PORT_I 8 +#define TEGRA_MAIN_GPIO_PORT_J 9 +#define TEGRA_MAIN_GPIO_PORT_K 10 +#define TEGRA_MAIN_GPIO_PORT_L 11 +#define TEGRA_MAIN_GPIO_PORT_M 12 +#define TEGRA_MAIN_GPIO_PORT_N 13 +#define TEGRA_MAIN_GPIO_PORT_O 14 +#define TEGRA_MAIN_GPIO_PORT_P 15 +#define TEGRA_MAIN_GPIO_PORT_Q 16 +#define TEGRA_MAIN_GPIO_PORT_R 17 +#define TEGRA_MAIN_GPIO_PORT_T 18 +#define TEGRA_MAIN_GPIO_PORT_X 19 +#define TEGRA_MAIN_GPIO_PORT_Y 20 +#define TEGRA_MAIN_GPIO_PORT_BB 21 +#define TEGRA_MAIN_GPIO_PORT_CC 22 + +#define TEGRA_MAIN_GPIO(port, offset) \ + ((TEGRA_MAIN_GPIO_PORT_##port * 8) + offset) + +/* GPIOs implemented by AON GPIO controller */ +#define TEGRA_AON_GPIO_PORT_S 0 +#define TEGRA_AON_GPIO_PORT_U 1 +#define TEGRA_AON_GPIO_PORT_V 2 +#define TEGRA_AON_GPIO_PORT_W 3 +#define TEGRA_AON_GPIO_PORT_Z 4 +#define TEGRA_AON_GPIO_PORT_AA 5 +#define TEGRA_AON_GPIO_PORT_EE 6 +#define TEGRA_AON_GPIO_PORT_FF 7 + +#define TEGRA_AON_GPIO(port, offset) \ + ((TEGRA_AON_GPIO_PORT_##port * 8) + offset) + +#endif