diff mbox series

[6/8] PCI: aardvark: Add support for issuing PERST via GPIO

Message ID 20200415160348.1146-2-pali@kernel.org
State New
Headers show
Series PCI: aardvark: Fix support for Turris MOX and Compex wifi cards | expand

Commit Message

Pali Rohár April 15, 2020, 4:03 p.m. UTC
bindings/pci/pci.txt defines standard DT property reset-gpios for
specifying PERST GPIO. Read this property from Device Tree via
devm_gpiod_get_from_of_node() function. As this property is optional,
function may return -ENOENT. During initialization of aardvark PCI
controller toggle supplied GPIO to issue PERST.

Some Compex ath10k cards (e.g. WLE900VX or WLE1216) are not detected after
reboot when PERST is not issued during driver initialization. And Compex
WLE1216 cards need to be in reset state for at least 1ms otherwise they are
not detected too.

Tested on Turris MOX and after this change Compex cards are detected also
after rebooting board.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/pci/controller/pci-aardvark.c | 30 ++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

Comments

Marek Behun April 19, 2020, 3:23 a.m. UTC | #1
On Wed, 15 Apr 2020 18:03:46 +0200
Pali Rohár <pali@kernel.org> wrote:

> +	if (IS_ERR(pcie->reset_gpio)) {
> +		if (PTR_ERR(pcie->reset_gpio) == -ENOENT) {
> +			pcie->reset_gpio = NULL;

this assignment is redundant, the variable is already NULL, such
structures are zeroed after allocation

> +		} else {
> +			if (PTR_ERR(pcie->reset_gpio) != -EPROBE_DEFER)
> +				dev_err(dev, "Failed to retrieve reset GPIO (%ld)\n",
> +					PTR_ERR(pcie->reset_gpio));
> +			return PTR_ERR(pcie->reset_gpio);
> +		}
> +	}
diff mbox series

Patch

diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
index a83bbc86e428..6a97a3838098 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>
@@ -18,6 +19,7 @@ 
 #include <linux/platform_device.h>
 #include <linux/msi.h>
 #include <linux/of_address.h>
+#include <linux/of_gpio.h>
 #include <linux/of_pci.h>
 
 #include "../pci.h"
@@ -203,6 +205,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)
@@ -280,6 +283,14 @@  static void advk_pcie_setup_hw(struct advk_pcie *pcie)
 	int max_link_speed, neg_link_speed;
 	u32 reg;
 
+	if (pcie->reset_gpio) {
+		dev_info(dev, "issuing PERST via reset GPIO for 1ms\n");
+		gpiod_set_value_cansleep(pcie->reset_gpio, 1);
+		/* Detection of some Compex WLE1216 cards needs at least 1ms */
+		mdelay(1);
+		gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+	}
+
 	/* Set to Direct mode */
 	reg = advk_readl(pcie, CTRL_CONFIG_REG);
 	reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT);
@@ -358,7 +369,8 @@  static void advk_pcie_setup_hw(struct advk_pcie *pcie)
 
 	/*
 	 * PERST# signal could have been asserted by pinctrl subsystem before
-	 * probe() callback has been called, making the endpoint going into
+	 * probe() callback has been called or issued explicitly by reset gpio
+	 * routine at beginning of this function, making the endpoint going into
 	 * fundamental reset. As required by PCI Express spec a delay for at
 	 * least 100ms after such a reset before link training is needed.
 	 */
@@ -1043,6 +1055,22 @@  static int advk_pcie_probe(struct platform_device *pdev)
 	}
 	pcie->root_bus_nr = bus->start;
 
+	/* Returns -ENOENT if reset-gpios property is not populated */
+	pcie->reset_gpio = devm_gpiod_get_from_of_node(dev, dev->of_node,
+						       "reset-gpios", 0,
+						       GPIOD_OUT_LOW,
+						       "pcie1-reset");
+	if (IS_ERR(pcie->reset_gpio)) {
+		if (PTR_ERR(pcie->reset_gpio) == -ENOENT) {
+			pcie->reset_gpio = NULL;
+		} else {
+			if (PTR_ERR(pcie->reset_gpio) != -EPROBE_DEFER)
+				dev_err(dev, "Failed to retrieve reset GPIO (%ld)\n",
+					PTR_ERR(pcie->reset_gpio));
+			return PTR_ERR(pcie->reset_gpio);
+		}
+	}
+
 	advk_pcie_setup_hw(pcie);
 
 	advk_sw_pci_bridge_init(pcie);