[RESEND PATCH v3 2/2] usb: dwc3: Add driver for Xilinx platforms

Michael Grzeschik mgr at pengutronix.de
Mon Feb 8 18:56:06 EST 2021


Hi Manish!

On Thu, Jan 28, 2021 at 12:36:07AM +0100, Michael Grzeschik wrote:
>On Fri, Jan 22, 2021 at 02:34:52PM +0100, Michael Grzeschik wrote:
>>On Fri, Jan 22, 2021 at 01:06:22PM +0000, Manish Narani wrote:
>>>Hi Michael,
>>>
>>>>-----Original Message-----
>>>>From: Michael Grzeschik <mgr at pengutronix.de>
>>>>Sent: Friday, January 22, 2021 1:39 PM
>>>>To: Manish Narani <MNARANI at xilinx.com>
>>>>Cc: devicetree at vger.kernel.org; kernel at pengutronix.de; balbi at kernel.org;
>>>>gregkh at linuxfoundation.org; linux-usb at vger.kernel.org; Michal Simek
>>>><michals at xilinx.com>; linux-kernel at vger.kernel.org; robh+dt at kernel.org;
>>>>git <git at xilinx.com>; p.zabel at pengutronix.de; linux-arm-
>>>>kernel at lists.infradead.org
>>>>Subject: Re: [RESEND PATCH v3 2/2] usb: dwc3: Add driver for Xilinx
>>>>platforms
>>>>
>>>>Hello!
>>>>
>>>>On Mon, Jan 18, 2021 at 02:42:24PM +0100, Michael Grzeschik wrote:
>>>>>Hi!
>>>>>
>>>>>On Tue, Dec 15, 2020 at 12:24:51PM +0530, Manish Narani wrote:
>>>>>>Add a new driver for supporting Xilinx platforms. This driver is used
>>>>>>for some sequence of operations required for Xilinx USB controllers.
>>>>>>This driver is also used to choose between PIPE clock coming from SerDes
>>>>>>and the Suspend Clock. Before the controller is out of reset, the clock
>>>>>>selection should be changed to PIPE clock in order to make the USB
>>>>>>controller work. There is a register added in Xilinx USB controller
>>>>>>register space for the same.
>>>>>
>>>>>I tried out this driver with the vanilla kernel on an zynqmp. Without
>>>>>this patch the USB-Gadget is already acting buggy. In the gadget mode,
>>>>>some iterations of plug/unplug results to an stalled gadget which will
>>>>>never come back without a reboot.
>>>>>
>>>>>With the corresponding code of this driver (reset assert, clk modify,
>>>>>reset deassert) in the downstream kernels phy driver we found out it is
>>>>>totaly stable. But using this exact glue driver which should do the same
>>>>>as the downstream code, the gadget still was buggy the way described
>>>>>above.
>>>>>
>>>>>I suspect the difference lays in the different order of operations.
>>>>>While the downstream code is runing the resets inside the phy driver
>>>>>which is powered and initialized in the dwc3-core itself. With this glue
>>>>>layser approach of this patch the whole phy init is done before even
>>>>>touching dwc3-core in any way. It seems not to have the same effect,
>>>>>though.
>>>>>
>>>>>If really the order of operations is limiting us, we probably need
>>>>>another solution than this glue layer. Any Ideas?
>>>>
>>>>I found out what the difference between the Downstream and this
>>>>Glue is. When using vanilla with this Glue code we may not set
>>>>the following bit:
>>>>
>>>>https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-
>>>>ultrascale-registers.html#usb3_regs___fpd_power_prsnt.html
>>>>
>>>>>>+	/* Set PIPE Power Present signal in FPD Power Present Register*/
>>>>>>+	writel(PIPE_POWER_ON, priv_data->regs +
>>>>XLNX_USB_FPD_POWER_PRSNT);
>>>>
>>>>When I comment this out, the link stays stable. This is different in
>>>>the Downstream Xilinx Kernel, where the bit is also set but has no
>>>>negativ effect.
>>>>
>>>>Manish, can you give me a pointer what to look for?
>>>>So setting this will also work with mainline?
>>>I am looking further on this but from what I see here is that,
>>>In order to make USB function properly, there are some dt changes needed in mainline for
>>>USB node which include defining clocks coming from serdes.
>>>The DT changes are pending to be sent to mainline.
>>
>>Can you push that state somewhere, so I could test it?
>>Or is in the downstream kernel some things to copy?
>>
>>>Can you share the DT settings for USB node on your side?
>>
>>Here is my current configuration for the device node at usb0:
>>
>>zynqmp.dtsi
>>
>>zynqmp_reset: reset-controller {
>>	compatible = "xlnx,zynqmp-reset";
>>	#reset-cells = <1>;
>>};
>>
>>usb0: usb at ff9d0000 {
>>	#address-cells = <2>;
>>	#size-cells = <2>;
>>	status = "disabled";
>>	compatible = "xlnx,zynqmp-dwc3";
>>	reg = <0x0 0xff9d0000 0x0 0x100>;
>>	clock-names = "bus_clk", "ref_clk";
>>	power-domains = <&zynqmp_firmware PD_USB_0>;
>>	ranges;
>>	resets = <&zynqmp_reset ZYNQMP_RESET_USB0_CORERESET>,
>>		<&zynqmp_reset ZYNQMP_RESET_USB0_HIBERRESET>,
>>		<&zynqmp_reset ZYNQMP_RESET_USB0_APB>;
>>	reset-names = "usb_crst", "usb_hibrst", "usb_apbrst";
>>	phy-names = "usb3-phy";
>>	phys = <&psgtr 2 PHY_TYPE_USB3 0 2>;
>>
>>	usb0_dwc3: dwc3 at fe200000 {
>>		compatible = "snps,dwc3";
>>		interrupt-parent = <&gic>;
>>		interrupts = <0 65 4>;
>>		clock-names = "ref", "bus_early", "suspend";
>>		reg = <0x0 0xfe200000 0x0 0x40000>;
>>	};
>>};
>>
>>platform.dts
>>
>>&usb0 {
>>	status = "okay";
>>	phy-names = "usb3-phy";
>>	phys = <&psgtr 2 PHY_TYPE_USB3 0 2>;
>>};
>>
>>&usb0_dwc3 {
>>	dr_mode = "peripheral";
>>
>>	/* The following quirks are required, since the bInterval is 1 and we
>>	 * handle steady ISOC streaming. See Usecase 3 in commit 729dcffd1ed3
>>	 * ("usb: dwc3: gadget: Add support for disabling U1 and U2 entries").
>>	 */
>>	snps,dis-u1-entry-quirk;
>>	snps,dis-u2-entry-quirk;
>>};
>>
>>
>>>Meanwhile I will keep updating on the same.
>>
>>Thanks, that sounds great!
>
>I have more feedback regarding this issues. As we saw new uncommon
>effects, when using the glue. Regarding to get the plug/unplug behaviour
>stable, we sticked with leaving out the setting of PIPE_POWER_ON in that
>driver. Unfortunately, with that change, the dwc3 is not only not
>sending any Erratic Errors any more, but also is lacking to send
>disconnect interrupts.
>
>Double checking with downstream shows that disconnects are working
>completely fine in your downstream stack.
>
>I think we should really need to know why PIPE_POWER_ON is making
>a difference before we can say the dwc3 is stable with that glue.

After bisecting your v5.4 and mainline we found out that this all is
working fine, when setting "snps,dis_u3_susphy_quirk" in the zynqmp.dtsi
dwc3 node.

The code handling this quirk was introduced after v5.4, so this was
never an issue with your downstream stack.

"9ba3aca8 usb: dwc3: Disable phy suspend after power-on reset"

We need to know if adding snps,dis_u3_susphy_quirk to the dwc nodes
is generally necessary for zynqmp, so we can fix for everyone.

Ryone.
Michael

>Regards,
>Michael
>
>>>>>>Signed-off-by: Manish Narani <manish.narani at xilinx.com>
>>>>>>---
>>>>>>drivers/usb/dwc3/Kconfig          |   9 +
>>>>>>drivers/usb/dwc3/Makefile         |   1 +
>>>>>>drivers/usb/dwc3/dwc3-of-simple.c |   1 -
>>>>>>drivers/usb/dwc3/dwc3-xilinx.c    | 334
>>>>++++++++++++++++++++++++++++++
>>>>>>4 files changed, 344 insertions(+), 1 deletion(-)
>>>>>>create mode 100644 drivers/usb/dwc3/dwc3-xilinx.c
>>>>>>
>>>>>>diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
>>>>>>index 7a2304565a73..0e00e6dfccd8 100644
>>>>>>--- a/drivers/usb/dwc3/Kconfig
>>>>>>+++ b/drivers/usb/dwc3/Kconfig
>>>>>>@@ -139,4 +139,13 @@ config USB_DWC3_QCOM
>>>>>>	  for peripheral mode support.
>>>>>>	  Say 'Y' or 'M' if you have one such device.
>>>>>>
>>>>>>+config USB_DWC3_XILINX
>>>>>>+	tristate "Xilinx Platforms"
>>>>>>+	depends on (ARCH_ZYNQMP || ARCH_VERSAL) && OF
>>>>>>+	default USB_DWC3
>>>>>>+	help
>>>>>>+	  Support Xilinx SoCs with DesignWare Core USB3 IP.
>>>>>>+	  This driver handles both ZynqMP and Versal SoC operations.
>>>>>>+	  Say 'Y' or 'M' if you have one such device.
>>>>>>+
>>>>>>endif
>>>>>>diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
>>>>>>index ae86da0dc5bd..add567578b1f 100644
>>>>>>--- a/drivers/usb/dwc3/Makefile
>>>>>>+++ b/drivers/usb/dwc3/Makefile
>>>>>>@@ -51,3 +51,4 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A)	+=
>>>>dwc3-meson-g12a.o
>>>>>>obj-$(CONFIG_USB_DWC3_OF_SIMPLE)	+= dwc3-of-simple.o
>>>>>>obj-$(CONFIG_USB_DWC3_ST)		+= dwc3-st.o
>>>>>>obj-$(CONFIG_USB_DWC3_QCOM)		+= dwc3-qcom.o
>>>>>>+obj-$(CONFIG_USB_DWC3_XILINX)		+= dwc3-xilinx.o
>>>>>>diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-
>>>>of-simple.c
>>>>>>index e62ecd22b3ed..71fd620c5161 100644
>>>>>>--- a/drivers/usb/dwc3/dwc3-of-simple.c
>>>>>>+++ b/drivers/usb/dwc3/dwc3-of-simple.c
>>>>>>@@ -172,7 +172,6 @@ static const struct dev_pm_ops
>>>>dwc3_of_simple_dev_pm_ops = {
>>>>>>
>>>>>>static const struct of_device_id of_dwc3_simple_match[] = {
>>>>>>	{ .compatible = "rockchip,rk3399-dwc3" },
>>>>>>-	{ .compatible = "xlnx,zynqmp-dwc3" },
>>>>>>	{ .compatible = "cavium,octeon-7130-usb-uctl" },
>>>>>>	{ .compatible = "sprd,sc9860-dwc3" },
>>>>>>	{ .compatible = "allwinner,sun50i-h6-dwc3" },
>>>>>>diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-
>>>>xilinx.c
>>>>>>new file mode 100644
>>>>>>index 000000000000..7e485951d2f7
>>>>>>--- /dev/null
>>>>>>+++ b/drivers/usb/dwc3/dwc3-xilinx.c
>>>>>>@@ -0,0 +1,334 @@
>>>>>>+// SPDX-License-Identifier: GPL-2.0
>>>>>>+/**
>>>>>>+ * dwc3-xilinx.c - Xilinx DWC3 controller specific glue driver
>>>>>>+ *
>>>>>>+ * Authors: Manish Narani <manish.narani at xilinx.com>
>>>>>>+ *          Anurag Kumar Vulisha <anurag.kumar.vulisha at xilinx.com>
>>>>>>+ */
>>>>>>+
>>>>>>+#include <linux/module.h>
>>>>>>+#include <linux/kernel.h>
>>>>>>+#include <linux/slab.h>
>>>>>>+#include <linux/clk.h>
>>>>>>+#include <linux/of.h>
>>>>>>+#include <linux/platform_device.h>
>>>>>>+#include <linux/dma-mapping.h>
>>>>>>+#include <linux/of_platform.h>
>>>>>>+#include <linux/pm_runtime.h>
>>>>>>+#include <linux/reset.h>
>>>>>>+#include <linux/of_address.h>
>>>>>>+#include <linux/delay.h>
>>>>>>+#include <linux/firmware/xlnx-zynqmp.h>
>>>>>>+#include <linux/io.h>
>>>>>>+
>>>>>>+#include <linux/phy/phy.h>
>>>>>>+
>>>>>>+/* USB phy reset mask register */
>>>>>>+#define XLNX_USB_PHY_RST_EN			0x001C
>>>>>>+#define XLNX_PHY_RST_MASK			0x1
>>>>>>+
>>>>>>+/* Xilinx USB 3.0 IP Register */
>>>>>>+#define XLNX_USB_TRAFFIC_ROUTE_CONFIG		0x005C
>>>>>>+#define XLNX_USB_TRAFFIC_ROUTE_FPD		0x1
>>>>>>+
>>>>>>+/* Versal USB Reset ID */
>>>>>>+#define VERSAL_USB_RESET_ID			0xC104036
>>>>>>+
>>>>>>+#define XLNX_USB_FPD_PIPE_CLK			0x7c
>>>>>>+#define PIPE_CLK_DESELECT			1
>>>>>>+#define PIPE_CLK_SELECT				0
>>>>>>+#define XLNX_USB_FPD_POWER_PRSNT		0x80
>>>>>>+#define PIPE_POWER_ON				1
>>>>>>+#define PIPE_POWER_OFF				0
>>>>>>+
>>>>>>+struct dwc3_xlnx {
>>>>>>+	int				num_clocks;
>>>>>>+	struct clk_bulk_data		*clks;
>>>>>>+	struct device			*dev;
>>>>>>+	void __iomem			*regs;
>>>>>>+	int				(*pltfm_init)(struct dwc3_xlnx *data);
>>>>>>+};
>>>>>>+
>>>>>>+static void dwc3_xlnx_mask_phy_rst(struct dwc3_xlnx *priv_data, bool
>>>>mask)
>>>>>>+{
>>>>>>+	u32 reg;
>>>>>>+
>>>>>>+	/*
>>>>>>+	 * Enable or disable ULPI PHY reset from USB Controller.
>>>>>>+	 * This does not actually reset the phy, but just controls
>>>>>>+	 * whether USB controller can or cannot reset ULPI PHY.
>>>>>>+	 */
>>>>>>+	reg = readl(priv_data->regs + XLNX_USB_PHY_RST_EN);
>>>>>>+
>>>>>>+	if (mask)
>>>>>>+		reg &= ~XLNX_PHY_RST_MASK;
>>>>>>+	else
>>>>>>+		reg |= XLNX_PHY_RST_MASK;
>>>>>>+
>>>>>>+	writel(reg, priv_data->regs + XLNX_USB_PHY_RST_EN);
>>>>>>+}
>>>>>>+
>>>>>>+static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data)
>>>>>>+{
>>>>>>+	struct device		*dev = priv_data->dev;
>>>>>>+	int			ret;
>>>>>>+
>>>>>>+	dwc3_xlnx_mask_phy_rst(priv_data, false);
>>>>>>+
>>>>>>+	/* Assert and De-assert reset */
>>>>>>+	ret = zynqmp_pm_reset_assert(VERSAL_USB_RESET_ID,
>>>>>>+				     PM_RESET_ACTION_ASSERT);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err_probe(dev, ret, "failed to assert Reset\n");
>>>>>>+		return ret;
>>>>>>+	}
>>>>>>+
>>>>>>+	ret = zynqmp_pm_reset_assert(VERSAL_USB_RESET_ID,
>>>>>>+				     PM_RESET_ACTION_RELEASE);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err_probe(dev, ret, "failed to De-assert Reset\n");
>>>>>>+		return ret;
>>>>>>+	}
>>>>>>+
>>>>>>+	dwc3_xlnx_mask_phy_rst(priv_data, true);
>>>>>>+
>>>>>>+	return 0;
>>>>>>+}
>>>>>>+
>>>>>>+static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
>>>>>>+{
>>>>>>+	struct device		*dev = priv_data->dev;
>>>>>>+	struct reset_control	*crst, *hibrst, *apbrst;
>>>>>>+	struct phy		*usb3_phy;
>>>>>>+	int			ret;
>>>>>>+	u32			reg;
>>>>>>+
>>>>>>+	crst = devm_reset_control_get_exclusive(dev, "usb_crst");
>>>>>>+	if (IS_ERR(crst)) {
>>>>>>+		ret = PTR_ERR(crst);
>>>>>>+		dev_err_probe(dev, ret,
>>>>>>+			      "failed to get core reset signal\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	hibrst = devm_reset_control_get_exclusive(dev, "usb_hibrst");
>>>>>>+	if (IS_ERR(hibrst)) {
>>>>>>+		ret = PTR_ERR(hibrst);
>>>>>>+		dev_err_probe(dev, ret,
>>>>>>+			      "failed to get hibernation reset signal\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	apbrst = devm_reset_control_get_exclusive(dev, "usb_apbrst");
>>>>>>+	if (IS_ERR(apbrst)) {
>>>>>>+		ret = PTR_ERR(apbrst);
>>>>>>+		dev_err_probe(dev, ret,
>>>>>>+			      "failed to get APB reset signal\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	ret = reset_control_assert(crst);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err(dev, "Failed to assert core reset\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	ret = reset_control_assert(hibrst);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err(dev, "Failed to assert hibernation reset\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	ret = reset_control_assert(apbrst);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err(dev, "Failed to assert APB reset\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	usb3_phy = devm_phy_get(dev, "usb3-phy");
>>>>>>+
>>>>>>+	ret = phy_init(usb3_phy);
>>>>>>+	if (ret < 0) {
>>>>>>+		phy_exit(usb3_phy);
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	ret = reset_control_deassert(apbrst);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err(dev, "Failed to release APB reset\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	/* Set PIPE Power Present signal in FPD Power Present Register*/
>>>>>>+	writel(PIPE_POWER_ON, priv_data->regs +
>>>>XLNX_USB_FPD_POWER_PRSNT);
>>>>
>>>>This is somehow leading to an unstable link when using vanilla.
>>>>
>>>>>>+
>>>>>>+	/* Set the PIPE Clock Select bit in FPD PIPE Clock register */
>>>>>>+	writel(PIPE_CLK_SELECT, priv_data->regs +
>>>>XLNX_USB_FPD_PIPE_CLK);
>>>>>>+
>>>>>>+	ret = reset_control_deassert(crst);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err(dev, "Failed to release core reset\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	ret = reset_control_deassert(hibrst);
>>>>>>+	if (ret < 0) {
>>>>>>+		dev_err(dev, "Failed to release hibernation reset\n");
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	ret = phy_power_on(usb3_phy);
>>>>>>+	if (ret < 0) {
>>>>>>+		phy_exit(usb3_phy);
>>>>>>+		goto err;
>>>>>>+	}
>>>>>>+
>>>>>>+	/*
>>>>>>+	 * This routes the USB DMA traffic to go through FPD path instead
>>>>>>+	 * of reaching DDR directly. This traffic routing is needed to
>>>>>>+	 * make SMMU and CCI work with USB DMA.
>>>>>>+	 */
>>>>>>+	if (of_dma_is_coherent(dev->of_node) ||
>>>>device_iommu_mapped(dev)) {
>>>>>>+		reg = readl(priv_data->regs +
>>>>XLNX_USB_TRAFFIC_ROUTE_CONFIG);
>>>>>>+		reg |= XLNX_USB_TRAFFIC_ROUTE_FPD;
>>>>>>+		writel(reg, priv_data->regs +
>>>>XLNX_USB_TRAFFIC_ROUTE_CONFIG);
>>>>>>+	}
>>>>>>+
>>>>>>+err:
>>>>>>+	return ret;
>>>>>>+}
>>>>>>+
>>>>>>+static const struct of_device_id dwc3_xlnx_of_match[] = {
>>>>>>+	{
>>>>>>+		.compatible = "xlnx,zynqmp-dwc3",
>>>>>>+		.data = &dwc3_xlnx_init_zynqmp,
>>>>>>+	},
>>>>>>+	{
>>>>>>+		.compatible = "xlnx,versal-dwc3",
>>>>>>+		.data = &dwc3_xlnx_init_versal,
>>>>>>+	},
>>>>>>+	{ /* Sentinel */ }
>>>>>>+};
>>>>>>+MODULE_DEVICE_TABLE(of, dwc3_xlnx_of_match);
>>>>>>+
>>>>>>+static int dwc3_xlnx_probe(struct platform_device *pdev)
>>>>>>+{
>>>>>>+	struct dwc3_xlnx		*priv_data;
>>>>>>+	struct device			*dev = &pdev->dev;
>>>>>>+	struct device_node		*np = dev->of_node;
>>>>>>+	const struct of_device_id	*match;
>>>>>>+	void __iomem			*regs;
>>>>>>+	int				ret;
>>>>>>+
>>>>>>+	priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL);
>>>>>>+	if (!priv_data)
>>>>>>+		return -ENOMEM;
>>>>>>+
>>>>>>+	regs = devm_platform_ioremap_resource(pdev, 0);
>>>>>>+	if (IS_ERR(regs)) {
>>>>>>+		ret = PTR_ERR(regs);
>>>>>>+		dev_err_probe(dev, ret, "failed to map registers\n");
>>>>>>+		return ret;
>>>>>>+	}
>>>>>>+
>>>>>>+	match = of_match_node(dwc3_xlnx_of_match, pdev->dev.of_node);
>>>>>>+
>>>>>>+	priv_data->pltfm_init = match->data;
>>>>>>+	priv_data->regs = regs;
>>>>>>+	priv_data->dev = dev;
>>>>>>+
>>>>>>+	platform_set_drvdata(pdev, priv_data);
>>>>>>+
>>>>>>+	ret = devm_clk_bulk_get_all(priv_data->dev, &priv_data->clks);
>>>>>>+	if (ret < 0)
>>>>>>+		return ret;
>>>>>>+
>>>>>>+	priv_data->num_clocks = ret;
>>>>>>+
>>>>>>+	ret = clk_bulk_prepare_enable(priv_data->num_clocks, priv_data-
>>>>>clks);
>>>>>>+	if (ret)
>>>>>>+		return ret;
>>>>>>+
>>>>>>+	ret = priv_data->pltfm_init(priv_data);
>>>>>>+	if (ret)
>>>>>>+		goto err_clk_put;
>>>>>>+
>>>>>>+	ret = of_platform_populate(np, NULL, NULL, dev);
>>>>>>+	if (ret)
>>>>>>+		goto err_clk_put;
>>>>>>+
>>>>>>+	pm_runtime_set_active(dev);
>>>>>>+	pm_runtime_enable(dev);
>>>>>>+	pm_suspend_ignore_children(dev, false);
>>>>>>+	pm_runtime_get_sync(dev);
>>>>>>+
>>>>>>+	return 0;
>>>>>>+
>>>>>>+err_clk_put:
>>>>>>+	clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data-
>>>>>clks);
>>>>>>+	clk_bulk_put_all(priv_data->num_clocks, priv_data->clks);
>>>>>>+
>>>>>>+	return ret;
>>>>>>+}
>>>>>>+
>>>>>>+static int dwc3_xlnx_remove(struct platform_device *pdev)
>>>>>>+{
>>>>>>+	struct dwc3_xlnx	*priv_data = platform_get_drvdata(pdev);
>>>>>>+	struct device		*dev = &pdev->dev;
>>>>>>+
>>>>>>+	of_platform_depopulate(dev);
>>>>>>+
>>>>>>+	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;
>>>>>>+
>>>>>>+	pm_runtime_disable(dev);
>>>>>>+	pm_runtime_put_noidle(dev);
>>>>>>+	pm_runtime_set_suspended(dev);
>>>>>>+
>>>>>>+	return 0;
>>>>>>+}
>>>>>>+
>>>>>>+static int __maybe_unused dwc3_xlnx_suspend_common(struct device
>>>>*dev)
>>>>>>+{
>>>>>>+	struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
>>>>>>+
>>>>>>+	clk_bulk_disable(priv_data->num_clocks, priv_data->clks);
>>>>>>+
>>>>>>+	return 0;
>>>>>>+}
>>>>>>+
>>>>>>+static int __maybe_unused dwc3_xlnx_resume_common(struct device
>>>>*dev)
>>>>>>+{
>>>>>>+	struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
>>>>>>+
>>>>>>+	return clk_bulk_enable(priv_data->num_clocks, priv_data->clks);
>>>>>>+}
>>>>>>+
>>>>>>+static int __maybe_unused dwc3_xlnx_runtime_idle(struct device *dev)
>>>>>>+{
>>>>>>+	pm_runtime_mark_last_busy(dev);
>>>>>>+	pm_runtime_autosuspend(dev);
>>>>>>+
>>>>>>+	return 0;
>>>>>>+}
>>>>>>+
>>>>>>+static UNIVERSAL_DEV_PM_OPS(dwc3_xlnx_dev_pm_ops,
>>>>dwc3_xlnx_suspend_common,
>>>>>>+			    dwc3_xlnx_resume_common,
>>>>dwc3_xlnx_runtime_idle);
>>>>>>+
>>>>>>+static struct platform_driver dwc3_xlnx_driver = {
>>>>>>+	.probe		= dwc3_xlnx_probe,
>>>>>>+	.remove		= dwc3_xlnx_remove,
>>>>>>+	.driver		= {
>>>>>>+		.name		= "dwc3-xilinx",
>>>>>>+		.of_match_table	= dwc3_xlnx_of_match,
>>>>>>+		.pm		= &dwc3_xlnx_dev_pm_ops,
>>>>>>+	},
>>>>>>+};
>>>>>>+
>>>>>>+module_platform_driver(dwc3_xlnx_driver);
>>>>>>+
>>>>>>+MODULE_LICENSE("GPL v2");
>>>>>>+MODULE_DESCRIPTION("Xilinx DWC3 controller specific glue driver");
>>>>>>+MODULE_AUTHOR("Manish Narani <manish.narani at xilinx.com>");
>>>>>>+MODULE_AUTHOR("Anurag Kumar Vulisha
>>>><anurag.kumar.vulisha at xilinx.com>");
>>>>>>--
>>>>>>2.17.1
>>>>>>
>>>>>>
>>>>>>_______________________________________________
>>>>>>linux-arm-kernel mailing list
>>>>>>linux-arm-kernel at lists.infradead.org
>>>>>>http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>>>
>>>>>--
>>>>>Pengutronix e.K.                           |                             |
>>>>>Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
>>>>>31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
>>>>>Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>>>>
>>>>
>>>>
>>>>>_______________________________________________
>>>>>linux-arm-kernel mailing list
>>>>>linux-arm-kernel at lists.infradead.org
>>>>>http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>>
>>>>
>>>>--
>>>>Pengutronix e.K.                           |                             |
>>>>Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
>>>>31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
>>>>Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>>>
>>>_______________________________________________
>>>linux-arm-kernel mailing list
>>>linux-arm-kernel at lists.infradead.org
>>>http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>
>>
>>-- 
>>Pengutronix e.K.                           |                             |
>>Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
>>31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
>>Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>
>
>
>>_______________________________________________
>>linux-arm-kernel mailing list
>>linux-arm-kernel at lists.infradead.org
>>http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>
>-- 
>Pengutronix e.K.                           |                             |
>Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
>31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
>Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



>_______________________________________________
>linux-arm-kernel mailing list
>linux-arm-kernel at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20210209/384902a6/attachment-0001.sig>


More information about the linux-arm-kernel mailing list