summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamneek Mehresh <ramneek.mehresh@freescale.com>2011-05-04 19:41:55 +0530
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-06 18:19:39 -0700
commitea437f39234f7f991428886f16aae5c264cffe62 (patch)
treece34d093ed810893aa03f61edaf2a24c3aaaf0d7
parent69248d4281fda03dd4da982e1d51f6b22cf1a109 (diff)
fsl/usb: Unused endpoint failure for USB gadget
Though USB controller works without this most of the time, an issue was faced where USB was configured as printer device and it was dropping first packet(64 bytes) in full speed mode due to DATA PID mismatch. The problem gets resolved once unused endpoints are configured as bulk. As per P1020 RM (Table17-31, bits 19-18, bits 3-2) "When only one endpoint (RX or TX, but not both) of an endpoint pair is used, the unused endpoint should be configured as a bulk type endpoint." So according to the RM, this patch is initializing TX and RX endpoints as bulk type Signed-off-by: Suchit Lepcha <Suchit.Lepcha@freescale.com> Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 999eafe89653..2cd9a60c7f3a 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
+ * All rights reserved.
*
* Author: Li Yang <leoli@freescale.com>
* Jiang Bo <tanya.jiang@freescale.com>
@@ -230,7 +231,8 @@ static void nuke(struct fsl_ep *ep, int status)
static int dr_controller_setup(struct fsl_udc *udc)
{
- unsigned int tmp, portctrl;
+ unsigned int tmp, portctrl, ep_num;
+ unsigned int max_no_of_ep;
#ifndef CONFIG_ARCH_MXC
unsigned int ctrl;
#endif
@@ -298,6 +300,14 @@ static int dr_controller_setup(struct fsl_udc *udc)
udc->ep_qh, (int)tmp,
fsl_readl(&dr_regs->endpointlistaddr));
+ max_no_of_ep = (0x0000001F & fsl_readl(&dr_regs->dccparams));
+ for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) {
+ tmp = fsl_readl(&dr_regs->endptctrl[ep_num]);
+ tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE);
+ tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT)
+ | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT);
+ fsl_writel(tmp, &dr_regs->endptctrl[ep_num]);
+ }
/* Config control enable i/o output, cpu endian register */
#ifndef CONFIG_ARCH_MXC
if (udc->pdata->have_sysif_regs) {
@@ -391,12 +401,14 @@ static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
if (ep_num)
tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
tmp_epctrl |= EPCTRL_TX_ENABLE;
+ tmp_epctrl &= ~EPCTRL_TX_TYPE;
tmp_epctrl |= ((unsigned int)(ep_type)
<< EPCTRL_TX_EP_TYPE_SHIFT);
} else {
if (ep_num)
tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
tmp_epctrl |= EPCTRL_RX_ENABLE;
+ tmp_epctrl &= ~EPCTRL_RX_TYPE;
tmp_epctrl |= ((unsigned int)(ep_type)
<< EPCTRL_RX_EP_TYPE_SHIFT);
}
@@ -619,10 +631,13 @@ static int fsl_ep_disable(struct usb_ep *_ep)
/* disable ep on controller */
ep_num = ep_index(ep);
epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
- if (ep_is_in(ep))
- epctrl &= ~EPCTRL_TX_ENABLE;
- else
- epctrl &= ~EPCTRL_RX_ENABLE;
+ if (ep_is_in(ep)) {
+ epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE);
+ epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT;
+ } else {
+ epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE);
+ epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT;
+ }
fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
udc = (struct fsl_udc *)ep->udc;