summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ehci-fsl.c3
-rw-r--r--drivers/usb/host/ehci-hub.c14
-rw-r--r--drivers/usb/host/ehci.h8
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c2
-rw-r--r--include/linux/fsl_devices.h1
5 files changed, 28 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 9f5ffb629973..91701cc68082 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -286,6 +286,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if (pdata->has_fsl_erratum_a005275 == 1)
ehci->has_fsl_hs_errata = 1;
+ if (pdata->has_fsl_erratum_a005697 == 1)
+ ehci->has_fsl_susp_errata = 1;
+
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))
if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 74f62d68f013..df169c8e7225 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -310,6 +310,14 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
spin_unlock_irq(&ehci->lock);
+ if (changed && ehci_has_fsl_susp_errata(ehci))
+ /*
+ * Wait for at least 10 millisecondes to ensure the controller
+ * enter the suspend status before initiating a port resume
+ * using the Force Port Resume bit (Not-EHCI compatible).
+ */
+ usleep_range(10000, 20000);
+
if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
/*
* Wait for HCD to enter low-power mode or for the bus
@@ -1200,6 +1208,12 @@ int ehci_hub_control(
wIndex, (temp1 & HOSTPC_PHCD) ?
"succeeded" : "failed");
}
+ if (ehci_has_fsl_susp_errata(ehci)) {
+ /* 10ms for HCD enter suspend */
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ usleep_range(10000, 20000);
+ spin_lock_irqsave(&ehci->lock, flags);
+ }
set_bit(wIndex, &ehci->suspended_ports);
break;
case USB_PORT_FEAT_POWER:
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 3f3b74aeca97..a8e36170d8b8 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -219,6 +219,7 @@ struct ehci_hcd { /* one per controller */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
+ unsigned has_fsl_susp_errata:1; /* NXP SUSP quirk */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
unsigned big_endian_capbase:1;
@@ -710,6 +711,13 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#endif
/*
+ * Some Freescale/NXP processors have an erratum (USB A-005697)
+ * in which we need to wait for 10ms for bus to enter suspend mode
+ * after setting SUSP bit.
+ */
+#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata)
+
+/*
* While most USB host controllers implement their registers in
* little-endian format, a minority (celleb companion chip) implement
* them in big endian format.
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index f07ccb25bc24..e90ddb530765 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -226,6 +226,8 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
of_property_read_bool(np, "fsl,usb-erratum-a007792");
pdata->has_fsl_erratum_a005275 =
of_property_read_bool(np, "fsl,usb-erratum-a005275");
+ pdata->has_fsl_erratum_a005697 =
+ of_property_read_bool(np, "fsl,usb_erratum-a005697");
/*
* Determine whether phy_clk_valid needs to be checked
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index f2912914141a..60cef8227534 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -100,6 +100,7 @@ struct fsl_usb2_platform_data {
unsigned already_suspended:1;
unsigned has_fsl_erratum_a007792:1;
unsigned has_fsl_erratum_a005275:1;
+ unsigned has_fsl_erratum_a005697:1;
unsigned check_phy_clk_valid:1;
/* register save area for suspend/resume */