Commit 10e4afd6 authored by Dipen Patel's avatar Dipen Patel Committed by Thierry Reding

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: default avatarDipen Patel <dipenp@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 42112dd7
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2016-2017 NVIDIA Corporation * Copyright (c) 2016-2022 NVIDIA Corporation
* *
* Author: Thierry Reding <treding@nvidia.com> * Author: Thierry Reding <treding@nvidia.com>
* Dipen Patel <dpatel@nvidia.com>
*/ */
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
...@@ -11,6 +12,7 @@ ...@@ -11,6 +12,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/hte.h>
#include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra186-gpio.h>
#include <dt-bindings/gpio/tegra194-gpio.h> #include <dt-bindings/gpio/tegra194-gpio.h>
...@@ -36,6 +38,7 @@ ...@@ -36,6 +38,7 @@
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4) #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5) #define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5)
#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6) #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 0x04
#define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff) #define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff)
...@@ -76,6 +79,7 @@ struct tegra_gpio_soc { ...@@ -76,6 +79,7 @@ struct tegra_gpio_soc {
const struct tegra186_pin_range *pin_ranges; const struct tegra186_pin_range *pin_ranges;
unsigned int num_pin_ranges; unsigned int num_pin_ranges;
const char *pinmux; const char *pinmux;
bool has_gte;
}; };
struct tegra_gpio { struct tegra_gpio {
...@@ -194,6 +198,76 @@ static int tegra186_gpio_direction_output(struct gpio_chip *chip, ...@@ -194,6 +198,76 @@ static int tegra186_gpio_direction_output(struct gpio_chip *chip,
return 0; 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) static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset)
{ {
struct tegra_gpio *gpio = gpiochip_get_data(chip); struct tegra_gpio *gpio = gpiochip_get_data(chip);
...@@ -726,6 +800,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev) ...@@ -726,6 +800,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.set = tegra186_gpio_set; gpio->gpio.set = tegra186_gpio_set;
gpio->gpio.set_config = tegra186_gpio_set_config; gpio->gpio.set_config = tegra186_gpio_set_config;
gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges; 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; gpio->gpio.base = -1;
...@@ -977,6 +1055,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { ...@@ -977,6 +1055,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = {
.name = "tegra194-gpio-aon", .name = "tegra194-gpio-aon",
.instance = 1, .instance = 1,
.num_irqs_per_bank = 8, .num_irqs_per_bank = 8,
.has_gte = true,
}; };
#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ #define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment