diff options
Diffstat (limited to 'drivers/gpio/gpio-tegra186.c')
-rw-r--r-- | drivers/gpio/gpio-tegra186.c | 273 |
1 files changed, 249 insertions, 24 deletions
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index c026e7141e4e..54d9fa7da9c1 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@nvidia.com> + * Dipen Patel <dpatel@nvidia.com> */ #include <linux/gpio/driver.h> @@ -11,9 +12,12 @@ #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> +#include <dt-bindings/gpio/tegra234-gpio.h> +#include <dt-bindings/gpio/tegra241-gpio.h> /* security registers */ #define TEGRA186_GPIO_CTL_SCR 0x0c @@ -34,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) @@ -74,11 +79,11 @@ 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 { struct gpio_chip gpio; - struct irq_chip intc; unsigned int num_irq; unsigned int *irq; @@ -192,6 +197,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); @@ -341,9 +416,12 @@ static int tegra186_gpio_of_xlate(struct gpio_chip *chip, return offset + pin; } +#define to_tegra_gpio(x) container_of((x), struct tegra_gpio, gpio) + static void tegra186_irq_ack(struct irq_data *data) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = to_tegra_gpio(gc); void __iomem *base; base = tegra186_gpio_get_base(gpio, data->hwirq); @@ -355,7 +433,8 @@ static void tegra186_irq_ack(struct irq_data *data) static void tegra186_irq_mask(struct irq_data *data) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = to_tegra_gpio(gc); void __iomem *base; u32 value; @@ -366,11 +445,14 @@ static void tegra186_irq_mask(struct irq_data *data) value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT; writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); + + gpiochip_disable_irq(&gpio->gpio, data->hwirq); } static void tegra186_irq_unmask(struct irq_data *data) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = to_tegra_gpio(gc); void __iomem *base; u32 value; @@ -378,6 +460,8 @@ static void tegra186_irq_unmask(struct irq_data *data) if (WARN_ON(base == NULL)) return; + gpiochip_enable_irq(&gpio->gpio, data->hwirq); + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT; writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); @@ -385,7 +469,8 @@ static void tegra186_irq_unmask(struct irq_data *data) static int tegra186_irq_set_type(struct irq_data *data, unsigned int type) { - struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct tegra_gpio *gpio = to_tegra_gpio(gc); void __iomem *base; u32 value; @@ -448,6 +533,24 @@ static int tegra186_irq_set_wake(struct irq_data *data, unsigned int on) return 0; } +static void tegra186_irq_print_chip(struct irq_data *data, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + + seq_printf(p, dev_name(gc->parent)); +} + +static const struct irq_chip tegra186_gpio_irq_chip = { + .irq_ack = tegra186_irq_ack, + .irq_mask = tegra186_irq_mask, + .irq_unmask = tegra186_irq_unmask, + .irq_set_type = tegra186_irq_set_type, + .irq_set_wake = tegra186_irq_set_wake, + .irq_print_chip = tegra186_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static void tegra186_gpio_irq(struct irq_desc *desc) { struct tegra_gpio *gpio = irq_desc_get_handler_data(desc); @@ -518,16 +621,13 @@ static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain, return 0; } -static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, - unsigned int parent_hwirq, - unsigned int parent_type) +static int tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, + union gpio_irq_fwspec *gfwspec, + unsigned int parent_hwirq, + unsigned int parent_type) { struct tegra_gpio *gpio = gpiochip_get_data(chip); - struct irq_fwspec *fwspec; - - fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL); - if (!fwspec) - return NULL; + struct irq_fwspec *fwspec = &gfwspec->fwspec; fwspec->fwnode = chip->irq.parent_domain->fwnode; fwspec->param_count = 3; @@ -535,7 +635,7 @@ static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, fwspec->param[1] = parent_hwirq; fwspec->param[2] = parent_type; - return fwspec; + return 0; } static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip, @@ -718,6 +818,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; @@ -748,20 +852,12 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.names = (const char * const *)names; #if defined(CONFIG_OF_GPIO) - gpio->gpio.of_node = pdev->dev.of_node; gpio->gpio.of_gpio_n_cells = 2; gpio->gpio.of_xlate = tegra186_gpio_of_xlate; #endif /* CONFIG_OF_GPIO */ - gpio->intc.name = dev_name(&pdev->dev); - gpio->intc.irq_ack = tegra186_irq_ack; - gpio->intc.irq_mask = tegra186_irq_mask; - gpio->intc.irq_unmask = tegra186_irq_unmask; - gpio->intc.irq_set_type = tegra186_irq_set_type; - gpio->intc.irq_set_wake = tegra186_irq_set_wake; - irq = &gpio->gpio.irq; - irq->chip = &gpio->intc; + gpio_irq_chip_set_chip(irq, &tegra186_gpio_irq_chip); irq->fwnode = of_node_to_fwnode(pdev->dev.of_node); irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq; irq->populate_parent_alloc_arg = tegra186_gpio_populate_parent_fwspec; @@ -970,6 +1066,127 @@ 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) \ + [TEGRA234_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra234_main_ports[] = { + TEGRA234_MAIN_GPIO_PORT( A, 0, 0, 8), + TEGRA234_MAIN_GPIO_PORT( B, 0, 3, 1), + TEGRA234_MAIN_GPIO_PORT( C, 5, 1, 8), + TEGRA234_MAIN_GPIO_PORT( D, 5, 2, 4), + TEGRA234_MAIN_GPIO_PORT( E, 5, 3, 8), + TEGRA234_MAIN_GPIO_PORT( F, 5, 4, 6), + TEGRA234_MAIN_GPIO_PORT( G, 4, 0, 8), + TEGRA234_MAIN_GPIO_PORT( H, 4, 1, 8), + TEGRA234_MAIN_GPIO_PORT( I, 4, 2, 7), + TEGRA234_MAIN_GPIO_PORT( J, 5, 0, 6), + TEGRA234_MAIN_GPIO_PORT( K, 3, 0, 8), + TEGRA234_MAIN_GPIO_PORT( L, 3, 1, 4), + TEGRA234_MAIN_GPIO_PORT( M, 2, 0, 8), + TEGRA234_MAIN_GPIO_PORT( N, 2, 1, 8), + TEGRA234_MAIN_GPIO_PORT( P, 2, 2, 8), + TEGRA234_MAIN_GPIO_PORT( Q, 2, 3, 8), + TEGRA234_MAIN_GPIO_PORT( R, 2, 4, 6), + TEGRA234_MAIN_GPIO_PORT( X, 1, 0, 8), + TEGRA234_MAIN_GPIO_PORT( Y, 1, 1, 8), + TEGRA234_MAIN_GPIO_PORT( Z, 1, 2, 8), + TEGRA234_MAIN_GPIO_PORT(AC, 0, 1, 8), + TEGRA234_MAIN_GPIO_PORT(AD, 0, 2, 4), + TEGRA234_MAIN_GPIO_PORT(AE, 3, 3, 2), + TEGRA234_MAIN_GPIO_PORT(AF, 3, 4, 4), + TEGRA234_MAIN_GPIO_PORT(AG, 3, 2, 8), +}; + +static const struct tegra_gpio_soc tegra234_main_soc = { + .num_ports = ARRAY_SIZE(tegra234_main_ports), + .ports = tegra234_main_ports, + .name = "tegra234-gpio", + .instance = 0, + .num_irqs_per_bank = 8, +}; + +#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA234_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra234_aon_ports[] = { + TEGRA234_AON_GPIO_PORT(AA, 0, 4, 8), + TEGRA234_AON_GPIO_PORT(BB, 0, 5, 4), + TEGRA234_AON_GPIO_PORT(CC, 0, 2, 8), + TEGRA234_AON_GPIO_PORT(DD, 0, 3, 3), + TEGRA234_AON_GPIO_PORT(EE, 0, 0, 8), + TEGRA234_AON_GPIO_PORT(GG, 0, 1, 1), +}; + +static const struct tegra_gpio_soc tegra234_aon_soc = { + .num_ports = ARRAY_SIZE(tegra234_aon_ports), + .ports = tegra234_aon_ports, + .name = "tegra234-gpio-aon", + .instance = 1, + .num_irqs_per_bank = 8, +}; + +#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA241_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra241_main_ports[] = { + TEGRA241_MAIN_GPIO_PORT(A, 0, 0, 8), + TEGRA241_MAIN_GPIO_PORT(B, 0, 1, 8), + TEGRA241_MAIN_GPIO_PORT(C, 0, 2, 2), + TEGRA241_MAIN_GPIO_PORT(D, 0, 3, 6), + TEGRA241_MAIN_GPIO_PORT(E, 0, 4, 8), + TEGRA241_MAIN_GPIO_PORT(F, 1, 0, 8), + TEGRA241_MAIN_GPIO_PORT(G, 1, 1, 8), + TEGRA241_MAIN_GPIO_PORT(H, 1, 2, 8), + TEGRA241_MAIN_GPIO_PORT(J, 1, 3, 8), + TEGRA241_MAIN_GPIO_PORT(K, 1, 4, 4), + TEGRA241_MAIN_GPIO_PORT(L, 1, 5, 6), +}; + +static const struct tegra_gpio_soc tegra241_main_soc = { + .num_ports = ARRAY_SIZE(tegra241_main_ports), + .ports = tegra241_main_ports, + .name = "tegra241-gpio", + .instance = 0, + .num_irqs_per_bank = 8, +}; + +#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA241_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra241_aon_ports[] = { + TEGRA241_AON_GPIO_PORT(AA, 0, 0, 8), + TEGRA241_AON_GPIO_PORT(BB, 0, 0, 4), +}; + +static const struct tegra_gpio_soc tegra241_aon_soc = { + .num_ports = ARRAY_SIZE(tegra241_aon_ports), + .ports = tegra241_aon_ports, + .name = "tegra241-gpio-aon", + .instance = 1, + .num_irqs_per_bank = 8, }; static const struct of_device_id tegra186_gpio_of_match[] = { @@ -986,6 +1203,12 @@ static const struct of_device_id tegra186_gpio_of_match[] = { .compatible = "nvidia,tegra194-gpio-aon", .data = &tegra194_aon_soc }, { + .compatible = "nvidia,tegra234-gpio", + .data = &tegra234_main_soc + }, { + .compatible = "nvidia,tegra234-gpio-aon", + .data = &tegra234_aon_soc + }, { /* sentinel */ } }; @@ -996,6 +1219,8 @@ static const struct acpi_device_id tegra186_gpio_acpi_match[] = { { .id = "NVDA0208", .driver_data = (kernel_ulong_t)&tegra186_aon_soc }, { .id = "NVDA0308", .driver_data = (kernel_ulong_t)&tegra194_main_soc }, { .id = "NVDA0408", .driver_data = (kernel_ulong_t)&tegra194_aon_soc }, + { .id = "NVDA0508", .driver_data = (kernel_ulong_t)&tegra241_main_soc }, + { .id = "NVDA0608", .driver_data = (kernel_ulong_t)&tegra241_aon_soc }, {} }; MODULE_DEVICE_TABLE(acpi, tegra186_gpio_acpi_match); |