diff --git a/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt b/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt
index adff16c71d21..00a3e47ab560 100644
--- a/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt
@@ -127,6 +127,12 @@ Required properties:
- 8: Active low level-sensitive.
Valid combinations are 1, 2, 3, 4, 8.
+Optional properties:
+- timestamp-engine
+ AON GPIO controller has timestamp engine which can hardware timestamp
+ GPIO configured as input and IRQ. This property specifies hardware
+ timestamp engine (HTE) device-tree node.
+
Example:
#include <dt-bindings/interrupt-controller/irq.h>@@ -162,4 +168,5 @@ gpio@c2f0000 {
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ timestamp-engine = <&tegra_hte_aon>;
};diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 05974b760796..4962d7de73f1 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -11,6 +11,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>
@@ -34,6 +35,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)
@@ -79,6 +81,7 @@ struct tegra_gpio {
struct irq_chip intc;
unsigned int num_irq;
unsigned int *irq;
+ struct device_node *hte_nd;
const struct tegra_gpio_soc *soc;
@@ -188,6 +191,65 @@ static int tegra186_gpio_direction_output(struct gpio_chip *chip,
return 0;
}
+static int tegra186_gpio_timestamp_control(struct gpio_chip *chip,
+ unsigned int offset,
+ struct hte_ts_desc **hdesc,
+ bool enable)
+{
+ struct tegra_gpio *gpio = gpiochip_get_data(chip);
+ void __iomem *base;
+ int value;
+ struct hte_ts_desc *desc;
+
+ if (!gpio->hte_nd)
+ return -ENOTSUPP;
+
+ base = tegra186_gpio_get_base(gpio, offset);
+ if (WARN_ON(base == NULL))
+ return -EINVAL;
+
+ value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+ if (enable) {
+ desc = hte_req_ts_by_dt_node(gpio->hte_nd, offset, NULL);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ *hdesc = desc;
+ value |= TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC;
+ } else {
+ desc = *hdesc;
+ hte_release_ts(desc);
+ value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC;
+ }
+
+ writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+ return 0;
+}
+
+static int tegra186_gpio_get_hw_timestamp(struct gpio_chip *chip, bool block,
+ struct hte_ts_desc *hdesc, u64 *ts)
+{
+ struct hte_ts_data el;
+ int ret;
+
+ if (!hdesc || !ts)
+ return -EINVAL;
+
+ if (!block)
+ ret = hte_retrieve_ts_ns(hdesc, &el, 1);
+ else
+ /* Wait till timestamp is available */
+ ret = hte_retrieve_ts_ns_wait(hdesc, &el, 1);
+
+ if (ret)
+ return ret;
+
+ *ts = el.tsc;
+
+ return 0;
+}
+
static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct tegra_gpio *gpio = gpiochip_get_data(chip);@@ -605,6 +667,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
struct device_node *np;
char **names;
int err;
+ phandle hte_ph;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@@ -730,6 +793,21 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
offset += port->pins;
}
+ err = of_property_read_u32(gpio->gpio.of_node,
+ "timestamp-engine", &hte_ph);
+ if (!err) {
+ gpio->hte_nd = of_find_node_by_phandle(hte_ph);
+ if (!gpio->hte_nd)
+ return -ENOSYS;
+
+ gpio->gpio.timestamp_control = tegra186_gpio_timestamp_control;
+ gpio->gpio.get_hw_timestamp = tegra186_gpio_get_hw_timestamp;
+
+ of_node_put(gpio->hte_nd);
+ } else {
+ gpio->hte_nd = NULL;
+ }
+
platform_set_drvdata(pdev, gpio);
err = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio);--
2.17.1