162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016-2022 NVIDIA Corporation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Thierry Reding <treding@nvidia.com> 662306a36Sopenharmony_ci * Dipen Patel <dpatel@nvidia.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1062306a36Sopenharmony_ci#include <linux/hte.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/irq.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/seq_file.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <dt-bindings/gpio/tegra186-gpio.h> 1962306a36Sopenharmony_ci#include <dt-bindings/gpio/tegra194-gpio.h> 2062306a36Sopenharmony_ci#include <dt-bindings/gpio/tegra234-gpio.h> 2162306a36Sopenharmony_ci#include <dt-bindings/gpio/tegra241-gpio.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* security registers */ 2462306a36Sopenharmony_ci#define TEGRA186_GPIO_CTL_SCR 0x0c 2562306a36Sopenharmony_ci#define TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28) 2662306a36Sopenharmony_ci#define TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define TEGRA186_GPIO_VM 0x00 3162306a36Sopenharmony_ci#define TEGRA186_GPIO_VM_RW_MASK 0x03 3262306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR 0x04 3362306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR_PIN_SIZE 0x08 3462306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR_PORT_SIZE 0x40 3562306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR_SEC_WEN BIT(28) 3662306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR_SEC_REN BIT(27) 3762306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR_SEC_G1W BIT(9) 3862306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR_SEC_G1R BIT(1) 3962306a36Sopenharmony_ci#define TEGRA186_GPIO_FULL_ACCESS (TEGRA186_GPIO_SCR_SEC_WEN | \ 4062306a36Sopenharmony_ci TEGRA186_GPIO_SCR_SEC_REN | \ 4162306a36Sopenharmony_ci TEGRA186_GPIO_SCR_SEC_G1R | \ 4262306a36Sopenharmony_ci TEGRA186_GPIO_SCR_SEC_G1W) 4362306a36Sopenharmony_ci#define TEGRA186_GPIO_SCR_SEC_ENABLE (TEGRA186_GPIO_SCR_SEC_WEN | \ 4462306a36Sopenharmony_ci TEGRA186_GPIO_SCR_SEC_REN) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* control registers */ 4762306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG 0x00 4862306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) 4962306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1) 5062306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_NONE (0x0 << 2) 5162306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL (0x1 << 2) 5262306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE (0x2 << 2) 5362306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2) 5462306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2) 5562306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4) 5662306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5) 5762306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6) 5862306a36Sopenharmony_ci#define TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC BIT(7) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04 6162306a36Sopenharmony_ci#define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define TEGRA186_GPIO_INPUT 0x08 6462306a36Sopenharmony_ci#define TEGRA186_GPIO_INPUT_HIGH BIT(0) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define TEGRA186_GPIO_OUTPUT_CONTROL 0x0c 6762306a36Sopenharmony_ci#define TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED BIT(0) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define TEGRA186_GPIO_OUTPUT_VALUE 0x10 7062306a36Sopenharmony_ci#define TEGRA186_GPIO_OUTPUT_VALUE_HIGH BIT(0) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define TEGRA186_GPIO_INTERRUPT_CLEAR 0x14 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistruct tegra_gpio_port { 7762306a36Sopenharmony_ci const char *name; 7862306a36Sopenharmony_ci unsigned int bank; 7962306a36Sopenharmony_ci unsigned int port; 8062306a36Sopenharmony_ci unsigned int pins; 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct tegra186_pin_range { 8462306a36Sopenharmony_ci unsigned int offset; 8562306a36Sopenharmony_ci const char *group; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct tegra_gpio_soc { 8962306a36Sopenharmony_ci const struct tegra_gpio_port *ports; 9062306a36Sopenharmony_ci unsigned int num_ports; 9162306a36Sopenharmony_ci const char *name; 9262306a36Sopenharmony_ci unsigned int instance; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci unsigned int num_irqs_per_bank; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci const struct tegra186_pin_range *pin_ranges; 9762306a36Sopenharmony_ci unsigned int num_pin_ranges; 9862306a36Sopenharmony_ci const char *pinmux; 9962306a36Sopenharmony_ci bool has_gte; 10062306a36Sopenharmony_ci bool has_vm_support; 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct tegra_gpio { 10462306a36Sopenharmony_ci struct gpio_chip gpio; 10562306a36Sopenharmony_ci unsigned int num_irq; 10662306a36Sopenharmony_ci unsigned int *irq; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci const struct tegra_gpio_soc *soc; 10962306a36Sopenharmony_ci unsigned int num_irqs_per_bank; 11062306a36Sopenharmony_ci unsigned int num_banks; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci void __iomem *secure; 11362306a36Sopenharmony_ci void __iomem *base; 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic const struct tegra_gpio_port * 11762306a36Sopenharmony_citegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci unsigned int start = 0, i; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci for (i = 0; i < gpio->soc->num_ports; i++) { 12262306a36Sopenharmony_ci const struct tegra_gpio_port *port = &gpio->soc->ports[i]; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (*pin >= start && *pin < start + port->pins) { 12562306a36Sopenharmony_ci *pin -= start; 12662306a36Sopenharmony_ci return port; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci start += port->pins; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return NULL; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio, 13662306a36Sopenharmony_ci unsigned int pin) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci const struct tegra_gpio_port *port; 13962306a36Sopenharmony_ci unsigned int offset; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci port = tegra186_gpio_get_port(gpio, &pin); 14262306a36Sopenharmony_ci if (!port) 14362306a36Sopenharmony_ci return NULL; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci offset = port->bank * 0x1000 + port->port * 0x200; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return gpio->base + offset + pin * 0x20; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void __iomem *tegra186_gpio_get_secure_base(struct tegra_gpio *gpio, 15162306a36Sopenharmony_ci unsigned int pin) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci const struct tegra_gpio_port *port; 15462306a36Sopenharmony_ci unsigned int offset; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci port = tegra186_gpio_get_port(gpio, &pin); 15762306a36Sopenharmony_ci if (!port) 15862306a36Sopenharmony_ci return NULL; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci offset = port->bank * 0x1000 + port->port * TEGRA186_GPIO_SCR_PORT_SIZE; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return gpio->secure + offset + pin * TEGRA186_GPIO_SCR_PIN_SIZE; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic inline bool tegra186_gpio_is_accessible(struct tegra_gpio *gpio, unsigned int pin) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci void __iomem *secure; 16862306a36Sopenharmony_ci u32 value; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci secure = tegra186_gpio_get_secure_base(gpio, pin); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (gpio->soc->has_vm_support) { 17362306a36Sopenharmony_ci value = readl(secure + TEGRA186_GPIO_VM); 17462306a36Sopenharmony_ci if ((value & TEGRA186_GPIO_VM_RW_MASK) != TEGRA186_GPIO_VM_RW_MASK) 17562306a36Sopenharmony_ci return false; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci value = __raw_readl(secure + TEGRA186_GPIO_SCR); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if ((value & TEGRA186_GPIO_SCR_SEC_ENABLE) == 0) 18162306a36Sopenharmony_ci return true; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if ((value & TEGRA186_GPIO_FULL_ACCESS) == TEGRA186_GPIO_FULL_ACCESS) 18462306a36Sopenharmony_ci return true; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return false; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int tegra186_init_valid_mask(struct gpio_chip *chip, 19062306a36Sopenharmony_ci unsigned long *valid_mask, unsigned int ngpios) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 19362306a36Sopenharmony_ci unsigned int j; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci for (j = 0; j < ngpios; j++) { 19662306a36Sopenharmony_ci if (!tegra186_gpio_is_accessible(gpio, j)) 19762306a36Sopenharmony_ci clear_bit(j, valid_mask); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int tegra186_gpio_get_direction(struct gpio_chip *chip, 20362306a36Sopenharmony_ci unsigned int offset) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 20662306a36Sopenharmony_ci void __iomem *base; 20762306a36Sopenharmony_ci u32 value; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 21062306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 21162306a36Sopenharmony_ci return -ENODEV; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 21462306a36Sopenharmony_ci if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT) 21562306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int tegra186_gpio_direction_input(struct gpio_chip *chip, 22162306a36Sopenharmony_ci unsigned int offset) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 22462306a36Sopenharmony_ci void __iomem *base; 22562306a36Sopenharmony_ci u32 value; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 22862306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 22962306a36Sopenharmony_ci return -ENODEV; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL); 23262306a36Sopenharmony_ci value |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED; 23362306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 23662306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE; 23762306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT; 23862306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int tegra186_gpio_direction_output(struct gpio_chip *chip, 24462306a36Sopenharmony_ci unsigned int offset, int level) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 24762306a36Sopenharmony_ci void __iomem *base; 24862306a36Sopenharmony_ci u32 value; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* configure output level first */ 25162306a36Sopenharmony_ci chip->set(chip, offset, level); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 25462306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 25562306a36Sopenharmony_ci return -EINVAL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* set the direction */ 25862306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL); 25962306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED; 26062306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 26362306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE; 26462306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_OUT; 26562306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci#define HTE_BOTH_EDGES (HTE_RISING_EDGE_TS | HTE_FALLING_EDGE_TS) 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int tegra186_gpio_en_hw_ts(struct gpio_chip *gc, u32 offset, 27362306a36Sopenharmony_ci unsigned long flags) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct tegra_gpio *gpio; 27662306a36Sopenharmony_ci void __iomem *base; 27762306a36Sopenharmony_ci int value; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (!gc) 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci gpio = gpiochip_get_data(gc); 28362306a36Sopenharmony_ci if (!gpio) 28462306a36Sopenharmony_ci return -ENODEV; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 28762306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 28862306a36Sopenharmony_ci return -EINVAL; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 29162306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (flags == HTE_BOTH_EDGES) { 29462306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; 29562306a36Sopenharmony_ci } else if (flags == HTE_RISING_EDGE_TS) { 29662306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 29762306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; 29862306a36Sopenharmony_ci } else if (flags == HTE_FALLING_EDGE_TS) { 29962306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int tegra186_gpio_dis_hw_ts(struct gpio_chip *gc, u32 offset, 30862306a36Sopenharmony_ci unsigned long flags) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct tegra_gpio *gpio; 31162306a36Sopenharmony_ci void __iomem *base; 31262306a36Sopenharmony_ci int value; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (!gc) 31562306a36Sopenharmony_ci return -EINVAL; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci gpio = gpiochip_get_data(gc); 31862306a36Sopenharmony_ci if (!gpio) 31962306a36Sopenharmony_ci return -ENODEV; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 32262306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 32362306a36Sopenharmony_ci return -EINVAL; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 32662306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; 32762306a36Sopenharmony_ci if (flags == HTE_BOTH_EDGES) { 32862306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; 32962306a36Sopenharmony_ci } else if (flags == HTE_RISING_EDGE_TS) { 33062306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 33162306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; 33262306a36Sopenharmony_ci } else if (flags == HTE_FALLING_EDGE_TS) { 33362306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 34362306a36Sopenharmony_ci void __iomem *base; 34462306a36Sopenharmony_ci u32 value; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 34762306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 34862306a36Sopenharmony_ci return -ENODEV; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 35162306a36Sopenharmony_ci if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT) 35262306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE); 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_INPUT); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return value & BIT(0); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset, 36062306a36Sopenharmony_ci int level) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 36362306a36Sopenharmony_ci void __iomem *base; 36462306a36Sopenharmony_ci u32 value; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 36762306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 36862306a36Sopenharmony_ci return; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE); 37162306a36Sopenharmony_ci if (level == 0) 37262306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH; 37362306a36Sopenharmony_ci else 37462306a36Sopenharmony_ci value |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int tegra186_gpio_set_config(struct gpio_chip *chip, 38062306a36Sopenharmony_ci unsigned int offset, 38162306a36Sopenharmony_ci unsigned long config) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 38462306a36Sopenharmony_ci u32 debounce, value; 38562306a36Sopenharmony_ci void __iomem *base; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, offset); 38862306a36Sopenharmony_ci if (base == NULL) 38962306a36Sopenharmony_ci return -ENXIO; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) 39262306a36Sopenharmony_ci return -ENOTSUPP; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci debounce = pinconf_to_config_argument(config); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * The Tegra186 GPIO controller supports a maximum of 255 ms debounce 39862306a36Sopenharmony_ci * time. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci if (debounce > 255000) 40162306a36Sopenharmony_ci return -EINVAL; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci debounce = DIV_ROUND_UP(debounce, USEC_PER_MSEC); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci value = TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(debounce); 40662306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_DEBOUNCE_CONTROL); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 40962306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE; 41062306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int tegra186_gpio_add_pin_ranges(struct gpio_chip *chip) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 41862306a36Sopenharmony_ci struct pinctrl_dev *pctldev; 41962306a36Sopenharmony_ci struct device_node *np; 42062306a36Sopenharmony_ci unsigned int i, j; 42162306a36Sopenharmony_ci int err; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (!gpio->soc->pinmux || gpio->soc->num_pin_ranges == 0) 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, gpio->soc->pinmux); 42762306a36Sopenharmony_ci if (!np) 42862306a36Sopenharmony_ci return -ENODEV; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci pctldev = of_pinctrl_get(np); 43162306a36Sopenharmony_ci of_node_put(np); 43262306a36Sopenharmony_ci if (!pctldev) 43362306a36Sopenharmony_ci return -EPROBE_DEFER; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci for (i = 0; i < gpio->soc->num_pin_ranges; i++) { 43662306a36Sopenharmony_ci unsigned int pin = gpio->soc->pin_ranges[i].offset, port; 43762306a36Sopenharmony_ci const char *group = gpio->soc->pin_ranges[i].group; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci port = pin / 8; 44062306a36Sopenharmony_ci pin = pin % 8; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (port >= gpio->soc->num_ports) { 44362306a36Sopenharmony_ci dev_warn(chip->parent, "invalid port %u for %s\n", 44462306a36Sopenharmony_ci port, group); 44562306a36Sopenharmony_ci continue; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (j = 0; j < port; j++) 44962306a36Sopenharmony_ci pin += gpio->soc->ports[j].pins; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci err = gpiochip_add_pingroup_range(chip, pctldev, pin, group); 45262306a36Sopenharmony_ci if (err < 0) 45362306a36Sopenharmony_ci return err; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int tegra186_gpio_of_xlate(struct gpio_chip *chip, 46062306a36Sopenharmony_ci const struct of_phandle_args *spec, 46162306a36Sopenharmony_ci u32 *flags) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 46462306a36Sopenharmony_ci unsigned int port, pin, i, offset = 0; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (WARN_ON(chip->of_gpio_n_cells < 2)) 46762306a36Sopenharmony_ci return -EINVAL; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (WARN_ON(spec->args_count < chip->of_gpio_n_cells)) 47062306a36Sopenharmony_ci return -EINVAL; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci port = spec->args[0] / 8; 47362306a36Sopenharmony_ci pin = spec->args[0] % 8; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (port >= gpio->soc->num_ports) { 47662306a36Sopenharmony_ci dev_err(chip->parent, "invalid port number: %u\n", port); 47762306a36Sopenharmony_ci return -EINVAL; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci for (i = 0; i < port; i++) 48162306a36Sopenharmony_ci offset += gpio->soc->ports[i].pins; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (flags) 48462306a36Sopenharmony_ci *flags = spec->args[1]; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return offset + pin; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci#define to_tegra_gpio(x) container_of((x), struct tegra_gpio, gpio) 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic void tegra186_irq_ack(struct irq_data *data) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(data); 49462306a36Sopenharmony_ci struct tegra_gpio *gpio = to_tegra_gpio(gc); 49562306a36Sopenharmony_ci void __iomem *base; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, data->hwirq); 49862306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 49962306a36Sopenharmony_ci return; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci writel(1, base + TEGRA186_GPIO_INTERRUPT_CLEAR); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void tegra186_irq_mask(struct irq_data *data) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(data); 50762306a36Sopenharmony_ci struct tegra_gpio *gpio = to_tegra_gpio(gc); 50862306a36Sopenharmony_ci void __iomem *base; 50962306a36Sopenharmony_ci u32 value; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, data->hwirq); 51262306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 51362306a36Sopenharmony_ci return; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 51662306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT; 51762306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci gpiochip_disable_irq(&gpio->gpio, data->hwirq); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic void tegra186_irq_unmask(struct irq_data *data) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(data); 52562306a36Sopenharmony_ci struct tegra_gpio *gpio = to_tegra_gpio(gc); 52662306a36Sopenharmony_ci void __iomem *base; 52762306a36Sopenharmony_ci u32 value; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, data->hwirq); 53062306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 53162306a36Sopenharmony_ci return; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci gpiochip_enable_irq(&gpio->gpio, data->hwirq); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 53662306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT; 53762306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int tegra186_irq_set_type(struct irq_data *data, unsigned int type) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(data); 54362306a36Sopenharmony_ci struct tegra_gpio *gpio = to_tegra_gpio(gc); 54462306a36Sopenharmony_ci void __iomem *base; 54562306a36Sopenharmony_ci u32 value; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci base = tegra186_gpio_get_base(gpio, data->hwirq); 54862306a36Sopenharmony_ci if (WARN_ON(base == NULL)) 54962306a36Sopenharmony_ci return -ENODEV; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 55262306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK; 55362306a36Sopenharmony_ci value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci switch (type & IRQ_TYPE_SENSE_MASK) { 55662306a36Sopenharmony_ci case IRQ_TYPE_NONE: 55762306a36Sopenharmony_ci break; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 56062306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 56162306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 56562306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 56962306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 57362306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL; 57462306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 57862306a36Sopenharmony_ci value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL; 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci default: 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if ((type & IRQ_TYPE_EDGE_BOTH) == 0) 58862306a36Sopenharmony_ci irq_set_handler_locked(data, handle_level_irq); 58962306a36Sopenharmony_ci else 59062306a36Sopenharmony_ci irq_set_handler_locked(data, handle_edge_irq); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (data->parent_data) 59362306a36Sopenharmony_ci return irq_chip_set_type_parent(data, type); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int tegra186_irq_set_wake(struct irq_data *data, unsigned int on) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci if (data->parent_data) 60162306a36Sopenharmony_ci return irq_chip_set_wake_parent(data, on); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic void tegra186_irq_print_chip(struct irq_data *data, struct seq_file *p) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(data); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci seq_printf(p, dev_name(gc->parent)); 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic const struct irq_chip tegra186_gpio_irq_chip = { 61462306a36Sopenharmony_ci .irq_ack = tegra186_irq_ack, 61562306a36Sopenharmony_ci .irq_mask = tegra186_irq_mask, 61662306a36Sopenharmony_ci .irq_unmask = tegra186_irq_unmask, 61762306a36Sopenharmony_ci .irq_set_type = tegra186_irq_set_type, 61862306a36Sopenharmony_ci .irq_set_wake = tegra186_irq_set_wake, 61962306a36Sopenharmony_ci .irq_print_chip = tegra186_irq_print_chip, 62062306a36Sopenharmony_ci .flags = IRQCHIP_IMMUTABLE, 62162306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 62262306a36Sopenharmony_ci}; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic void tegra186_gpio_irq(struct irq_desc *desc) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct tegra_gpio *gpio = irq_desc_get_handler_data(desc); 62762306a36Sopenharmony_ci struct irq_domain *domain = gpio->gpio.irq.domain; 62862306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 62962306a36Sopenharmony_ci unsigned int parent = irq_desc_get_irq(desc); 63062306a36Sopenharmony_ci unsigned int i, j, offset = 0; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci chained_irq_enter(chip, desc); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci for (i = 0; i < gpio->soc->num_ports; i++) { 63562306a36Sopenharmony_ci const struct tegra_gpio_port *port = &gpio->soc->ports[i]; 63662306a36Sopenharmony_ci unsigned int pin; 63762306a36Sopenharmony_ci unsigned long value; 63862306a36Sopenharmony_ci void __iomem *base; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci base = gpio->base + port->bank * 0x1000 + port->port * 0x200; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* skip ports that are not associated with this bank */ 64362306a36Sopenharmony_ci for (j = 0; j < gpio->num_irqs_per_bank; j++) { 64462306a36Sopenharmony_ci if (parent == gpio->irq[port->bank * gpio->num_irqs_per_bank + j]) 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (j == gpio->num_irqs_per_bank) 64962306a36Sopenharmony_ci goto skip; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci for_each_set_bit(pin, &value, port->pins) { 65462306a36Sopenharmony_ci int ret = generic_handle_domain_irq(domain, offset + pin); 65562306a36Sopenharmony_ci WARN_RATELIMIT(ret, "hwirq = %d", offset + pin); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ciskip: 65962306a36Sopenharmony_ci offset += port->pins; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci chained_irq_exit(chip, desc); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int tegra186_gpio_irq_domain_translate(struct irq_domain *domain, 66662306a36Sopenharmony_ci struct irq_fwspec *fwspec, 66762306a36Sopenharmony_ci unsigned long *hwirq, 66862306a36Sopenharmony_ci unsigned int *type) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data); 67162306a36Sopenharmony_ci unsigned int port, pin, i, offset = 0; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (WARN_ON(gpio->gpio.of_gpio_n_cells < 2)) 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (WARN_ON(fwspec->param_count < gpio->gpio.of_gpio_n_cells)) 67762306a36Sopenharmony_ci return -EINVAL; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci port = fwspec->param[0] / 8; 68062306a36Sopenharmony_ci pin = fwspec->param[0] % 8; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (port >= gpio->soc->num_ports) 68362306a36Sopenharmony_ci return -EINVAL; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci for (i = 0; i < port; i++) 68662306a36Sopenharmony_ci offset += gpio->soc->ports[i].pins; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; 68962306a36Sopenharmony_ci *hwirq = offset + pin; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, 69562306a36Sopenharmony_ci union gpio_irq_fwspec *gfwspec, 69662306a36Sopenharmony_ci unsigned int parent_hwirq, 69762306a36Sopenharmony_ci unsigned int parent_type) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 70062306a36Sopenharmony_ci struct irq_fwspec *fwspec = &gfwspec->fwspec; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci fwspec->fwnode = chip->irq.parent_domain->fwnode; 70362306a36Sopenharmony_ci fwspec->param_count = 3; 70462306a36Sopenharmony_ci fwspec->param[0] = gpio->soc->instance; 70562306a36Sopenharmony_ci fwspec->param[1] = parent_hwirq; 70662306a36Sopenharmony_ci fwspec->param[2] = parent_type; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip, 71262306a36Sopenharmony_ci unsigned int hwirq, 71362306a36Sopenharmony_ci unsigned int type, 71462306a36Sopenharmony_ci unsigned int *parent_hwirq, 71562306a36Sopenharmony_ci unsigned int *parent_type) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci *parent_hwirq = chip->irq.child_offset_to_irq(chip, hwirq); 71862306a36Sopenharmony_ci *parent_type = type; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip, 72462306a36Sopenharmony_ci unsigned int offset) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct tegra_gpio *gpio = gpiochip_get_data(chip); 72762306a36Sopenharmony_ci unsigned int i; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci for (i = 0; i < gpio->soc->num_ports; i++) { 73062306a36Sopenharmony_ci if (offset < gpio->soc->ports[i].pins) 73162306a36Sopenharmony_ci break; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci offset -= gpio->soc->ports[i].pins; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return offset + i * 8; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic const struct of_device_id tegra186_pmc_of_match[] = { 74062306a36Sopenharmony_ci { .compatible = "nvidia,tegra186-pmc" }, 74162306a36Sopenharmony_ci { .compatible = "nvidia,tegra194-pmc" }, 74262306a36Sopenharmony_ci { .compatible = "nvidia,tegra234-pmc" }, 74362306a36Sopenharmony_ci { /* sentinel */ } 74462306a36Sopenharmony_ci}; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct device *dev = gpio->gpio.parent; 74962306a36Sopenharmony_ci unsigned int i; 75062306a36Sopenharmony_ci u32 value; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci for (i = 0; i < gpio->soc->num_ports; i++) { 75362306a36Sopenharmony_ci const struct tegra_gpio_port *port = &gpio->soc->ports[i]; 75462306a36Sopenharmony_ci unsigned int offset, p = port->port; 75562306a36Sopenharmony_ci void __iomem *base; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci base = gpio->secure + port->bank * 0x1000 + 0x800; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci value = readl(base + TEGRA186_GPIO_CTL_SCR); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* 76262306a36Sopenharmony_ci * For controllers that haven't been locked down yet, make 76362306a36Sopenharmony_ci * sure to program the default interrupt route mapping. 76462306a36Sopenharmony_ci */ 76562306a36Sopenharmony_ci if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 && 76662306a36Sopenharmony_ci (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) { 76762306a36Sopenharmony_ci /* 76862306a36Sopenharmony_ci * On Tegra194 and later, each pin can be routed to one or more 76962306a36Sopenharmony_ci * interrupts. 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_ci dev_dbg(dev, "programming default interrupt routing for port %s\n", 77262306a36Sopenharmony_ci port->name); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, 0); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* 77762306a36Sopenharmony_ci * By default we only want to route GPIO pins to IRQ 0. This works 77862306a36Sopenharmony_ci * only under the assumption that we're running as the host kernel 77962306a36Sopenharmony_ci * and hence all GPIO pins are owned by Linux. 78062306a36Sopenharmony_ci * 78162306a36Sopenharmony_ci * For cases where Linux is the guest OS, the hypervisor will have 78262306a36Sopenharmony_ci * to configure the interrupt routing and pass only the valid 78362306a36Sopenharmony_ci * interrupts via device tree. 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_ci value = readl(base + offset); 78662306a36Sopenharmony_ci value = BIT(port->pins) - 1; 78762306a36Sopenharmony_ci writel(value, base + offset); 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic unsigned int tegra186_gpio_irqs_per_bank(struct tegra_gpio *gpio) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct device *dev = gpio->gpio.parent; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (gpio->num_irq > gpio->num_banks) { 79762306a36Sopenharmony_ci if (gpio->num_irq % gpio->num_banks != 0) 79862306a36Sopenharmony_ci goto error; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (gpio->num_irq < gpio->num_banks) 80262306a36Sopenharmony_ci goto error; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci gpio->num_irqs_per_bank = gpio->num_irq / gpio->num_banks; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (gpio->num_irqs_per_bank > gpio->soc->num_irqs_per_bank) 80762306a36Sopenharmony_ci goto error; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci return 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cierror: 81262306a36Sopenharmony_ci dev_err(dev, "invalid number of interrupts (%u) for %u banks\n", 81362306a36Sopenharmony_ci gpio->num_irq, gpio->num_banks); 81462306a36Sopenharmony_ci return -EINVAL; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic int tegra186_gpio_probe(struct platform_device *pdev) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci unsigned int i, j, offset; 82062306a36Sopenharmony_ci struct gpio_irq_chip *irq; 82162306a36Sopenharmony_ci struct tegra_gpio *gpio; 82262306a36Sopenharmony_ci struct device_node *np; 82362306a36Sopenharmony_ci char **names; 82462306a36Sopenharmony_ci int err; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 82762306a36Sopenharmony_ci if (!gpio) 82862306a36Sopenharmony_ci return -ENOMEM; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci gpio->soc = device_get_match_data(&pdev->dev); 83162306a36Sopenharmony_ci gpio->gpio.label = gpio->soc->name; 83262306a36Sopenharmony_ci gpio->gpio.parent = &pdev->dev; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* count the number of banks in the controller */ 83562306a36Sopenharmony_ci for (i = 0; i < gpio->soc->num_ports; i++) 83662306a36Sopenharmony_ci if (gpio->soc->ports[i].bank > gpio->num_banks) 83762306a36Sopenharmony_ci gpio->num_banks = gpio->soc->ports[i].bank; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci gpio->num_banks++; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* get register apertures */ 84262306a36Sopenharmony_ci gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security"); 84362306a36Sopenharmony_ci if (IS_ERR(gpio->secure)) { 84462306a36Sopenharmony_ci gpio->secure = devm_platform_ioremap_resource(pdev, 0); 84562306a36Sopenharmony_ci if (IS_ERR(gpio->secure)) 84662306a36Sopenharmony_ci return PTR_ERR(gpio->secure); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio"); 85062306a36Sopenharmony_ci if (IS_ERR(gpio->base)) { 85162306a36Sopenharmony_ci gpio->base = devm_platform_ioremap_resource(pdev, 1); 85262306a36Sopenharmony_ci if (IS_ERR(gpio->base)) 85362306a36Sopenharmony_ci return PTR_ERR(gpio->base); 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci err = platform_irq_count(pdev); 85762306a36Sopenharmony_ci if (err < 0) 85862306a36Sopenharmony_ci return err; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci gpio->num_irq = err; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci err = tegra186_gpio_irqs_per_bank(gpio); 86362306a36Sopenharmony_ci if (err < 0) 86462306a36Sopenharmony_ci return err; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq), 86762306a36Sopenharmony_ci GFP_KERNEL); 86862306a36Sopenharmony_ci if (!gpio->irq) 86962306a36Sopenharmony_ci return -ENOMEM; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci for (i = 0; i < gpio->num_irq; i++) { 87262306a36Sopenharmony_ci err = platform_get_irq(pdev, i); 87362306a36Sopenharmony_ci if (err < 0) 87462306a36Sopenharmony_ci return err; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci gpio->irq[i] = err; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci gpio->gpio.request = gpiochip_generic_request; 88062306a36Sopenharmony_ci gpio->gpio.free = gpiochip_generic_free; 88162306a36Sopenharmony_ci gpio->gpio.get_direction = tegra186_gpio_get_direction; 88262306a36Sopenharmony_ci gpio->gpio.direction_input = tegra186_gpio_direction_input; 88362306a36Sopenharmony_ci gpio->gpio.direction_output = tegra186_gpio_direction_output; 88462306a36Sopenharmony_ci gpio->gpio.get = tegra186_gpio_get; 88562306a36Sopenharmony_ci gpio->gpio.set = tegra186_gpio_set; 88662306a36Sopenharmony_ci gpio->gpio.set_config = tegra186_gpio_set_config; 88762306a36Sopenharmony_ci gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges; 88862306a36Sopenharmony_ci gpio->gpio.init_valid_mask = tegra186_init_valid_mask; 88962306a36Sopenharmony_ci if (gpio->soc->has_gte) { 89062306a36Sopenharmony_ci gpio->gpio.en_hw_timestamp = tegra186_gpio_en_hw_ts; 89162306a36Sopenharmony_ci gpio->gpio.dis_hw_timestamp = tegra186_gpio_dis_hw_ts; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci gpio->gpio.base = -1; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci for (i = 0; i < gpio->soc->num_ports; i++) 89762306a36Sopenharmony_ci gpio->gpio.ngpio += gpio->soc->ports[i].pins; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci names = devm_kcalloc(gpio->gpio.parent, gpio->gpio.ngpio, 90062306a36Sopenharmony_ci sizeof(*names), GFP_KERNEL); 90162306a36Sopenharmony_ci if (!names) 90262306a36Sopenharmony_ci return -ENOMEM; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) { 90562306a36Sopenharmony_ci const struct tegra_gpio_port *port = &gpio->soc->ports[i]; 90662306a36Sopenharmony_ci char *name; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci for (j = 0; j < port->pins; j++) { 90962306a36Sopenharmony_ci name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL, 91062306a36Sopenharmony_ci "P%s.%02x", port->name, j); 91162306a36Sopenharmony_ci if (!name) 91262306a36Sopenharmony_ci return -ENOMEM; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci names[offset + j] = name; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci offset += port->pins; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci gpio->gpio.names = (const char * const *)names; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci#if defined(CONFIG_OF_GPIO) 92362306a36Sopenharmony_ci gpio->gpio.of_gpio_n_cells = 2; 92462306a36Sopenharmony_ci gpio->gpio.of_xlate = tegra186_gpio_of_xlate; 92562306a36Sopenharmony_ci#endif /* CONFIG_OF_GPIO */ 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci irq = &gpio->gpio.irq; 92862306a36Sopenharmony_ci gpio_irq_chip_set_chip(irq, &tegra186_gpio_irq_chip); 92962306a36Sopenharmony_ci irq->fwnode = of_node_to_fwnode(pdev->dev.of_node); 93062306a36Sopenharmony_ci irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq; 93162306a36Sopenharmony_ci irq->populate_parent_alloc_arg = tegra186_gpio_populate_parent_fwspec; 93262306a36Sopenharmony_ci irq->child_offset_to_irq = tegra186_gpio_child_offset_to_irq; 93362306a36Sopenharmony_ci irq->child_irq_domain_ops.translate = tegra186_gpio_irq_domain_translate; 93462306a36Sopenharmony_ci irq->handler = handle_simple_irq; 93562306a36Sopenharmony_ci irq->default_type = IRQ_TYPE_NONE; 93662306a36Sopenharmony_ci irq->parent_handler = tegra186_gpio_irq; 93762306a36Sopenharmony_ci irq->parent_handler_data = gpio; 93862306a36Sopenharmony_ci irq->num_parents = gpio->num_irq; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* 94162306a36Sopenharmony_ci * To simplify things, use a single interrupt per bank for now. Some 94262306a36Sopenharmony_ci * chips support up to 8 interrupts per bank, which can be useful to 94362306a36Sopenharmony_ci * distribute the load and decrease the processing latency for GPIOs 94462306a36Sopenharmony_ci * but it also requires a more complicated interrupt routing than we 94562306a36Sopenharmony_ci * currently program. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_ci if (gpio->num_irqs_per_bank > 1) { 94862306a36Sopenharmony_ci irq->parents = devm_kcalloc(&pdev->dev, gpio->num_banks, 94962306a36Sopenharmony_ci sizeof(*irq->parents), GFP_KERNEL); 95062306a36Sopenharmony_ci if (!irq->parents) 95162306a36Sopenharmony_ci return -ENOMEM; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci for (i = 0; i < gpio->num_banks; i++) 95462306a36Sopenharmony_ci irq->parents[i] = gpio->irq[i * gpio->num_irqs_per_bank]; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci irq->num_parents = gpio->num_banks; 95762306a36Sopenharmony_ci } else { 95862306a36Sopenharmony_ci irq->num_parents = gpio->num_irq; 95962306a36Sopenharmony_ci irq->parents = gpio->irq; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (gpio->soc->num_irqs_per_bank > 1) 96362306a36Sopenharmony_ci tegra186_gpio_init_route_mapping(gpio); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci np = of_find_matching_node(NULL, tegra186_pmc_of_match); 96662306a36Sopenharmony_ci if (np) { 96762306a36Sopenharmony_ci if (of_device_is_available(np)) { 96862306a36Sopenharmony_ci irq->parent_domain = irq_find_host(np); 96962306a36Sopenharmony_ci of_node_put(np); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (!irq->parent_domain) 97262306a36Sopenharmony_ci return -EPROBE_DEFER; 97362306a36Sopenharmony_ci } else { 97462306a36Sopenharmony_ci of_node_put(np); 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, 97962306a36Sopenharmony_ci sizeof(*irq->map), GFP_KERNEL); 98062306a36Sopenharmony_ci if (!irq->map) 98162306a36Sopenharmony_ci return -ENOMEM; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) { 98462306a36Sopenharmony_ci const struct tegra_gpio_port *port = &gpio->soc->ports[i]; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci for (j = 0; j < port->pins; j++) 98762306a36Sopenharmony_ci irq->map[offset + j] = irq->parents[port->bank]; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci offset += port->pins; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ 99662306a36Sopenharmony_ci [TEGRA186_MAIN_GPIO_PORT_##_name] = { \ 99762306a36Sopenharmony_ci .name = #_name, \ 99862306a36Sopenharmony_ci .bank = _bank, \ 99962306a36Sopenharmony_ci .port = _port, \ 100062306a36Sopenharmony_ci .pins = _pins, \ 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra186_main_ports[] = { 100462306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7), 100562306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7), 100662306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( C, 3, 1, 7), 100762306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( D, 3, 2, 6), 100862306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( E, 2, 1, 8), 100962306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( F, 2, 2, 6), 101062306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( G, 4, 1, 6), 101162306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( H, 1, 0, 7), 101262306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( I, 0, 4, 8), 101362306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( J, 5, 0, 8), 101462306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( K, 5, 1, 1), 101562306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( L, 1, 1, 8), 101662306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( M, 5, 3, 6), 101762306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( N, 0, 0, 7), 101862306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( O, 0, 1, 4), 101962306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( P, 4, 0, 7), 102062306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( Q, 0, 2, 6), 102162306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( R, 0, 5, 6), 102262306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( T, 0, 3, 4), 102362306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( X, 1, 2, 8), 102462306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT( Y, 1, 3, 7), 102562306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT(BB, 2, 3, 2), 102662306a36Sopenharmony_ci TEGRA186_MAIN_GPIO_PORT(CC, 5, 2, 4), 102762306a36Sopenharmony_ci}; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra186_main_soc = { 103062306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra186_main_ports), 103162306a36Sopenharmony_ci .ports = tegra186_main_ports, 103262306a36Sopenharmony_ci .name = "tegra186-gpio", 103362306a36Sopenharmony_ci .instance = 0, 103462306a36Sopenharmony_ci .num_irqs_per_bank = 1, 103562306a36Sopenharmony_ci .has_vm_support = false, 103662306a36Sopenharmony_ci}; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ 103962306a36Sopenharmony_ci [TEGRA186_AON_GPIO_PORT_##_name] = { \ 104062306a36Sopenharmony_ci .name = #_name, \ 104162306a36Sopenharmony_ci .bank = _bank, \ 104262306a36Sopenharmony_ci .port = _port, \ 104362306a36Sopenharmony_ci .pins = _pins, \ 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra186_aon_ports[] = { 104762306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT( S, 0, 1, 5), 104862306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT( U, 0, 2, 6), 104962306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT( V, 0, 4, 8), 105062306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT( W, 0, 5, 8), 105162306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT( Z, 0, 7, 4), 105262306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT(AA, 0, 6, 8), 105362306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT(EE, 0, 3, 3), 105462306a36Sopenharmony_ci TEGRA186_AON_GPIO_PORT(FF, 0, 0, 5), 105562306a36Sopenharmony_ci}; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra186_aon_soc = { 105862306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra186_aon_ports), 105962306a36Sopenharmony_ci .ports = tegra186_aon_ports, 106062306a36Sopenharmony_ci .name = "tegra186-gpio-aon", 106162306a36Sopenharmony_ci .instance = 1, 106262306a36Sopenharmony_ci .num_irqs_per_bank = 1, 106362306a36Sopenharmony_ci .has_vm_support = false, 106462306a36Sopenharmony_ci}; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ 106762306a36Sopenharmony_ci [TEGRA194_MAIN_GPIO_PORT_##_name] = { \ 106862306a36Sopenharmony_ci .name = #_name, \ 106962306a36Sopenharmony_ci .bank = _bank, \ 107062306a36Sopenharmony_ci .port = _port, \ 107162306a36Sopenharmony_ci .pins = _pins, \ 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra194_main_ports[] = { 107562306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8), 107662306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( B, 4, 7, 2), 107762306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( C, 4, 3, 8), 107862306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( D, 4, 4, 4), 107962306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( E, 4, 5, 8), 108062306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( F, 4, 6, 6), 108162306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( G, 4, 0, 8), 108262306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( H, 4, 1, 8), 108362306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( I, 4, 2, 5), 108462306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( J, 5, 1, 6), 108562306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( K, 3, 0, 8), 108662306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( L, 3, 1, 4), 108762306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( M, 2, 3, 8), 108862306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( N, 2, 4, 3), 108962306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( O, 5, 0, 6), 109062306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( P, 2, 5, 8), 109162306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( Q, 2, 6, 8), 109262306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( R, 2, 7, 6), 109362306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( S, 3, 3, 8), 109462306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( T, 3, 4, 8), 109562306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( U, 3, 5, 1), 109662306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( V, 1, 0, 8), 109762306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( W, 1, 1, 2), 109862306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( X, 2, 0, 8), 109962306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( Y, 2, 1, 8), 110062306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT( Z, 2, 2, 8), 110162306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT(FF, 3, 2, 2), 110262306a36Sopenharmony_ci TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2) 110362306a36Sopenharmony_ci}; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic const struct tegra186_pin_range tegra194_main_pin_ranges[] = { 110662306a36Sopenharmony_ci { TEGRA194_MAIN_GPIO(GG, 0), "pex_l5_clkreq_n_pgg0" }, 110762306a36Sopenharmony_ci { TEGRA194_MAIN_GPIO(GG, 1), "pex_l5_rst_n_pgg1" }, 110862306a36Sopenharmony_ci}; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra194_main_soc = { 111162306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra194_main_ports), 111262306a36Sopenharmony_ci .ports = tegra194_main_ports, 111362306a36Sopenharmony_ci .name = "tegra194-gpio", 111462306a36Sopenharmony_ci .instance = 0, 111562306a36Sopenharmony_ci .num_irqs_per_bank = 8, 111662306a36Sopenharmony_ci .num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges), 111762306a36Sopenharmony_ci .pin_ranges = tegra194_main_pin_ranges, 111862306a36Sopenharmony_ci .pinmux = "nvidia,tegra194-pinmux", 111962306a36Sopenharmony_ci .has_vm_support = true, 112062306a36Sopenharmony_ci}; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ 112362306a36Sopenharmony_ci [TEGRA194_AON_GPIO_PORT_##_name] = { \ 112462306a36Sopenharmony_ci .name = #_name, \ 112562306a36Sopenharmony_ci .bank = _bank, \ 112662306a36Sopenharmony_ci .port = _port, \ 112762306a36Sopenharmony_ci .pins = _pins, \ 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra194_aon_ports[] = { 113162306a36Sopenharmony_ci TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8), 113262306a36Sopenharmony_ci TEGRA194_AON_GPIO_PORT(BB, 0, 4, 4), 113362306a36Sopenharmony_ci TEGRA194_AON_GPIO_PORT(CC, 0, 1, 8), 113462306a36Sopenharmony_ci TEGRA194_AON_GPIO_PORT(DD, 0, 2, 3), 113562306a36Sopenharmony_ci TEGRA194_AON_GPIO_PORT(EE, 0, 0, 7) 113662306a36Sopenharmony_ci}; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra194_aon_soc = { 113962306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra194_aon_ports), 114062306a36Sopenharmony_ci .ports = tegra194_aon_ports, 114162306a36Sopenharmony_ci .name = "tegra194-gpio-aon", 114262306a36Sopenharmony_ci .instance = 1, 114362306a36Sopenharmony_ci .num_irqs_per_bank = 8, 114462306a36Sopenharmony_ci .has_gte = true, 114562306a36Sopenharmony_ci .has_vm_support = false, 114662306a36Sopenharmony_ci}; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ 114962306a36Sopenharmony_ci [TEGRA234_MAIN_GPIO_PORT_##_name] = { \ 115062306a36Sopenharmony_ci .name = #_name, \ 115162306a36Sopenharmony_ci .bank = _bank, \ 115262306a36Sopenharmony_ci .port = _port, \ 115362306a36Sopenharmony_ci .pins = _pins, \ 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra234_main_ports[] = { 115762306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( A, 0, 0, 8), 115862306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( B, 0, 3, 1), 115962306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( C, 5, 1, 8), 116062306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( D, 5, 2, 4), 116162306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( E, 5, 3, 8), 116262306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( F, 5, 4, 6), 116362306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( G, 4, 0, 8), 116462306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( H, 4, 1, 8), 116562306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( I, 4, 2, 7), 116662306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( J, 5, 0, 6), 116762306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( K, 3, 0, 8), 116862306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( L, 3, 1, 4), 116962306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( M, 2, 0, 8), 117062306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( N, 2, 1, 8), 117162306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( P, 2, 2, 8), 117262306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( Q, 2, 3, 8), 117362306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( R, 2, 4, 6), 117462306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( X, 1, 0, 8), 117562306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( Y, 1, 1, 8), 117662306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT( Z, 1, 2, 8), 117762306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT(AC, 0, 1, 8), 117862306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT(AD, 0, 2, 4), 117962306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT(AE, 3, 3, 2), 118062306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT(AF, 3, 4, 4), 118162306a36Sopenharmony_ci TEGRA234_MAIN_GPIO_PORT(AG, 3, 2, 8), 118262306a36Sopenharmony_ci}; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra234_main_soc = { 118562306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra234_main_ports), 118662306a36Sopenharmony_ci .ports = tegra234_main_ports, 118762306a36Sopenharmony_ci .name = "tegra234-gpio", 118862306a36Sopenharmony_ci .instance = 0, 118962306a36Sopenharmony_ci .num_irqs_per_bank = 8, 119062306a36Sopenharmony_ci .has_vm_support = true, 119162306a36Sopenharmony_ci}; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \ 119462306a36Sopenharmony_ci [TEGRA234_AON_GPIO_PORT_##_name] = { \ 119562306a36Sopenharmony_ci .name = #_name, \ 119662306a36Sopenharmony_ci .bank = _bank, \ 119762306a36Sopenharmony_ci .port = _port, \ 119862306a36Sopenharmony_ci .pins = _pins, \ 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra234_aon_ports[] = { 120262306a36Sopenharmony_ci TEGRA234_AON_GPIO_PORT(AA, 0, 4, 8), 120362306a36Sopenharmony_ci TEGRA234_AON_GPIO_PORT(BB, 0, 5, 4), 120462306a36Sopenharmony_ci TEGRA234_AON_GPIO_PORT(CC, 0, 2, 8), 120562306a36Sopenharmony_ci TEGRA234_AON_GPIO_PORT(DD, 0, 3, 3), 120662306a36Sopenharmony_ci TEGRA234_AON_GPIO_PORT(EE, 0, 0, 8), 120762306a36Sopenharmony_ci TEGRA234_AON_GPIO_PORT(GG, 0, 1, 1), 120862306a36Sopenharmony_ci}; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra234_aon_soc = { 121162306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra234_aon_ports), 121262306a36Sopenharmony_ci .ports = tegra234_aon_ports, 121362306a36Sopenharmony_ci .name = "tegra234-gpio-aon", 121462306a36Sopenharmony_ci .instance = 1, 121562306a36Sopenharmony_ci .num_irqs_per_bank = 8, 121662306a36Sopenharmony_ci .has_gte = true, 121762306a36Sopenharmony_ci .has_vm_support = false, 121862306a36Sopenharmony_ci}; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ 122162306a36Sopenharmony_ci [TEGRA241_MAIN_GPIO_PORT_##_name] = { \ 122262306a36Sopenharmony_ci .name = #_name, \ 122362306a36Sopenharmony_ci .bank = _bank, \ 122462306a36Sopenharmony_ci .port = _port, \ 122562306a36Sopenharmony_ci .pins = _pins, \ 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra241_main_ports[] = { 122962306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(A, 0, 0, 8), 123062306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(B, 0, 1, 8), 123162306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(C, 0, 2, 2), 123262306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(D, 0, 3, 6), 123362306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(E, 0, 4, 8), 123462306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(F, 1, 0, 8), 123562306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(G, 1, 1, 8), 123662306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(H, 1, 2, 8), 123762306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(J, 1, 3, 8), 123862306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(K, 1, 4, 4), 123962306a36Sopenharmony_ci TEGRA241_MAIN_GPIO_PORT(L, 1, 5, 6), 124062306a36Sopenharmony_ci}; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra241_main_soc = { 124362306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra241_main_ports), 124462306a36Sopenharmony_ci .ports = tegra241_main_ports, 124562306a36Sopenharmony_ci .name = "tegra241-gpio", 124662306a36Sopenharmony_ci .instance = 0, 124762306a36Sopenharmony_ci .num_irqs_per_bank = 8, 124862306a36Sopenharmony_ci .has_vm_support = false, 124962306a36Sopenharmony_ci}; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \ 125262306a36Sopenharmony_ci [TEGRA241_AON_GPIO_PORT_##_name] = { \ 125362306a36Sopenharmony_ci .name = #_name, \ 125462306a36Sopenharmony_ci .bank = _bank, \ 125562306a36Sopenharmony_ci .port = _port, \ 125662306a36Sopenharmony_ci .pins = _pins, \ 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic const struct tegra_gpio_port tegra241_aon_ports[] = { 126062306a36Sopenharmony_ci TEGRA241_AON_GPIO_PORT(AA, 0, 0, 8), 126162306a36Sopenharmony_ci TEGRA241_AON_GPIO_PORT(BB, 0, 0, 4), 126262306a36Sopenharmony_ci}; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_cistatic const struct tegra_gpio_soc tegra241_aon_soc = { 126562306a36Sopenharmony_ci .num_ports = ARRAY_SIZE(tegra241_aon_ports), 126662306a36Sopenharmony_ci .ports = tegra241_aon_ports, 126762306a36Sopenharmony_ci .name = "tegra241-gpio-aon", 126862306a36Sopenharmony_ci .instance = 1, 126962306a36Sopenharmony_ci .num_irqs_per_bank = 8, 127062306a36Sopenharmony_ci .has_vm_support = false, 127162306a36Sopenharmony_ci}; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_cistatic const struct of_device_id tegra186_gpio_of_match[] = { 127462306a36Sopenharmony_ci { 127562306a36Sopenharmony_ci .compatible = "nvidia,tegra186-gpio", 127662306a36Sopenharmony_ci .data = &tegra186_main_soc 127762306a36Sopenharmony_ci }, { 127862306a36Sopenharmony_ci .compatible = "nvidia,tegra186-gpio-aon", 127962306a36Sopenharmony_ci .data = &tegra186_aon_soc 128062306a36Sopenharmony_ci }, { 128162306a36Sopenharmony_ci .compatible = "nvidia,tegra194-gpio", 128262306a36Sopenharmony_ci .data = &tegra194_main_soc 128362306a36Sopenharmony_ci }, { 128462306a36Sopenharmony_ci .compatible = "nvidia,tegra194-gpio-aon", 128562306a36Sopenharmony_ci .data = &tegra194_aon_soc 128662306a36Sopenharmony_ci }, { 128762306a36Sopenharmony_ci .compatible = "nvidia,tegra234-gpio", 128862306a36Sopenharmony_ci .data = &tegra234_main_soc 128962306a36Sopenharmony_ci }, { 129062306a36Sopenharmony_ci .compatible = "nvidia,tegra234-gpio-aon", 129162306a36Sopenharmony_ci .data = &tegra234_aon_soc 129262306a36Sopenharmony_ci }, { 129362306a36Sopenharmony_ci /* sentinel */ 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci}; 129662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra186_gpio_of_match); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic const struct acpi_device_id tegra186_gpio_acpi_match[] = { 129962306a36Sopenharmony_ci { .id = "NVDA0108", .driver_data = (kernel_ulong_t)&tegra186_main_soc }, 130062306a36Sopenharmony_ci { .id = "NVDA0208", .driver_data = (kernel_ulong_t)&tegra186_aon_soc }, 130162306a36Sopenharmony_ci { .id = "NVDA0308", .driver_data = (kernel_ulong_t)&tegra194_main_soc }, 130262306a36Sopenharmony_ci { .id = "NVDA0408", .driver_data = (kernel_ulong_t)&tegra194_aon_soc }, 130362306a36Sopenharmony_ci { .id = "NVDA0508", .driver_data = (kernel_ulong_t)&tegra241_main_soc }, 130462306a36Sopenharmony_ci { .id = "NVDA0608", .driver_data = (kernel_ulong_t)&tegra241_aon_soc }, 130562306a36Sopenharmony_ci {} 130662306a36Sopenharmony_ci}; 130762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, tegra186_gpio_acpi_match); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic struct platform_driver tegra186_gpio_driver = { 131062306a36Sopenharmony_ci .driver = { 131162306a36Sopenharmony_ci .name = "tegra186-gpio", 131262306a36Sopenharmony_ci .of_match_table = tegra186_gpio_of_match, 131362306a36Sopenharmony_ci .acpi_match_table = tegra186_gpio_acpi_match, 131462306a36Sopenharmony_ci }, 131562306a36Sopenharmony_ci .probe = tegra186_gpio_probe, 131662306a36Sopenharmony_ci}; 131762306a36Sopenharmony_cimodule_platform_driver(tegra186_gpio_driver); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra186 GPIO controller driver"); 132062306a36Sopenharmony_ciMODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); 132162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1322