Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: tegra186: Add HTE support

Tegra194 AON GPIO controller with the use of its internal hardware
timestamping engine (HTE), also known as GTE, can timestamp GPIO lines
through system counter. This patch implements enable/disable callbacks
for the GPIO controller. In enable call, it will set timestamp function
bit and GPIO line rising/falling edges in the config register. In
disable call, it restores the state.

Signed-off-by: Dipen Patel <dipenp@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Dipen Patel and committed by
Thierry Reding
10e4afd6 42112dd7

+80 -1
+80 -1
drivers/gpio/gpio-tegra186.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * Copyright (c) 2016-2017 NVIDIA Corporation 3 + * Copyright (c) 2016-2022 NVIDIA Corporation 4 4 * 5 5 * Author: Thierry Reding <treding@nvidia.com> 6 + * Dipen Patel <dpatel@nvidia.com> 6 7 */ 7 8 8 9 #include <linux/gpio/driver.h> ··· 12 11 #include <linux/module.h> 13 12 #include <linux/of_device.h> 14 13 #include <linux/platform_device.h> 14 + #include <linux/hte.h> 15 15 16 16 #include <dt-bindings/gpio/tegra186-gpio.h> 17 17 #include <dt-bindings/gpio/tegra194-gpio.h> ··· 38 36 #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4) 39 37 #define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5) 40 38 #define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6) 39 + #define TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC BIT(7) 41 40 42 41 #define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04 43 42 #define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff) ··· 79 76 const struct tegra186_pin_range *pin_ranges; 80 77 unsigned int num_pin_ranges; 81 78 const char *pinmux; 79 + bool has_gte; 82 80 }; 83 81 84 82 struct tegra_gpio { ··· 193 189 value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 194 190 value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE; 195 191 value |= TEGRA186_GPIO_ENABLE_CONFIG_OUT; 192 + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 193 + 194 + return 0; 195 + } 196 + 197 + #define HTE_BOTH_EDGES (HTE_RISING_EDGE_TS | HTE_FALLING_EDGE_TS) 198 + 199 + static int tegra186_gpio_en_hw_ts(struct gpio_chip *gc, u32 offset, 200 + unsigned long flags) 201 + { 202 + struct tegra_gpio *gpio; 203 + void __iomem *base; 204 + int value; 205 + 206 + if (!gc) 207 + return -EINVAL; 208 + 209 + gpio = gpiochip_get_data(gc); 210 + if (!gpio) 211 + return -ENODEV; 212 + 213 + base = tegra186_gpio_get_base(gpio, offset); 214 + if (WARN_ON(base == NULL)) 215 + return -EINVAL; 216 + 217 + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 218 + value |= TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; 219 + 220 + if (flags == HTE_BOTH_EDGES) { 221 + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; 222 + } else if (flags == HTE_RISING_EDGE_TS) { 223 + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 224 + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; 225 + } else if (flags == HTE_FALLING_EDGE_TS) { 226 + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 227 + } 228 + 229 + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 230 + 231 + return 0; 232 + } 233 + 234 + static int tegra186_gpio_dis_hw_ts(struct gpio_chip *gc, u32 offset, 235 + unsigned long flags) 236 + { 237 + struct tegra_gpio *gpio; 238 + void __iomem *base; 239 + int value; 240 + 241 + if (!gc) 242 + return -EINVAL; 243 + 244 + gpio = gpiochip_get_data(gc); 245 + if (!gpio) 246 + return -ENODEV; 247 + 248 + base = tegra186_gpio_get_base(gpio, offset); 249 + if (WARN_ON(base == NULL)) 250 + return -EINVAL; 251 + 252 + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); 253 + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; 254 + if (flags == HTE_BOTH_EDGES) { 255 + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; 256 + } else if (flags == HTE_RISING_EDGE_TS) { 257 + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 258 + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; 259 + } else if (flags == HTE_FALLING_EDGE_TS) { 260 + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; 261 + } 196 262 writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); 197 263 198 264 return 0; ··· 800 726 gpio->gpio.set = tegra186_gpio_set; 801 727 gpio->gpio.set_config = tegra186_gpio_set_config; 802 728 gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges; 729 + if (gpio->soc->has_gte) { 730 + gpio->gpio.en_hw_timestamp = tegra186_gpio_en_hw_ts; 731 + gpio->gpio.dis_hw_timestamp = tegra186_gpio_dis_hw_ts; 732 + } 803 733 804 734 gpio->gpio.base = -1; 805 735 ··· 1055 977 .name = "tegra194-gpio-aon", 1056 978 .instance = 1, 1057 979 .num_irqs_per_bank = 8, 980 + .has_gte = true, 1058 981 }; 1059 982 1060 983 #define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \