]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
gpio: tegra186: Add support for pin ranges
authorThierry Reding <treding@nvidia.com>
Thu, 19 Mar 2020 12:27:30 +0000 (13:27 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Fri, 27 Mar 2020 10:37:31 +0000 (11:37 +0100)
Add support for Tegra SoC generations to specify a list of pin ranges
that map GPIOs to ranges of pins in the pin controller.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: https://lore.kernel.org/r/20200319122737.3063291-3-thierry.reding@gmail.com
Tested-by: Vidya Sagar <vidyas@nvidia.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/gpio/gpio-tegra186.c

index de241263d4be36f13d0018c3f1100399a8bb3b7f..1086c1fcaf4972ea6aaadc88d58f6e88c3d8c690 100644 (file)
@@ -58,11 +58,20 @@ struct tegra_gpio_port {
        unsigned int pins;
 };
 
+struct tegra186_pin_range {
+       unsigned int offset;
+       const char *group;
+};
+
 struct tegra_gpio_soc {
        const struct tegra_gpio_port *ports;
        unsigned int num_ports;
        const char *name;
        unsigned int instance;
+
+       const struct tegra186_pin_range *pin_ranges;
+       unsigned int num_pin_ranges;
+       const char *pinmux;
 };
 
 struct tegra_gpio {
@@ -254,6 +263,50 @@ static int tegra186_gpio_set_config(struct gpio_chip *chip,
        return 0;
 }
 
+static int tegra186_gpio_add_pin_ranges(struct gpio_chip *chip)
+{
+       struct tegra_gpio *gpio = gpiochip_get_data(chip);
+       struct pinctrl_dev *pctldev;
+       struct device_node *np;
+       unsigned int i, j;
+       int err;
+
+       if (!gpio->soc->pinmux || gpio->soc->num_pin_ranges == 0)
+               return 0;
+
+       np = of_find_compatible_node(NULL, NULL, gpio->soc->pinmux);
+       if (!np)
+               return -ENODEV;
+
+       pctldev = of_pinctrl_get(np);
+       of_node_put(np);
+       if (!pctldev)
+               return -EPROBE_DEFER;
+
+       for (i = 0; i < gpio->soc->num_pin_ranges; i++) {
+               unsigned int pin = gpio->soc->pin_ranges[i].offset, port;
+               const char *group = gpio->soc->pin_ranges[i].group;
+
+               port = pin / 8;
+               pin = pin % 8;
+
+               if (port >= gpio->soc->num_ports) {
+                       dev_warn(chip->parent, "invalid port %u for %s\n",
+                                port, group);
+                       continue;
+               }
+
+               for (j = 0; j < port; j++)
+                       pin += gpio->soc->ports[j].pins;
+
+               err = gpiochip_add_pingroup_range(chip, pctldev, pin, group);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
                                  const struct of_phandle_args *spec,
                                  u32 *flags)
@@ -578,12 +631,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        gpio->gpio.label = gpio->soc->name;
        gpio->gpio.parent = &pdev->dev;
 
+       gpio->gpio.request = gpiochip_generic_request;
+       gpio->gpio.free = gpiochip_generic_free;
        gpio->gpio.get_direction = tegra186_gpio_get_direction;
        gpio->gpio.direction_input = tegra186_gpio_direction_input;
        gpio->gpio.direction_output = tegra186_gpio_direction_output;
        gpio->gpio.get = tegra186_gpio_get,
        gpio->gpio.set = tegra186_gpio_set;
        gpio->gpio.set_config = tegra186_gpio_set_config;
+       gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges;
 
        gpio->gpio.base = -1;