The IP supports a reset GPIO. When S2RAM will be added, we must ensure
the reset line (if any) is deasserted when resuming. Add support for
it.

Signed-off-by: Miquel Raynal <[email protected]>
---
 drivers/pci/controller/pci-aardvark.c | 57 +++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/drivers/pci/controller/pci-aardvark.c 
b/drivers/pci/controller/pci-aardvark.c
index b95eb2aa00bb..1d31d74ddab7 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
@@ -17,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/of_address.h>
+#include <linux/of_gpio.h>
 #include <linux/of_pci.h>
 
 #include "../pci.h"
@@ -201,6 +203,7 @@ struct advk_pcie {
        u16 msi_msg;
        int root_bus_nr;
        struct pci_bridge_emul bridge;
+       struct gpio_desc *reset_gpio;
 };
 
 static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
@@ -973,6 +976,55 @@ static int advk_pcie_parse_request_of_pci_ranges(struct 
advk_pcie *pcie)
        return err;
 }
 
+static int advk_pcie_hard_reset(struct advk_pcie *pcie)
+{
+       if (!pcie->reset_gpio)
+               return -EINVAL;
+
+       gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+       msleep(1);
+       gpiod_set_value_cansleep(pcie->reset_gpio, 1);
+
+       return 0;
+}
+
+static int advk_pcie_setup_reset_gpio(struct advk_pcie *pcie)
+{
+       struct device *dev = &pcie->pdev->dev;
+       enum of_gpio_flags of_flags;
+       unsigned long gpio_flags;
+       int gpio_nb;
+       int ret;
+
+       gpio_nb = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0,
+                                         &of_flags);
+       if (gpio_nb == -EPROBE_DEFER)
+               return gpio_nb;
+
+       /* Old bindings miss the reset GPIO handle */
+       if (!gpio_is_valid(gpio_nb)) {
+               dev_warn(dev, "Reset GPIO unavailable\n");
+               return 0;
+       }
+
+       if (of_flags & OF_GPIO_ACTIVE_LOW)
+               gpio_flags = GPIOF_ACTIVE_LOW |
+                            GPIOF_OUT_INIT_LOW;
+       else
+               gpio_flags = GPIOF_OUT_INIT_HIGH;
+
+       ret = devm_gpio_request_one(dev, gpio_nb, gpio_flags,
+                                   "pcie-aardvark-reset");
+       if (ret) {
+               dev_err(dev, "Failed to retrieve reset GPIO (%d)\n", ret);
+               return ret;
+       }
+
+       pcie->reset_gpio = gpio_to_desc(gpio_nb);
+
+       return 0;
+}
+
 static int advk_pcie_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1008,6 +1060,11 @@ static int advk_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = advk_pcie_setup_reset_gpio(pcie);
+       if (ret)
+               return ret;
+
+       advk_pcie_hard_reset(pcie);
        advk_pcie_setup_hw(pcie);
 
        advk_sw_pci_bridge_init(pcie);
-- 
2.19.1

Reply via email to