@@ -23,6 +23,7 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/chipidea.h>
+#include <linux/usb/otg.h>
#define CHIPIDEA_EHCI
#include "../host/ehci-hcd.c"
@@ -46,6 +47,76 @@ static int ci_ehci_setup(struct usb_hcd *hcd)
return ret;
}
+static enum usb_device_speed ci_get_device_speed(struct ehci_hcd *ehci,
+ u32 portsc)
+{
+ if (ehci_is_TDI(ehci)) {
+ switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
+ case 0:
+ return USB_SPEED_FULL;
+ case 1:
+ return USB_SPEED_LOW;
+ case 2:
+ return USB_SPEED_HIGH;
+ default:
+ return USB_SPEED_UNKNOWN;
+ }
+ } else {
+ return USB_SPEED_HIGH;
+ }
+}
+
+static int ci_bus_suspend(struct usb_hcd *hcd)
+{
+ int ret;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int port;
+
+ ret = ehci_bus_suspend(hcd);
+ if (ret)
+ return ret;
+
+ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ u32 __iomem *reg = &ehci->regs->port_status[port];
+ u32 portsc = ehci_readl(ehci, reg);
+
+ if (portsc & PORT_CONNECT) {
+ enum usb_device_speed speed;
+ speed = ci_get_device_speed(ehci, portsc);
+ /* notify the USB PHY */
+ if (hcd->phy)
+ usb_phy_notify_suspend(hcd->phy, speed);
+ }
+ }
+
+ return ret;
+}
+
+static int ci_bus_resume(struct usb_hcd *hcd)
+{
+ int ret;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int port;
+
+ ret = ehci_bus_resume(hcd);
+
+ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ u32 __iomem *reg = &ehci->regs->port_status[port];
+ u32 portsc = ehci_readl(ehci, reg);
+
+ if (portsc & PORT_CONNECT) {
+ enum usb_device_speed speed;
+ speed = ci_get_device_speed(ehci, portsc);
+ /* notify the USB PHY */
+ if (hcd->phy)
+ usb_phy_notify_resume(hcd->phy, speed);
+ }
+ }
+
+ return ret;
+}
static const struct hc_driver ci_ehci_hc_driver = {
.description = "ehci_hcd",
@@ -84,8 +155,8 @@ static const struct hc_driver ci_ehci_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
+ .bus_suspend = ci_bus_suspend,
+ .bus_resume = ci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
When there is a device at the port, it needs to notify PHY driver bus's status during bus suspend/resume procedure for some freescale i.mx SoC (i.mx23, i.mx28, i.mx6). Signed-off-by: Peter Chen <peter.chen@freescale.com> --- drivers/usb/chipidea/host.c | 75 +++++++++++++++++++++++++++++++++++++++++- 1 files changed, 73 insertions(+), 2 deletions(-)