All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@gmail.com>
To: JC Kuo <jckuo@nvidia.com>
Cc: gregkh@linuxfoundation.org, robh@kernel.org,
	jonathanh@nvidia.com, kishon@ti.com, linux-tegra@vger.kernel.org,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, nkristam@nvidia.com
Subject: Re: [PATCH v2 12/12] xhci: tegra: enable ELPG for runtime/system PM
Date: Mon, 31 Aug 2020 14:50:35 +0200	[thread overview]
Message-ID: <20200831125035.GH1689119@ulmo> (raw)
In-Reply-To: <20200831044043.1561074-13-jckuo@nvidia.com>

[-- Attachment #1: Type: text/plain, Size: 18885 bytes --]

On Mon, Aug 31, 2020 at 12:40:43PM +0800, JC Kuo wrote:
> This commit implements the complete programming sequence for ELPG
> entry and exit.
> 
>  1. At ELPG entry, invokes tegra_xusb_padctl_enable_phy_sleepwalk()
>     and tegra_xusb_padctl_enable_phy_wake() to configure XUSB PADCTL
>     sleepwalk and wake detection circuits to maintain USB lines level
>     and respond to wake events (wake-on-connect, wake-on-disconnect,
>     device-initiated-wake).
> 
>  2. At ELPG exit, invokes tegra_xusb_padctl_disable_phy_sleepwalk()
>     and tegra_xusb_padctl_disable_phy_wake() to disarm sleepwalk and
>     wake detection circuits.
> 
> At runtime suspend, XUSB host controller can enter ELPG to reduce
> power consumption. When XUSB PADCTL wake detection circuit detects
> a wake event, an interrupt will be raised. xhci-tegra driver then
> will invoke pm_runtime_resume() for xhci-tegra.
> 
> Runtime resume could also be triggered by protocol drivers, this is
> the host-initiated-wake event. At runtime resume, xhci-tegra driver
> brings XUSB host controller out of ELPG to handle the wake events.
> 
> The same ELPG enter/exit procedure will be performed for system
> suspend/resume path so USB devices can remain connected across SC7.
> 
> Signed-off-by: JC Kuo <jckuo@nvidia.com>
> ---
>  drivers/usb/host/xhci-tegra.c | 391 +++++++++++++++++++++++++++++++---
>  1 file changed, 361 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
> index ce6526c2caf6..9530cfc83f45 100644
> --- a/drivers/usb/host/xhci-tegra.c
> +++ b/drivers/usb/host/xhci-tegra.c
> @@ -15,9 +15,11 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
> +#include <linux/of_irq.h>
>  #include <linux/phy/phy.h>
>  #include <linux/phy/tegra/xusb.h>
>  #include <linux/platform_device.h>
> +#include <linux/usb/ch9.h>
>  #include <linux/pm.h>
>  #include <linux/pm_domain.h>
>  #include <linux/pm_runtime.h>
> @@ -224,6 +226,7 @@ struct tegra_xusb {
>  
>  	int xhci_irq;
>  	int mbox_irq;
> +	int padctl_irq;
>  
>  	void __iomem *ipfs_base;
>  	void __iomem *fpci_base;
> @@ -268,10 +271,13 @@ struct tegra_xusb {
>  		dma_addr_t phys;
>  	} fw;
>  
> +	bool suspended;
>  	struct tegra_xusb_context context;
>  };
>  
>  static struct hc_driver __read_mostly tegra_xhci_hc_driver;
> +static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool runtime);
> +static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime);
>  
>  static inline u32 fpci_readl(struct tegra_xusb *tegra, unsigned int offset)
>  {
> @@ -657,6 +663,9 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
>  
>  	mutex_lock(&tegra->lock);
>  
> +	if (pm_runtime_suspended(tegra->dev) || tegra->suspended)
> +		goto out;
> +
>  	value = fpci_readl(tegra, tegra->soc->mbox.data_out);
>  	tegra_xusb_mbox_unpack(&msg, value);
>  
> @@ -670,6 +679,7 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
>  
>  	tegra_xusb_mbox_handle(tegra, &msg);
>  
> +out:
>  	mutex_unlock(&tegra->lock);
>  	return IRQ_HANDLED;
>  }
> @@ -812,12 +822,27 @@ static void tegra_xusb_phy_disable(struct tegra_xusb *tegra)
>  
>  static int tegra_xusb_runtime_suspend(struct device *dev)
>  {
> -	return 0;
> +	struct tegra_xusb *tegra = dev_get_drvdata(dev);
> +	int ret;
> +
> +	synchronize_irq(tegra->mbox_irq);
> +	mutex_lock(&tegra->lock);
> +	ret = tegra_xusb_enter_elpg(tegra, true);
> +	mutex_unlock(&tegra->lock);
> +
> +	return ret;
>  }
>  
>  static int tegra_xusb_runtime_resume(struct device *dev)
>  {
> -	return 0;
> +	struct tegra_xusb *tegra = dev_get_drvdata(dev);
> +	int err;
> +
> +	mutex_lock(&tegra->lock);
> +	err = tegra_xusb_exit_elpg(tegra, true);
> +	mutex_unlock(&tegra->lock);
> +
> +	return err;
>  }
>  
>  #ifdef CONFIG_PM_SLEEP
> @@ -1121,6 +1146,22 @@ static int __tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
>  	return err;
>  }
>  
> +static irqreturn_t tegra_xusb_padctl_irq(int irq, void *data)
> +{
> +	struct tegra_xusb *tegra = data;
> +
> +	mutex_lock(&tegra->lock);
> +	if (tegra->suspended) {
> +		mutex_unlock(&tegra->lock);
> +		return IRQ_HANDLED;
> +	}
> +	mutex_unlock(&tegra->lock);

Blank lines before and after a block can help make this less cluttered.

> +
> +	pm_runtime_resume(tegra->dev);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static int tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
>  {
>  	int err;
> @@ -1244,6 +1285,51 @@ static void tegra_xhci_id_work(struct work_struct *work)
>  	}
>  }
>  
> +static bool is_usb2_otg_phy(struct tegra_xusb *tegra, int index)

unsigned int index?

> +{
> +	return (tegra->usbphy[index] != NULL);
> +}
> +
> +static bool is_usb3_otg_phy(struct tegra_xusb *tegra, int index)

Here too.

> +{
> +	struct tegra_xusb_padctl *padctl = tegra->padctl;
> +	int i, port;

These can also be unsigned.

> +
> +	for (i = 0; i < tegra->num_usb_phys; i++) {
> +		if (is_usb2_otg_phy(tegra, i)) {
> +			port = tegra_xusb_padctl_get_usb3_companion(padctl,i);

Space after ",".

> +			if (index == port)
> +				return true;
> +		}
> +	}
> +
> +	return false;
> +}
> +
> +static bool is_host_mode_phy(struct tegra_xusb *tegra, int phy_type, int index)
> +{
> +	if (strcmp(tegra->soc->phy_types[phy_type].name, "hsic") == 0)
> +		return true;
> +
> +	if (strcmp(tegra->soc->phy_types[phy_type].name, "usb2") == 0) {
> +		if (is_usb2_otg_phy(tegra, index)) {
> +			return ((index == tegra->otg_usb2_port) &&
> +				 tegra->host_mode);
> +		} else
> +			return true;
> +	}
> +
> +	if (strcmp(tegra->soc->phy_types[phy_type].name, "usb3") == 0) {
> +		if (is_usb3_otg_phy(tegra, index)) {
> +			return ((index == tegra->otg_usb3_port) &&
> +				 tegra->host_mode);
> +		} else
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
>  static int tegra_xusb_get_usb2_port(struct tegra_xusb *tegra,
>  					      struct usb_phy *usbphy)
>  {
> @@ -1336,6 +1422,7 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra)
>  static int tegra_xusb_probe(struct platform_device *pdev)
>  {
>  	struct tegra_xusb *tegra;
> +	struct device_node *np;
>  	struct resource *regs;
>  	struct xhci_hcd *xhci;
>  	unsigned int i, j, k;
> @@ -1383,6 +1470,14 @@ static int tegra_xusb_probe(struct platform_device *pdev)
>  	if (IS_ERR(tegra->padctl))
>  		return PTR_ERR(tegra->padctl);
>  
> +	np = of_parse_phandle(pdev->dev.of_node, "nvidia,xusb-padctl", 0);
> +	if (!np)
> +		return -ENODEV;
> +
> +	tegra->padctl_irq = of_irq_get(np, 0);
> +	if (tegra->padctl_irq < 0)
> +		return tegra->padctl_irq;
> +
>  	tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
>  	if (IS_ERR(tegra->host_clk)) {
>  		err = PTR_ERR(tegra->host_clk);
> @@ -1527,6 +1622,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
>  		goto put_powerdomains;
>  	}
>  
> +	tegra->hcd->skip_phy_initialization = 1;
>  	tegra->hcd->regs = tegra->regs;
>  	tegra->hcd->rsrc_start = regs->start;
>  	tegra->hcd->rsrc_len = resource_size(regs);
> @@ -1609,12 +1705,6 @@ static int tegra_xusb_probe(struct platform_device *pdev)
>  		goto put_usb3;
>  	}
>  
> -	err = tegra_xusb_enable_firmware_messages(tegra);
> -	if (err < 0) {
> -		dev_err(&pdev->dev, "failed to enable messages: %d\n", err);
> -		goto remove_usb3;
> -	}
> -
>  	err = devm_request_threaded_irq(&pdev->dev, tegra->mbox_irq,
>  					tegra_xusb_mbox_irq,
>  					tegra_xusb_mbox_thread, 0,
> @@ -1624,12 +1714,40 @@ static int tegra_xusb_probe(struct platform_device *pdev)
>  		goto remove_usb3;
>  	}
>  
> +	err = devm_request_threaded_irq(&pdev->dev, tegra->padctl_irq,
> +		NULL,
> +		tegra_xusb_padctl_irq,
> +		IRQF_ONESHOT |
> +		IRQF_TRIGGER_HIGH,
> +		dev_name(&pdev->dev), tegra);

The alignment here is off. Also, try to make good use of those 100
columns.

> +	if (err < 0) {
> +		dev_err(&pdev->dev, "failed to request padctl IRQ: %d\n", err);
> +		goto remove_usb3;
> +	}
> +
> +	err = tegra_xusb_enable_firmware_messages(tegra);
> +	if (err < 0) {
> +		dev_err(&pdev->dev, "failed to enable messages: %d\n", err);
> +		goto remove_usb3;
> +	}
> +
>  	err = tegra_xusb_init_usb_phy(tegra);
>  	if (err < 0) {
>  		dev_err(&pdev->dev, "failed to init USB PHY: %d\n", err);
>  		goto remove_usb3;
>  	}
>  
> +	/* Enable wake for both USB 2.0 and USB 3.0 roothubs */
> +	device_init_wakeup(&tegra->hcd->self.root_hub->dev, true);
> +	device_init_wakeup(&xhci->shared_hcd->self.root_hub->dev, true);
> +	device_init_wakeup(tegra->dev, true);
> +
> +	pm_runtime_use_autosuspend(tegra->dev);
> +	pm_runtime_set_autosuspend_delay(tegra->dev, 2000);
> +	pm_runtime_mark_last_busy(tegra->dev);
> +	pm_runtime_set_active(tegra->dev);
> +	pm_runtime_enable(tegra->dev);
> +
>  	return 0;
>  
>  remove_usb3:
> @@ -1665,6 +1783,7 @@ static int tegra_xusb_remove(struct platform_device *pdev)
>  
>  	tegra_xusb_deinit_usb_phy(tegra);
>  
> +	pm_runtime_get_sync(&pdev->dev);
>  	usb_remove_hcd(xhci->shared_hcd);
>  	usb_put_hcd(xhci->shared_hcd);
>  	xhci->shared_hcd = NULL;
> @@ -1674,8 +1793,8 @@ static int tegra_xusb_remove(struct platform_device *pdev)
>  	dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt,
>  			  tegra->fw.phys);
>  
> -	pm_runtime_put_sync(&pdev->dev);
>  	pm_runtime_disable(&pdev->dev);
> +	pm_runtime_put(&pdev->dev);
>  
>  	tegra_xusb_powergate_partitions(tegra);
>  
> @@ -1717,9 +1836,17 @@ static bool xhci_hub_ports_suspended(struct xhci_hub *hub)
>  static int tegra_xusb_check_ports(struct tegra_xusb *tegra)
>  {
>  	struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
> +	struct xhci_hub *rhub =  xhci_get_rhub(xhci->main_hcd);
> +	struct xhci_bus_state *bus_state = &rhub->bus_state;
>  	unsigned long flags;
>  	int err = 0;
>  
> +	if (bus_state->bus_suspended) {
> +		/* xusb_hub_suspend() has just directed one or more USB2 port(s)
> +		 * to U3 state, it takes 3ms to enter U3. */
> +		usleep_range(3000, 4000);
> +	}
> +
>  	spin_lock_irqsave(&xhci->lock, flags);
>  
>  	if (!xhci_hub_ports_suspended(&xhci->usb2_rhub) ||
> @@ -1765,45 +1892,184 @@ static void tegra_xusb_restore_context(struct tegra_xusb *tegra)
>  	}
>  }
>  
> -static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool wakeup)
> +static enum usb_device_speed
> +tegra_xhci_portsc_to_speed(struct tegra_xusb *tegra, u32 portsc)
> +{
> +	if (DEV_LOWSPEED(portsc))
> +		return USB_SPEED_LOW;
> +	else if (DEV_HIGHSPEED(portsc))
> +		return USB_SPEED_HIGH;
> +	else if (DEV_FULLSPEED(portsc))
> +		return USB_SPEED_FULL;
> +	else if (DEV_SUPERSPEED_ANY(portsc))
> +		return USB_SPEED_SUPER;
> +	else
> +		return USB_SPEED_UNKNOWN;
> +}

As in a prior patch you can make this simpler by dropping the elses.

> +
> +static void tegra_xhci_enable_phy_sleepwalk_wake(struct tegra_xusb *tegra)
> +{
> +	struct tegra_xusb_padctl *padctl = tegra->padctl;
> +	struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
> +	enum usb_device_speed speed;
> +	struct phy *phy;
> +	int index, offset;
> +	int i, j, k;

It looks like these can all be unsigned int.

> +	struct xhci_hub *rhub;
> +	u32 portsc;
> +
> +	for (i = 0, k = 0; i < tegra->soc->num_types; i++) {
> +		if (strcmp(tegra->soc->phy_types[i].name, "usb3") == 0)
> +			rhub = &xhci->usb3_rhub;
> +		else
> +			rhub = &xhci->usb2_rhub;
> +
> +		if (strcmp(tegra->soc->phy_types[i].name, "hsic") == 0)
> +			offset = tegra->soc->ports.usb2.count;
> +		else
> +			offset = 0;
> +
> +		for (j = 0; j < tegra->soc->phy_types[i].num; j++) {
> +			phy = tegra->phys[k++];
> +
> +			if (!phy)
> +				continue;
> +
> +			index = j + offset;
> +
> +			if (index >= rhub->num_ports)
> +				continue;
> +
> +			if (!is_host_mode_phy(tegra, i, j))
> +				continue;
> +
> +			portsc = readl(rhub->ports[index]->addr);
> +			speed = tegra_xhci_portsc_to_speed(tegra, portsc);
> +			tegra_xusb_padctl_enable_phy_sleepwalk(padctl, phy,
> +							       speed);
> +			tegra_xusb_padctl_enable_phy_wake(padctl, phy);
> +		}
> +	}
> +}
> +
> +static void tegra_xhci_disable_phy_wake(struct tegra_xusb *tegra)
> +{
> +	struct tegra_xusb_padctl *padctl = tegra->padctl;
> +	int i;

Same here.

> +
> +	for (i = 0; i < tegra->num_phys; i++) {
> +		if (!tegra->phys[i])
> +			continue;
> +
> +		tegra_xusb_padctl_disable_phy_wake(padctl, tegra->phys[i]);
> +	}
> +}
> +
> +static void tegra_xhci_disable_phy_sleepwalk(struct tegra_xusb *tegra)
> +{
> +	struct tegra_xusb_padctl *padctl = tegra->padctl;
> +	int i;

And here.

> +
> +	for (i = 0; i < tegra->num_phys; i++) {
> +		if (!tegra->phys[i])
> +			continue;
> +
> +		tegra_xusb_padctl_disable_phy_sleepwalk(padctl, tegra->phys[i]);
> +	}
> +}
> +
> +static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
>  {
>  	struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
> +	struct device *dev = tegra->dev;
> +	bool wakeup = runtime ? true : device_may_wakeup(dev);
> +	unsigned int i;
>  	int err;
> +	u32 usbcmd;
> +
> +	dev_dbg(dev, "entering ELPG\n");
> +
> +	usbcmd = readl(&xhci->op_regs->command);
> +	usbcmd &= ~CMD_EIE;
> +	writel(usbcmd, &xhci->op_regs->command);
>  
>  	err = tegra_xusb_check_ports(tegra);
>  	if (err < 0) {
>  		dev_err(tegra->dev, "not all ports suspended: %d\n", err);
> -		return err;
> +		goto out;
>  	}
>  
>  	err = xhci_suspend(xhci, wakeup);
>  	if (err < 0) {
>  		dev_err(tegra->dev, "failed to suspend XHCI: %d\n", err);
> -		return err;
> +		goto out;
>  	}
>  
>  	tegra_xusb_save_context(tegra);
> -	tegra_xusb_phy_disable(tegra);
> +
> +	if (wakeup)
> +		tegra_xhci_enable_phy_sleepwalk_wake(tegra);
> +
> +	tegra_xusb_powergate_partitions(tegra);
> +
> +	for (i = 0; i < tegra->num_phys; i++) {
> +		if (!tegra->phys[i])
> +			continue;
> +
> +		phy_power_off(tegra->phys[i]);
> +		if (!wakeup)
> +			phy_exit(tegra->phys[i]);
> +	}
>  	tegra_xusb_clk_disable(tegra);

Use blank lines to separate blocks of code.

>  
> -	return 0;
> +out:
> +	if (!err)
> +		dev_dbg(tegra->dev, "entering ELPG done\n");
> +	else {
> +		usbcmd = readl(&xhci->op_regs->command);
> +		usbcmd |= CMD_EIE;
> +		writel(usbcmd, &xhci->op_regs->command);
> +
> +		dev_dbg(tegra->dev, "entering ELPG failed\n");
> +		pm_runtime_mark_last_busy(tegra->dev);
> +	}
> +
> +	return err;
>  }
>  
> -static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool wakeup)
> +static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool runtime)
>  {
>  	struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
> +	struct device *dev = tegra->dev;
> +	bool wakeup = runtime ? true : device_may_wakeup(dev);
> +	unsigned int i;
> +	u32 usbcmd;
>  	int err;
>  
> +	dev_dbg(dev, "exiting ELPG\n");
> +	pm_runtime_mark_last_busy(tegra->dev);
> +
>  	err = tegra_xusb_clk_enable(tegra);
>  	if (err < 0) {
>  		dev_err(tegra->dev, "failed to enable clocks: %d\n", err);
> -		return err;
> +		goto out;
>  	}
>  
> -	err = tegra_xusb_phy_enable(tegra);
> -	if (err < 0) {
> -		dev_err(tegra->dev, "failed to enable PHYs: %d\n", err);
> -		goto disable_clk;
> +	err = tegra_xusb_unpowergate_partitions(tegra);
> +	if (err)
> +		goto disable_clks;
> +
> +	if (wakeup)
> +		tegra_xhci_disable_phy_wake(tegra);
> +
> +	for (i = 0; i < tegra->num_phys; i++) {
> +		if (!tegra->phys[i])
> +			continue;
> +
> +		if (!wakeup)
> +			phy_init(tegra->phys[i]);
> +
> +		phy_power_on(tegra->phys[i]);
>  	}
>  
>  	tegra_xusb_config(tegra);
> @@ -1821,31 +2087,78 @@ static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool wakeup)
>  		goto disable_phy;
>  	}
>  
> -	err = xhci_resume(xhci, true);
> +	if (wakeup)
> +		tegra_xhci_disable_phy_sleepwalk(tegra);
> +
> +	err = xhci_resume(xhci, 0);
>  	if (err < 0) {
>  		dev_err(tegra->dev, "failed to resume XHCI: %d\n", err);
>  		goto disable_phy;
>  	}
>  
> -	return 0;
> +	usbcmd = readl(&xhci->op_regs->command);
> +	usbcmd |= CMD_EIE;
> +	writel(usbcmd, &xhci->op_regs->command);
> +
> +	goto out;
>  
>  disable_phy:
> -	tegra_xusb_phy_disable(tegra);
> -disable_clk:
> +	for (i = 0; i < tegra->num_phys; i++) {
> +		if (!tegra->phys[i])
> +			continue;
> +
> +		phy_power_off(tegra->phys[i]);
> +		if (!wakeup)
> +			phy_exit(tegra->phys[i]);
> +	}
> +	tegra_xusb_powergate_partitions(tegra);
> +disable_clks:
>  	tegra_xusb_clk_disable(tegra);
> +out:
> +	if (!err)
> +		dev_dbg(dev, "exiting ELPG done\n");
> +	else
> +		dev_dbg(dev, "exiting ELPG failed\n");
> +
>  	return err;
>  }
>  
>  static int tegra_xusb_suspend(struct device *dev)
>  {
>  	struct tegra_xusb *tegra = dev_get_drvdata(dev);
> -	bool wakeup = device_may_wakeup(dev);
>  	int err;
>  
>  	synchronize_irq(tegra->mbox_irq);
> -

I think that blank line actually helped with readability.

Thierry

>  	mutex_lock(&tegra->lock);
> -	err = tegra_xusb_enter_elpg(tegra, wakeup);
> +
> +	if (pm_runtime_suspended(dev)) {
> +		err = tegra_xusb_exit_elpg(tegra, true);
> +		if (err < 0)
> +			goto out;
> +	}
> +
> +	err = tegra_xusb_enter_elpg(tegra, false);
> +	if (err < 0) {
> +		if (pm_runtime_suspended(dev)) {
> +			pm_runtime_disable(dev);
> +			pm_runtime_set_active(dev);
> +			pm_runtime_enable(dev);
> +		}
> +
> +		goto out;
> +	}
> +
> +out:
> +	if (!err) {
> +		tegra->suspended = true;
> +		pm_runtime_disable(dev);
> +
> +		if (device_may_wakeup(dev)) {
> +			if (enable_irq_wake(tegra->padctl_irq))
> +				dev_err(dev, "failed to enable padctl wakes\n");
> +		}
> +	}
> +
>  	mutex_unlock(&tegra->lock);
>  
>  	return err;
> @@ -1854,14 +2167,32 @@ static int tegra_xusb_suspend(struct device *dev)
>  static int tegra_xusb_resume(struct device *dev)
>  {
>  	struct tegra_xusb *tegra = dev_get_drvdata(dev);
> -	bool wakeup = device_may_wakeup(dev);
>  	int err;
>  
>  	mutex_lock(&tegra->lock);
> -	err = tegra_xusb_exit_elpg(tegra, wakeup);
> +
> +	if (!tegra->suspended) {
> +		mutex_unlock(&tegra->lock);
> +		return 0;
> +	}
> +
> +	err = tegra_xusb_exit_elpg(tegra, false);
> +	if (err < 0) {
> +		mutex_unlock(&tegra->lock);
> +		return err;
> +	}
> +
> +	if (device_may_wakeup(dev)) {
> +		if (disable_irq_wake(tegra->padctl_irq))
> +			dev_err(dev, "failed to disable padctl wakes\n");
> +	}
> +	tegra->suspended = false;
>  	mutex_unlock(&tegra->lock);
>  
> -	return err;
> +	pm_runtime_set_active(dev);
> +	pm_runtime_enable(dev);
> +
> +	return 0;
>  }
>  #endif
>  
> -- 
> 2.25.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2020-08-31 12:50 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-31  4:40 [PATCH v2 00/12] Tegra XHCI controller ELPG support JC Kuo
2020-08-31  4:40 ` [PATCH v2 01/12] clk: tegra: Add PLLE HW power sequencer control JC Kuo
2020-08-31  4:40 ` [PATCH v2 02/12] clk: tegra: don't enable PLLE HW sequencer at init JC Kuo
2020-08-31  4:40 ` [PATCH v2 03/12] phy: tegra: xusb: t210: rearrange UPHY init JC Kuo
2020-08-31 11:42   ` Thierry Reding
2020-09-04  9:10     ` JC Kuo
2020-08-31  4:40 ` [PATCH v2 04/12] phy: tegra: xusb: t210: add lane_iddq operations JC Kuo
2020-08-31 11:53   ` Thierry Reding
2020-09-07  2:26     ` JC Kuo
2020-08-31  4:40 ` [PATCH v2 05/12] phy: tegra: xusb: add sleepwalk and suspend/resume JC Kuo
2020-08-31 11:58   ` Thierry Reding
2020-09-07  2:34     ` JC Kuo
2020-08-31  4:40 ` [PATCH v2 06/12] soc/tegra: pmc: provide usb sleepwalk register map JC Kuo
2020-08-31 12:09   ` Thierry Reding
2020-09-07  3:07     ` JC Kuo
2020-08-31  4:40 ` [PATCH v2 07/12] arm64: tegra210: XUSB PADCTL add "nvidia,pmc" prop JC Kuo
2020-08-31  4:40 ` [PATCH v2 08/12] phy: tegra: xusb: t210: support wake and sleepwalk JC Kuo
2020-08-31 12:37   ` Thierry Reding
2020-09-08  1:14     ` JC Kuo
2020-09-01 15:14   ` kernel test robot
2020-09-01 15:14     ` kernel test robot
2020-08-31  4:40 ` [PATCH v2 09/12] phy: tegra: xusb: t186: " JC Kuo
2020-08-31 12:38   ` Thierry Reding
2020-09-01 16:51   ` kernel test robot
2020-09-01 16:51     ` kernel test robot
2020-08-31  4:40 ` [PATCH v2 10/12] arm64: tegra210/tegra186/tegra194: XUSB PADCTL irq JC Kuo
2020-08-31  4:40 ` [PATCH v2 11/12] usb: host: xhci-tegra: unlink power domain devices JC Kuo
2020-08-31 12:42   ` Thierry Reding
2020-09-08  2:19     ` JC Kuo
2020-08-31  4:40 ` [PATCH v2 12/12] xhci: tegra: enable ELPG for runtime/system PM JC Kuo
2020-08-31 12:50   ` Thierry Reding [this message]
2020-09-08  2:29     ` JC Kuo
2020-09-01 20:33   ` Dmitry Osipenko
2020-09-08  2:42     ` JC Kuo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200831125035.GH1689119@ulmo \
    --to=thierry.reding@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=jckuo@nvidia.com \
    --cc=jonathanh@nvidia.com \
    --cc=kishon@ti.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=nkristam@nvidia.com \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.