Skip to content

Commit

Permalink
gpio: tegra186: Add HTE support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dipen Patel authored and Thierry Reding committed May 4, 2022
1 parent 42112dd commit 10e4afd
Showing 1 changed file with 80 additions and 1 deletion.
81 changes: 80 additions & 1 deletion drivers/gpio/gpio-tegra186.c
Original file line number Diff line number Diff line change
@@ -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@nvidia.com>
* Dipen Patel <dpatel@nvidia.com>
*/

#include <linux/gpio/driver.h>
Expand All @@ -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>
Expand All @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) \
Expand Down

0 comments on commit 10e4afd

Please sign in to comment.