Skip to content
Permalink
Browse files
usb: dwc3: Added remote wake-up in xilinx glue driver
To support USB remote wake-up in xilinx glue driver, Added disable
regulator interface in core to enter in U3(suspend) state, and
introduced wake-up capability flag to enable the feature. when the
remote wakeup flag is enabled and the controller is in U3 state
(suspended), it requires suspend_clk to be active to detect wake-up
signaling driven on the link.

Added function registration and deregistration functionality for
remote wakeup feature from/to dwc3-host.

Signed-off-by: Piyush Mehta <piyush.mehta@xilinx.com>
State: pending
  • Loading branch information
Piyush Mehta authored and Michal Simek committed Sep 22, 2021
1 parent 4a90973 commit e2af4271df5c22814241e855edd3a23d6fae326b
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 6 deletions.
@@ -1849,6 +1849,18 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
break;
}

/* Put the core into D3 state */
if (dwc->dwc3_pmu) {
int ret;

ret = regulator_disable(dwc->dwc3_pmu);
if (ret) {
dev_err(dwc->dev,
"Failed to disable dwc3_pmu supply\n");
return ret;
}
}

return 0;
}

@@ -29,6 +29,7 @@
#include <linux/ulpi/interface.h>

#include <linux/phy/phy.h>
#include <../drivers/usb/host/xhci.h>

#define DWC3_MSG_MAX 500

@@ -1473,6 +1474,9 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);

typedef void (*dwc3_wakeup_t)(struct device *dev, bool wakeup);
void dwc3_host_wakeup_register(dwc3_wakeup_t func);

#define DWC3_IP_IS(_ip) \
(dwc->ip == _ip##_IP)

@@ -28,6 +28,8 @@

#include <linux/phy/phy.h>

#include "core.h"

/* USB phy reset mask register */
#define XLNX_USB_PHY_RST_EN 0x001C
#define XLNX_PHY_RST_MASK 0x1
@@ -80,6 +82,7 @@ struct dwc3_xlnx {
struct regulator *dwc3_pmu;
struct regulator_dev *dwc3_xlnx_reg_rdev;
enum dwc3_xlnx_core_state pmu_state;
bool wakeup_capable;
struct reset_control *crst;
bool enable_d3_suspend;
enum usb_dr_mode dr_mode;
@@ -159,6 +162,8 @@ static int dwc3_zynqmp_power_req(struct device *dev, bool on)
}

priv_data->pmu_state = D0_STATE;
/* disable D3 entry */
priv_data->enable_d3_suspend = false;
} else {
dev_dbg(priv_data->dev, "Trying to set power state to D3...\n");

@@ -500,6 +505,36 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
return ret;
}

/* xilinx feature support functions */
void dwc3_xilinx_wakeup_capable(struct device *dev, bool wakeup)
{
struct device_node *node = of_node_get(dev->parent->of_node);

/* check for valid parent node */
while (node) {
if (of_device_is_compatible(node, "xlnx,zynqmp-dwc3") ||
of_device_is_compatible(node, "xlnx,versal-dwc3"))
break;

/* get the next parent node */
node = of_get_next_parent(node);
}

if (node) {
struct platform_device *pdev_parent;
struct dwc3_xlnx *priv_data;

pdev_parent = of_find_device_by_node(node);
priv_data = platform_get_drvdata(pdev_parent);

/* Set wakeup capable as true or false */
priv_data->wakeup_capable = wakeup;

/* Allow D3 state if wakeup capable only */
priv_data->enable_d3_suspend = wakeup;
}
}

static const struct of_device_id dwc3_xlnx_of_match[] = {
{
.compatible = "xlnx,zynqmp-dwc3",
@@ -567,6 +602,8 @@ static int dwc3_xlnx_probe(struct platform_device *pdev)
if (ret)
return ret;
#endif
/* Register the dwc3-xilinx wakeup function to dwc3 host */
dwc3_host_wakeup_register(dwc3_xilinx_wakeup_capable);

ret = devm_clk_bulk_get_all(priv_data->dev, &priv_data->clks);
if (ret < 0)
@@ -607,6 +644,8 @@ static int dwc3_xlnx_remove(struct platform_device *pdev)

of_platform_depopulate(dev);

/* Unregister the dwc3-xilinx wakeup function from dwc3 host */
dwc3_host_wakeup_register(NULL);
clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks);
clk_bulk_put_all(priv_data->num_clocks, priv_data->clks);
priv_data->num_clocks = 0;
@@ -646,14 +685,15 @@ static int __maybe_unused dwc3_xlnx_suspend(struct device *dev)
{
struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);

if (!priv_data->wakeup_capable) {
#ifdef CONFIG_PM
if (priv_data->dr_mode == USB_DR_MODE_PERIPHERAL)
/* Put the core into D3 */
dwc3_set_usb_core_power(dev, false);
if (priv_data->dr_mode == USB_DR_MODE_PERIPHERAL)
/* Put the core into D3 */
dwc3_set_usb_core_power(dev, false);
#endif
/* Disable the clocks */
clk_bulk_disable(priv_data->num_clocks, priv_data->clks);

/* Disable the clocks */
clk_bulk_disable(priv_data->num_clocks, priv_data->clks);
}
return 0;
}

@@ -662,6 +702,9 @@ static int __maybe_unused dwc3_xlnx_resume(struct device *dev)
struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
int ret;

if (priv_data->wakeup_capable)
return 0;

#ifdef CONFIG_PM
if (priv_data->dr_mode == USB_DR_MODE_PERIPHERAL)
/* Put the core into D0 */
@@ -13,6 +13,21 @@

#include "core.h"

static dwc3_wakeup_t dwc3_wakeup_fn;

/* dwc3 host wakeup registration */
void dwc3_host_wakeup_register(dwc3_wakeup_t func)
{
dwc3_wakeup_fn = func;
}

/* callback function */
void dwc3_host_wakeup_capable(struct device *dev, bool wakeup)
{
if (dwc3_wakeup_fn)
dwc3_wakeup_fn(dev, wakeup);
}

static int dwc3_host_get_irq(struct dwc3 *dwc)
{
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);

0 comments on commit e2af427

Please sign in to comment.