|
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 <[email protected]>
|
| 6 | + |
6 | 7 | */
|
7 | 8 |
|
8 | 9 | #include <linux/gpio/driver.h>
|
|
11 | 12 | #include <linux/module.h>
|
12 | 13 | #include <linux/of_device.h>
|
13 | 14 | #include <linux/platform_device.h>
|
| 15 | +#include <linux/hte.h> |
14 | 16 |
|
15 | 17 | #include <dt-bindings/gpio/tegra186-gpio.h>
|
16 | 18 | #include <dt-bindings/gpio/tegra194-gpio.h>
|
|
36 | 38 | #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
|
37 | 39 | #define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5)
|
38 | 40 | #define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
|
| 41 | +#define TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC BIT(7) |
39 | 42 |
|
40 | 43 | #define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
|
41 | 44 | #define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff)
|
@@ -76,6 +79,7 @@ struct tegra_gpio_soc {
|
76 | 79 | const struct tegra186_pin_range *pin_ranges;
|
77 | 80 | unsigned int num_pin_ranges;
|
78 | 81 | const char *pinmux;
|
| 82 | + bool has_gte; |
79 | 83 | };
|
80 | 84 |
|
81 | 85 | struct tegra_gpio {
|
@@ -194,6 +198,76 @@ static int tegra186_gpio_direction_output(struct gpio_chip *chip,
|
194 | 198 | return 0;
|
195 | 199 | }
|
196 | 200 |
|
| 201 | +#define HTE_BOTH_EDGES (HTE_RISING_EDGE_TS | HTE_FALLING_EDGE_TS) |
| 202 | + |
| 203 | +static int tegra186_gpio_en_hw_ts(struct gpio_chip *gc, u32 offset, |
| 204 | + unsigned long flags) |
| 205 | +{ |
| 206 | + struct tegra_gpio *gpio; |
| 207 | + void __iomem *base; |
| 208 | + int value; |
| 209 | + |
| 210 | + if (!gc) |
| 211 | + return -EINVAL; |
| 212 | + |
| 213 | + gpio = gpiochip_get_data(gc); |
| 214 | + if (!gpio) |
| 215 | + return -ENODEV; |
| 216 | + |
| 217 | + base = tegra186_gpio_get_base(gpio, offset); |
| 218 | + if (WARN_ON(base == NULL)) |
| 219 | + return -EINVAL; |
| 220 | + |
| 221 | + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); |
| 222 | + value |= TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; |
| 223 | + |
| 224 | + if (flags == HTE_BOTH_EDGES) { |
| 225 | + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; |
| 226 | + } else if (flags == HTE_RISING_EDGE_TS) { |
| 227 | + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; |
| 228 | + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; |
| 229 | + } else if (flags == HTE_FALLING_EDGE_TS) { |
| 230 | + value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; |
| 231 | + } |
| 232 | + |
| 233 | + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); |
| 234 | + |
| 235 | + return 0; |
| 236 | +} |
| 237 | + |
| 238 | +static int tegra186_gpio_dis_hw_ts(struct gpio_chip *gc, u32 offset, |
| 239 | + unsigned long flags) |
| 240 | +{ |
| 241 | + struct tegra_gpio *gpio; |
| 242 | + void __iomem *base; |
| 243 | + int value; |
| 244 | + |
| 245 | + if (!gc) |
| 246 | + return -EINVAL; |
| 247 | + |
| 248 | + gpio = gpiochip_get_data(gc); |
| 249 | + if (!gpio) |
| 250 | + return -ENODEV; |
| 251 | + |
| 252 | + base = tegra186_gpio_get_base(gpio, offset); |
| 253 | + if (WARN_ON(base == NULL)) |
| 254 | + return -EINVAL; |
| 255 | + |
| 256 | + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); |
| 257 | + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC; |
| 258 | + if (flags == HTE_BOTH_EDGES) { |
| 259 | + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE; |
| 260 | + } else if (flags == HTE_RISING_EDGE_TS) { |
| 261 | + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; |
| 262 | + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL; |
| 263 | + } else if (flags == HTE_FALLING_EDGE_TS) { |
| 264 | + value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE; |
| 265 | + } |
| 266 | + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); |
| 267 | + |
| 268 | + return 0; |
| 269 | +} |
| 270 | + |
197 | 271 | static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
198 | 272 | {
|
199 | 273 | struct tegra_gpio *gpio = gpiochip_get_data(chip);
|
@@ -726,6 +800,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
726 | 800 | gpio->gpio.set = tegra186_gpio_set;
|
727 | 801 | gpio->gpio.set_config = tegra186_gpio_set_config;
|
728 | 802 | gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges;
|
| 803 | + if (gpio->soc->has_gte) { |
| 804 | + gpio->gpio.en_hw_timestamp = tegra186_gpio_en_hw_ts; |
| 805 | + gpio->gpio.dis_hw_timestamp = tegra186_gpio_dis_hw_ts; |
| 806 | + } |
729 | 807 |
|
730 | 808 | gpio->gpio.base = -1;
|
731 | 809 |
|
@@ -977,6 +1055,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = {
|
977 | 1055 | .name = "tegra194-gpio-aon",
|
978 | 1056 | .instance = 1,
|
979 | 1057 | .num_irqs_per_bank = 8,
|
| 1058 | + .has_gte = true, |
980 | 1059 | };
|
981 | 1060 |
|
982 | 1061 | #define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
|
0 commit comments