diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 7aa46d426f31..2494c26e3bc5 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -2,7 +2,7 @@ /* * NVIDIA Tegra XUSB device mode controller * - * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2015, Google Inc. */ @@ -501,6 +501,9 @@ struct tegra_xudc { struct clk_bulk_data *clks; + struct reset_control *dev_rst; + struct reset_control *ss_rst; + bool device_mode; struct work_struct usb_role_sw_work; @@ -555,6 +558,7 @@ struct tegra_xudc_soc { bool port_reset_quirk; bool port_speed_quirk; bool has_ipfs; + bool has_pg_support; }; static inline u32 fpci_readl(struct tegra_xudc *xudc, unsigned int offset) @@ -3646,6 +3650,7 @@ static struct tegra_xudc_soc tegra210_xudc_soc_data = { .port_reset_quirk = true, .port_speed_quirk = false, .has_ipfs = true, + .has_pg_support = true, }; static struct tegra_xudc_soc tegra186_xudc_soc_data = { @@ -3660,6 +3665,7 @@ static struct tegra_xudc_soc tegra186_xudc_soc_data = { .port_reset_quirk = false, .port_speed_quirk = false, .has_ipfs = false, + .has_pg_support = true, }; static struct tegra_xudc_soc tegra194_xudc_soc_data = { @@ -3674,6 +3680,7 @@ static struct tegra_xudc_soc tegra194_xudc_soc_data = { .port_reset_quirk = false, .port_speed_quirk = true, .has_ipfs = false, + .has_pg_support = true, }; static struct tegra_xudc_soc tegra234_xudc_soc_data = { @@ -3687,6 +3694,7 @@ static struct tegra_xudc_soc tegra234_xudc_soc_data = { .pls_quirk = false, .port_reset_quirk = false, .has_ipfs = false, + .has_pg_support = true, }; static const struct of_device_id tegra_xudc_of_match[] = { @@ -3849,9 +3857,25 @@ static int tegra_xudc_probe(struct platform_device *pdev) if (err) goto disable_regulator; - err = tegra_xudc_powerdomain_init(xudc); - if (err) - goto put_powerdomains; + if (xudc->soc->has_pg_support) { + err = tegra_xudc_powerdomain_init(xudc); + if (err) + goto put_powerdomains; + } else { + xudc->dev_rst = devm_reset_control_get(&pdev->dev, "xusb_dev"); + if (IS_ERR(xudc->dev_rst)) { + err = PTR_ERR(xudc->dev_rst); + dev_err(&pdev->dev, "failed to get xusb_dev reset: %d\n", err); + goto disable_regulator; + } + + xudc->ss_rst = devm_reset_control_get_shared(&pdev->dev, "xusb_ss"); + if (IS_ERR(xudc->ss_rst)) { + err = PTR_ERR(xudc->ss_rst); + dev_err(&pdev->dev, "failed to get xusb_ss reset: %d\n", err); + goto disable_regulator; + } + } err = tegra_xudc_phy_init(xudc); if (err) @@ -3948,11 +3972,13 @@ static void tegra_xudc_remove(struct platform_device *pdev) tegra_xusb_padctl_put(xudc->padctl); } -static int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc) +static int __maybe_unused +tegra_xudc_lowpower_enter(struct tegra_xudc *xudc) { unsigned long flags; + int err; - dev_dbg(xudc->dev, "entering ELPG\n"); + dev_dbg(xudc->dev, "entering low power state\n"); spin_lock_irqsave(&xudc->lock, flags); @@ -3967,16 +3993,31 @@ static int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc) regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies); - dev_dbg(xudc->dev, "entering ELPG done\n"); + if (!xudc->soc->has_pg_support) { + err = reset_control_assert(xudc->dev_rst); + if (err) { + dev_err(xudc->dev, "failed to assert xusb_dev reset: %d\n", err); + return err; + } + + err = reset_control_assert(xudc->ss_rst); + if (err) { + dev_err(xudc->dev, "failed to assert xusb_ss reset: %d\n", err); + return err; + } + } + + dev_dbg(xudc->dev, "entering low power state done\n"); return 0; } -static int __maybe_unused tegra_xudc_unpowergate(struct tegra_xudc *xudc) +static int __maybe_unused +tegra_xudc_lowpower_exit(struct tegra_xudc *xudc) { unsigned long flags; int err; - dev_dbg(xudc->dev, "exiting ELPG\n"); + dev_dbg(xudc->dev, "exiting low power state\n"); err = regulator_bulk_enable(xudc->soc->num_supplies, xudc->supplies); @@ -3987,6 +4028,20 @@ static int __maybe_unused tegra_xudc_unpowergate(struct tegra_xudc *xudc) if (err < 0) return err; + if (!xudc->soc->has_pg_support) { + err = reset_control_deassert(xudc->dev_rst); + if (err) { + dev_err(xudc->dev, "failed to deassert xusb_dev reset: %d\n", err); + return err; + } + + err = reset_control_deassert(xudc->ss_rst); + if (err) { + dev_err(xudc->dev, "failed to deassert xusb_ss reset: %d\n", err); + return err; + } + } + tegra_xudc_fpci_ipfs_init(xudc); tegra_xudc_device_params_init(xudc); @@ -4002,7 +4057,7 @@ static int __maybe_unused tegra_xudc_unpowergate(struct tegra_xudc *xudc) xudc->powergated = false; spin_unlock_irqrestore(&xudc->lock, flags); - dev_dbg(xudc->dev, "exiting ELPG done\n"); + dev_dbg(xudc->dev, "exiting low power state done\n"); return 0; } @@ -4020,7 +4075,7 @@ static int __maybe_unused tegra_xudc_suspend(struct device *dev) if (!pm_runtime_status_suspended(dev)) { /* Forcibly disconnect before powergating. */ tegra_xudc_device_mode_off(xudc); - tegra_xudc_powergate(xudc); + tegra_xudc_lowpower_enter(xudc); } pm_runtime_disable(dev); @@ -4034,7 +4089,7 @@ static int __maybe_unused tegra_xudc_resume(struct device *dev) unsigned long flags; int err; - err = tegra_xudc_unpowergate(xudc); + err = tegra_xudc_lowpower_exit(xudc); if (err < 0) return err; @@ -4053,14 +4108,14 @@ static int __maybe_unused tegra_xudc_runtime_suspend(struct device *dev) { struct tegra_xudc *xudc = dev_get_drvdata(dev); - return tegra_xudc_powergate(xudc); + return tegra_xudc_lowpower_enter(xudc); } static int __maybe_unused tegra_xudc_runtime_resume(struct device *dev) { struct tegra_xudc *xudc = dev_get_drvdata(dev); - return tegra_xudc_unpowergate(xudc); + return tegra_xudc_lowpower_exit(xudc); } static const struct dev_pm_ops tegra_xudc_pm_ops = {