These notify will be called during the bus suspend/resume procedure.

The mxs-phy needs to set/clear HW_USBPHY_CTRL.ENHOSTDISCONDETECT
during the connect, disconnect,suspend and resume procedure.
The phy notification should be added according to below rules:

1. Only set HW_USBPHY_CTRL.ENHOSTDISCONDETECT
during high speed host mode.
2. Do not set HW_USBPHY_CTRL.ENHOSTDISCONDETECT
during the reset and speed negotiation period.
3. Do not set HW_USBPHY_CTRL.ENHOSTDISCONDETECT
during host suspend/resume sequence.

Please refer: i.mx23RM, page: 413.
http://www.freescale.com/files/dsp/doc/ref_manual/IMX23RM.pdf

Freescale i.MX SoC, i.mx23, i.mx28 and i.mx6(i.mx6SL does not
need to follow the 3rd rule) need to follow above rules.

Signed-off-by: Peter Chen <peter.c...@freescale.com>
Tested-by: Mike Thompson <mpthomp...@gmail.com>

---
Changes for v2:
- Add Tested-by: Mike Thompson <mpthomp...@gmail.com>

 drivers/usb/otg/mxs-phy.c |   56 +++++++++++++++++++++++++++++++++++---------
 1 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c
index 88db976..41e0543 100644
--- a/drivers/usb/otg/mxs-phy.c
+++ b/drivers/usb/otg/mxs-phy.c
@@ -96,39 +96,69 @@ static void mxs_phy_enhostdiscondetect_delay(struct 
work_struct *ws)
                                mxs_phy->phy.io_priv + HW_USBPHY_CTRL_SET);
 }
 
-static int mxs_phy_on_connect(struct usb_phy *phy, int port)
+static int mxs_phy_on_connect(struct usb_phy *phy,
+               enum usb_device_speed speed)
 {
        struct mxs_phy *mxs_phy = to_mxs_phy(phy);
 
-       dev_dbg(phy->dev, "Connect on port %d\n", port);
-
-       mxs_phy_hw_init(mxs_phy);
+       dev_dbg(phy->dev, "%s speed device has connected\n",
+               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
 
        /*
         * Delay enabling ENHOSTDISCONDETECT so that connection and
         * reset processing can be completed for the root hub.
         */
-       dev_dbg(phy->dev, "Delaying setting ENHOSTDISCONDETECT\n");
-       PREPARE_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work,
+       if (speed == USB_SPEED_HIGH) {
+               PREPARE_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work,
                        mxs_phy_enhostdiscondetect_delay);
-       schedule_delayed_work(&mxs_phy->enhostdiscondetect_work,
+               schedule_delayed_work(&mxs_phy->enhostdiscondetect_work,
                        msecs_to_jiffies(MXY_PHY_ENHOSTDISCONDETECT_DELAY));
+       }
 
        return 0;
 }
 
-static int mxs_phy_on_disconnect(struct usb_phy *phy, int port)
+static int mxs_phy_on_disconnect(struct usb_phy *phy,
+               enum usb_device_speed speed)
 {
-       dev_dbg(phy->dev, "Disconnect on port %d\n", port);
+       dev_dbg(phy->dev, "%s speed device has disconnected\n",
+               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
 
-       /* No need to delay before clearing ENHOSTDISCONDETECT. */
-       dev_dbg(phy->dev, "Clearing ENHOSTDISCONDETECT\n");
-       writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+       if (speed == USB_SPEED_HIGH) {
+               /* No need to delay before clearing ENHOSTDISCONDETECT. */
+               writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+                               phy->io_priv + HW_USBPHY_CTRL_CLR);
+       }
+
+       return 0;
+}
+
+static int mxs_phy_on_suspend(struct usb_phy *phy,
+               enum usb_device_speed speed)
+{
+       dev_dbg(phy->dev, "At suspend, %s speed device on the port\n",
+               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
+
+       if (speed == USB_SPEED_HIGH)
+               writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
                        phy->io_priv + HW_USBPHY_CTRL_CLR);
 
        return 0;
 }
 
+static int mxs_phy_on_resume(struct usb_phy *phy,
+               enum usb_device_speed speed)
+{
+       dev_dbg(phy->dev, "after resume, %s speed device on the port\n",
+               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
+
+       if (speed == USB_SPEED_HIGH)
+               writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+                       phy->io_priv + HW_USBPHY_CTRL_SET);
+
+       return 0;
+}
+
 static int mxs_phy_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -166,6 +196,8 @@ static int mxs_phy_probe(struct platform_device *pdev)
        mxs_phy->phy.shutdown           = mxs_phy_shutdown;
        mxs_phy->phy.notify_connect     = mxs_phy_on_connect;
        mxs_phy->phy.notify_disconnect  = mxs_phy_on_disconnect;
+       mxs_phy->phy.notify_suspend     = mxs_phy_on_suspend;
+       mxs_phy->phy.notify_resume      = mxs_phy_on_resume;
 
        ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier);
 
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to