[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20210208235606.GA8982@pengutronix.de>
Date: Tue, 9 Feb 2021 00:56:06 +0100
From: Michael Grzeschik <mgr@...gutronix.de>
To: Manish Narani <MNARANI@...inx.com>
Cc: "devicetree@...r.kernel.org" <devicetree@...r.kernel.org>,
"p.zabel@...gutronix.de" <p.zabel@...gutronix.de>,
"balbi@...nel.org" <balbi@...nel.org>,
"gregkh@...uxfoundation.org" <gregkh@...uxfoundation.org>,
"linux-usb@...r.kernel.org" <linux-usb@...r.kernel.org>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
"robh+dt@...nel.org" <robh+dt@...nel.org>,
Michal Simek <michals@...inx.com>, git <git@...inx.com>,
"kernel@...gutronix.de" <kernel@...gutronix.de>,
"linux-arm-kernel@...ts.infradead.org"
<linux-arm-kernel@...ts.infradead.org>
Subject: Re: [RESEND PATCH v3 2/2] usb: dwc3: Add driver for Xilinx platforms
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@...gutronix.de>
>>>>Sent: Friday, January 22, 2021 1:39 PM
>>>>To: Manish Narani <MNARANI@...inx.com>
>>>>Cc: devicetree@...r.kernel.org; kernel@...gutronix.de; balbi@...nel.org;
>>>>gregkh@...uxfoundation.org; linux-usb@...r.kernel.org; Michal Simek
>>>><michals@...inx.com>; linux-kernel@...r.kernel.org; robh+dt@...nel.org;
>>>>git <git@...inx.com>; p.zabel@...gutronix.de; linux-arm-
>>>>kernel@...ts.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@...d0000 {
>> #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@...00000 {
>> 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@...inx.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@...inx.com>
>>>>>>+ * Anurag Kumar Vulisha <anurag.kumar.vulisha@...inx.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@...inx.com>");
>>>>>>+MODULE_AUTHOR("Anurag Kumar Vulisha
>>>><anurag.kumar.vulisha@...inx.com>");
>>>>>>--
>>>>>>2.17.1
>>>>>>
>>>>>>
>>>>>>_______________________________________________
>>>>>>linux-arm-kernel mailing list
>>>>>>linux-arm-kernel@...ts.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@...ts.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@...ts.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@...ts.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@...ts.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 |
Download attachment "signature.asc" of type "application/pgp-signature" (834 bytes)
Powered by blists - more mailing lists