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@xxxxxxxxxx> --- Changes in v4: - Added edge setup and hardware timestamping enable/disable APIs. drivers/gpio/gpio-tegra186.c | 81 +++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 031fe105b58e..6a6852b4785e 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2017 NVIDIA Corporation + * Copyright (c) 2016-2022 NVIDIA Corporation * * Author: Thierry Reding <treding@xxxxxxxxxx> + * Dipen Patel <dpatel@xxxxxxxxxx> */ #include <linux/gpio/driver.h> @@ -11,6 +12,7 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/hte.h> #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra194-gpio.h> @@ -36,6 +38,7 @@ #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4) #define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5) #define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6) +#define TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC BIT(7) #define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04 #define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff) @@ -76,6 +79,7 @@ struct tegra_gpio_soc { const struct tegra186_pin_range *pin_ranges; unsigned int num_pin_ranges; const char *pinmux; + bool has_gte; }; struct tegra_gpio { @@ -194,6 +198,76 @@ static int tegra186_gpio_direction_output(struct gpio_chip *chip, return 0; } +#define HTE_BOTH_EDGES (HTE_RISING_EDGE_TS | HTE_FALLING_EDGE_TS) + +static int tegra186_gpio_en_hw_ts(struct gpio_chip *gc, u32 offset, + unsigned long flags) +{ + struct tegra_gpio *gpio; + void __iomem *base; + int value; + + if (!gc) + return -EINVAL; + + gpio = gpiochip_get_data(gc); + if (!gpio) + return -ENODEV; + + base = tegra186_gpio_get_base(gpio, offset); + if (WARN_ON(base == NULL)) + return -EINVAL; + + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); + value |= TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; + + if (flags == HTE_BOTH_EDGES) { + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; + } else if (flags == HTE_RISING_EDGE_TS) { + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; + } else if (flags == HTE_FALLING_EDGE_TS) { + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; + } + + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); + + return 0; +} + +static int tegra186_gpio_dis_hw_ts(struct gpio_chip *gc, u32 offset, + unsigned long flags) +{ + struct tegra_gpio *gpio; + void __iomem *base; + int value; + + if (!gc) + return -EINVAL; + + gpio = gpiochip_get_data(gc); + if (!gpio) + return -ENODEV; + + base = tegra186_gpio_get_base(gpio, offset); + if (WARN_ON(base == NULL)) + return -EINVAL; + + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; + if (flags == HTE_BOTH_EDGES) { + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; + } else if (flags == HTE_RISING_EDGE_TS) { + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; + } else if (flags == HTE_FALLING_EDGE_TS) { + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; + } + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); + + return 0; +} + static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct tegra_gpio *gpio = gpiochip_get_data(chip); @@ -726,6 +800,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.set = tegra186_gpio_set; gpio->gpio.set_config = tegra186_gpio_set_config; gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges; + if (gpio->soc->has_gte) { + gpio->gpio.en_hw_timestamp = tegra186_gpio_en_hw_ts; + gpio->gpio.dis_hw_timestamp = tegra186_gpio_dis_hw_ts; + } gpio->gpio.base = -1; @@ -977,6 +1055,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { .name = "tegra194-gpio-aon", .instance = 1, .num_irqs_per_bank = 8, + .has_gte = true, }; #define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ -- 2.17.1