aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChangming Huang <jerry.huang@nxp.com>2016-11-29 00:45:38 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-12-05 09:13:58 -0500
commit9d4b82706357f2eb23f45309227fc94d11eea255 (patch)
tree6cfe74d0824423d75256a71587bec8d73e24b032
parent22547c4cc4fe20698a6a85a55b8788859134b8e4 (diff)
fsl/usb: Workarourd for USB erratum-A005697
The EHCI specification states the following in the SUSP bit description: In the Suspend state, the port is sensitive to resume detection. Note that the bit status does not change until the port is suspended and that there may be a delay in suspending a port if there is a transaction currently in progress on the USB. However, in NXP USBDR controller, the PORTSCx[SUSP] bit changes immediately when the application sets it and not when the port is actually suspended. So the application must wait for at least 10 milliseconds after a port indicates that it is suspended, to make sure this port has entered suspended state before initiating this port resume using the Force Port Resume bit. This bit is for NXP controller, not EHCI compatible. Signed-off-by: Changming Huang <jerry.huang@nxp.com> Signed-off-by: Ramneek Mehresh <ramneek.mehresh@nxp.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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)
286 if (pdata->has_fsl_erratum_a005275 == 1) 286 if (pdata->has_fsl_erratum_a005275 == 1)
287 ehci->has_fsl_hs_errata = 1; 287 ehci->has_fsl_hs_errata = 1;
288 288
289 if (pdata->has_fsl_erratum_a005697 == 1)
290 ehci->has_fsl_susp_errata = 1;
291
289 if ((pdata->operating_mode == FSL_USB2_DR_HOST) || 292 if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
290 (pdata->operating_mode == FSL_USB2_DR_OTG)) 293 (pdata->operating_mode == FSL_USB2_DR_OTG))
291 if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) 294 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)
310 } 310 }
311 spin_unlock_irq(&ehci->lock); 311 spin_unlock_irq(&ehci->lock);
312 312
313 if (changed && ehci_has_fsl_susp_errata(ehci))
314 /*
315 * Wait for at least 10 millisecondes to ensure the controller
316 * enter the suspend status before initiating a port resume
317 * using the Force Port Resume bit (Not-EHCI compatible).
318 */
319 usleep_range(10000, 20000);
320
313 if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) { 321 if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
314 /* 322 /*
315 * Wait for HCD to enter low-power mode or for the bus 323 * Wait for HCD to enter low-power mode or for the bus
@@ -1200,6 +1208,12 @@ int ehci_hub_control(
1200 wIndex, (temp1 & HOSTPC_PHCD) ? 1208 wIndex, (temp1 & HOSTPC_PHCD) ?
1201 "succeeded" : "failed"); 1209 "succeeded" : "failed");
1202 } 1210 }
1211 if (ehci_has_fsl_susp_errata(ehci)) {
1212 /* 10ms for HCD enter suspend */
1213 spin_unlock_irqrestore(&ehci->lock, flags);
1214 usleep_range(10000, 20000);
1215 spin_lock_irqsave(&ehci->lock, flags);
1216 }
1203 set_bit(wIndex, &ehci->suspended_ports); 1217 set_bit(wIndex, &ehci->suspended_ports);
1204 break; 1218 break;
1205 case USB_PORT_FEAT_POWER: 1219 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 */
219 unsigned no_selective_suspend:1; 219 unsigned no_selective_suspend:1;
220 unsigned has_fsl_port_bug:1; /* FreeScale */ 220 unsigned has_fsl_port_bug:1; /* FreeScale */
221 unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */ 221 unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
222 unsigned has_fsl_susp_errata:1; /* NXP SUSP quirk */
222 unsigned big_endian_mmio:1; 223 unsigned big_endian_mmio:1;
223 unsigned big_endian_desc:1; 224 unsigned big_endian_desc:1;
224 unsigned big_endian_capbase:1; 225 unsigned big_endian_capbase:1;
@@ -710,6 +711,13 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
710#endif 711#endif
711 712
712/* 713/*
714 * Some Freescale/NXP processors have an erratum (USB A-005697)
715 * in which we need to wait for 10ms for bus to enter suspend mode
716 * after setting SUSP bit.
717 */
718#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata)
719
720/*
713 * While most USB host controllers implement their registers in 721 * While most USB host controllers implement their registers in
714 * little-endian format, a minority (celleb companion chip) implement 722 * little-endian format, a minority (celleb companion chip) implement
715 * them in big endian format. 723 * 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)
226 of_property_read_bool(np, "fsl,usb-erratum-a007792"); 226 of_property_read_bool(np, "fsl,usb-erratum-a007792");
227 pdata->has_fsl_erratum_a005275 = 227 pdata->has_fsl_erratum_a005275 =
228 of_property_read_bool(np, "fsl,usb-erratum-a005275"); 228 of_property_read_bool(np, "fsl,usb-erratum-a005275");
229 pdata->has_fsl_erratum_a005697 =
230 of_property_read_bool(np, "fsl,usb_erratum-a005697");
229 231
230 /* 232 /*
231 * Determine whether phy_clk_valid needs to be checked 233 * 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 {
100 unsigned already_suspended:1; 100 unsigned already_suspended:1;
101 unsigned has_fsl_erratum_a007792:1; 101 unsigned has_fsl_erratum_a007792:1;
102 unsigned has_fsl_erratum_a005275:1; 102 unsigned has_fsl_erratum_a005275:1;
103 unsigned has_fsl_erratum_a005697:1;
103 unsigned check_phy_clk_valid:1; 104 unsigned check_phy_clk_valid:1;
104 105
105 /* register save area for suspend/resume */ 106 /* register save area for suspend/resume */