summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorIan Wisbon <ian.wisbon@timesys.com>2011-02-15 15:53:51 -0500
committerIan Wisbon <ian.wisbon@timesys.com>2011-02-15 15:53:51 -0500
commitdfdbf3f6e2d279f2a46ed95614cb4bf07657394d (patch)
tree2cc05669c5d3e47f7d4b28e31076b6dc6e771f36 /drivers/usb/gadget
parenteffff5718c380983788fe6c380671c18e15ac7c2 (diff)
Digi del-5.6 Complete2.6.31-digi-201102151558
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/amd5536udc.c49
-rw-r--r--drivers/usb/gadget/arcotg_udc.c77
-rw-r--r--drivers/usb/gadget/arcotg_udc.h1
-rw-r--r--drivers/usb/gadget/fsl_updater.c79
-rw-r--r--drivers/usb/gadget/fsl_updater.h1
6 files changed, 134 insertions, 74 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index ce44379bd172..a19d73730470 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -466,7 +466,6 @@ config USB_GOKU
config USB_GADGET_ARC
boolean "Freescale USB Device Controller"
depends on ARCH_MXC || ARCH_STMP3XXX || ARCH_MXS
- depends on !USB_EHCI_ARC_OTG
select USB_GADGET_DUALSPEED
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED if USB_GADGET_FSL_1504 || USB_GADGET_FSL_UTMI
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 77352ccc245e..fb0976643a2f 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1213,7 +1213,12 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
tmp &= AMD_UNMASK_BIT(ep->num);
writel(tmp, &dev->regs->ep_irqmsk);
}
- }
+ } else if (ep->in) {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
} else if (ep->dma) {
@@ -2005,18 +2010,17 @@ __acquires(dev->lock)
{
int tmp;
- /* empty queues and init hardware */
- udc_basic_init(dev);
- for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
- empty_req_queue(&dev->ep[tmp]);
- }
-
if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
- /* init */
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+ empty_req_queue(&dev->ep[tmp]);
+
udc_setup_endpoints(dev);
}
@@ -2478,6 +2482,13 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
}
}
+ } else if (!use_dma && ep->in) {
+ /* disable interrupt */
+ tmp = readl(
+ &dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp,
+ &dev->regs->ep_irqmsk);
}
}
/* clear status bits */
@@ -3285,6 +3296,17 @@ static int udc_pci_probe(
goto finished;
}
+ spin_lock_init(&dev->lock);
+ /* udc csr registers base */
+ dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+ /* dev registers base */
+ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+ /* ep registers base */
+ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+ /* fifo's base */
+ dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
kfree(dev);
@@ -3337,7 +3359,6 @@ static int udc_probe(struct udc *dev)
udc_pollstall_timer.data = 0;
/* device struct setup */
- spin_lock_init(&dev->lock);
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
@@ -3346,16 +3367,6 @@ static int udc_probe(struct udc *dev)
dev->gadget.name = name;
dev->gadget.is_dualspeed = 1;
- /* udc csr registers base */
- dev->csr = dev->virt_addr + UDC_CSR_ADDR;
- /* dev registers base */
- dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
- /* ep registers base */
- dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
- /* fifo's base */
- dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
- dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
-
/* init registers, interrupts, ... */
startup_registers(dev);
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 1577c93c35bb..abba4d2ae8d4 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -177,6 +177,25 @@ static inline void dump_ep_queue(struct fsl_ep *ep)
}
#endif
+#if (defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25)
+/*
+ * The Phy at MX35 and MX25 have bugs, it must disable, and re-eable phy
+ * if the phy clock is disabled before
+ */
+static void reset_phy(void)
+{
+ u32 phyctrl;
+ phyctrl = fsl_readl(&dr_regs->phyctrl1);
+ phyctrl &= ~PHY_CTRL0_USBEN;
+ fsl_writel(phyctrl, &dr_regs->phyctrl1);
+
+ phyctrl = fsl_readl(&dr_regs->phyctrl1);
+ phyctrl |= PHY_CTRL0_USBEN;
+ fsl_writel(phyctrl, &dr_regs->phyctrl1);
+}
+#else
+static void reset_phy(void){; }
+#endif
/*-----------------------------------------------------------------
* done() - retire a request; caller blocked irqs
* @status : request status to be set, only works when
@@ -300,6 +319,8 @@ static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
if (udc_controller->pdata->usb_clock_for_pm)
udc_controller->pdata->usb_clock_for_pm(true);
+ /* Due to mx35/mx25's phy's bug */
+ reset_phy();
temp = fsl_readl(&dr_regs->portsc1);
temp &= ~PORTSCX_PHY_LOW_POWER_SPD;
fsl_writel(temp, &dr_regs->portsc1);
@@ -445,12 +466,14 @@ static void dr_controller_run(struct fsl_udc *udc)
dr_phy_low_power_mode(udc, true);
printk(KERN_INFO "udc enter low power mode \n");
} else {
+#ifdef CONFIG_ARCH_MX37
/*
add some delay for USB timing issue. USB may be
recognize as FS device
during USB gadget remote wake up function
*/
mdelay(100);
+#endif
/* Clear stopped bit */
udc->stopped = 0;
/* Set controller to Run */
@@ -680,7 +703,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
case USB_ENDPOINT_XFER_ISOC:
/* Calculate transactions needed for high bandwidth iso */
mult = (unsigned char)(1 + ((max >> 11) & 0x03));
- max = max & 0x8ff; /* bit 0~10 */
+ max = max & 0x7ff; /* bit 0~10 */
/* 3 transactions at most */
if (mult > 3)
goto en_done;
@@ -2018,29 +2041,12 @@ static void reset_irq(struct fsl_udc *udc)
/* Write 1s to the flush register */
fsl_writel(0xffffffff, &dr_regs->endptflush);
- if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
- VDBG("Bus reset");
- /* Bus is reseting */
- udc->bus_reset = 1;
- /* Reset all the queues, include XD, dTD, EP queue
- * head and TR Queue */
- reset_queues(udc);
- udc->usb_state = USB_STATE_DEFAULT;
- } else {
- VDBG("Controller reset");
- /* initialize usb hw reg except for regs for EP, not
- * touch usbintr reg */
- dr_controller_setup(udc);
-
- /* Reset all internal used Queues */
- reset_queues(udc);
-
- ep0_setup(udc);
-
- /* Enable DR IRQ reg, Set Run bit, change udc state */
- dr_controller_run(udc);
- udc->usb_state = USB_STATE_ATTACHED;
- }
+ /* Bus is reseting */
+ udc->bus_reset = 1;
+ /* Reset all the queues, include XD, dTD, EP queue
+ * head and TR Queue */
+ reset_queues(udc);
+ udc->usb_state = USB_STATE_DEFAULT;
}
/* if wakup udc, return true; else return false*/
@@ -2176,9 +2182,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
int retval = -ENODEV;
unsigned long flags = 0;
-#ifndef CONFIG_USB_OTG
u32 portsc;
-#endif
if (!udc_controller)
return -ENODEV;
@@ -2200,14 +2204,14 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
udc_controller->driver = driver;
udc_controller->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
-#ifndef CONFIG_USB_OTG
+
if (udc_controller->pdata->usb_clock_for_pm)
udc_controller->pdata->usb_clock_for_pm(true);
portsc = fsl_readl(&dr_regs->portsc1);
portsc &= ~PORTSCX_PHY_LOW_POWER_SPD;
fsl_writel(portsc, &dr_regs->portsc1);
-#endif
+
/* bind udc driver to gadget driver */
retval = driver->bind(&udc_controller->gadget);
if (retval) {
@@ -2705,14 +2709,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
int ret = -ENODEV;
unsigned int i;
u32 dccparams;
-#ifndef CONFIG_USB_OTG
- u32 portsc;
-#endif
-
- if (strcmp(pdev->name, driver_name)) {
- VDBG("Wrong device\n");
- return -ENODEV;
- }
udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
if (udc_controller == NULL) {
@@ -2768,6 +2764,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
goto err2a;
}
+ /* Due to mx35/mx25's phy's bug */
+ reset_phy();
+
if (pdata->have_sysif_regs)
usb_sys_regs = (struct usb_sys_interface *)
((u32)dr_regs + USB_DR_SYS_OFFSET);
@@ -2881,10 +2880,14 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
dr_wake_up_enable(udc_controller, false);
udc_controller->stopped = 1;
+#if !(defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25)
+{
+ u32 portsc;
portsc = fsl_readl(&dr_regs->portsc1);
portsc |= PORTSCX_PHY_LOW_POWER_SPD;
fsl_writel(portsc, &dr_regs->portsc1);
-
+}
+#endif
if (udc_controller->pdata->usb_clock_for_pm)
udc_controller->pdata->usb_clock_for_pm(false);
#endif
diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h
index 480d953dcf58..4574954bf4f4 100644
--- a/drivers/usb/gadget/arcotg_udc.h
+++ b/drivers/usb/gadget/arcotg_udc.h
@@ -365,6 +365,7 @@ struct usb_sys_interface {
/* PHY control0 Register Bit Masks */
#define PHY_CTRL0_CONF2 (1 << 26)
+#define PHY_CTRL0_USBEN (1 << 24) /* USB UTMI PHY Enable */
/* USB UH2 CTRL Register Bits */
#define USB_UH2_OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */
diff --git a/drivers/usb/gadget/fsl_updater.c b/drivers/usb/gadget/fsl_updater.c
index 8b4b54f8cca7..50acce441a90 100644
--- a/drivers/usb/gadget/fsl_updater.c
+++ b/drivers/usb/gadget/fsl_updater.c
@@ -29,6 +29,7 @@ static int utp_init(struct fsg_dev *fsg)
INIT_LIST_HEAD(&utp_context.write);
mutex_init(&utp_context.lock);
+ /* the max message is 64KB */
utp_context.buffer = vmalloc(0x10000);
if (!utp_context.buffer)
return -EIO;
@@ -63,6 +64,7 @@ static void utp_user_data_free(struct utp_user_data *uud)
kfree(uud);
}
+/* Get the number of element for list */
static u32 count_list(struct list_head *l)
{
u32 count = 0;
@@ -74,10 +76,11 @@ static u32 count_list(struct list_head *l)
return count;
}
-
+/* The routine will not go on if utp_context.queue is empty */
#define WAIT_ACTIVITY(queue) \
wait_event_interruptible(utp_context.wq, !list_empty(&utp_context.queue))
+/* Called by userspace program (uuc) */
static ssize_t utp_file_read(struct file *file,
char __user *buf,
size_t size,
@@ -109,12 +112,15 @@ static ssize_t utp_file_read(struct file *file,
"need to put %d\n", size, size_to_put);
}
+ /*
+ * The user program has already finished data process,
+ * go on getting data from the host
+ */
wake_up(&utp_context.list_full_wq);
return size_to_put;
}
-
static ssize_t utp_file_write(struct file *file, const char __user *buf,
size_t size, loff_t *off)
{
@@ -127,11 +133,13 @@ static ssize_t utp_file_write(struct file *file, const char __user *buf,
return -EACCES;
mutex_lock(&utp_context.lock);
list_add_tail(&uud->link, &utp_context.write);
+ /* Go on EXEC routine process */
wake_up(&utp_context.wq);
mutex_unlock(&utp_context.lock);
return size;
}
+/* Will be called when the host wants to get the sense data */
static int utp_get_sense(struct fsg_dev *fsg)
{
if (UTP_CTX(fsg)->processed == 0)
@@ -186,6 +194,7 @@ static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size)
/* Perform the read */
pr_info("Copied to %p, %d bytes started from %d\n",
bh->buf, amount, size - amount_left);
+ /* from upt buffer to file_storeage buffer */
memcpy(bh->buf, data + size - amount_left, amount);
amount_left -= amount;
fsg->residue -= amount;
@@ -196,6 +205,7 @@ static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size)
/* Send this buffer and go read some more */
bh->inreq->zero = 0;
+ /* USB Physical transfer: Data from device to host */
start_transfer(fsg, fsg->bulk_in, bh->inreq,
&bh->inreq_busy, &bh->state);
@@ -326,8 +336,8 @@ static void utp_poll(struct fsg_dev *fsg)
if (uud) {
if (uud->data.flags & UTP_FLAG_STATUS) {
- pr_debug("%s: exit with status %d\n", __func__,
- uud->data.status);
+ printk(KERN_WARNING "%s: exit with status %d\n",
+ __func__, uud->data.status);
UTP_SS_EXIT(fsg, uud->data.status);
} else {
pr_debug("%s: pass\n", __func__);
@@ -356,11 +366,16 @@ static int utp_exec(struct fsg_dev *fsg,
mutex_lock(&ctx->lock);
list_add_tail(&uud2r->link, &ctx->read);
mutex_unlock(&ctx->lock);
+ /* wake up the read routine */
wake_up(&ctx->wq);
if (command[0] == '!') /* there will be no response */
return 0;
+ /*
+ * the user program (uuc) will return utp_message
+ * and add list to write list
+ */
WAIT_ACTIVITY(write);
mutex_lock(&ctx->lock);
@@ -382,21 +397,19 @@ static int utp_exec(struct fsg_dev *fsg,
if (uud->data.flags & UTP_FLAG_DATA) {
memcpy(ctx->buffer, uud->data.data, uud->data.bufsize);
UTP_SS_SIZE(fsg, uud->data.bufsize);
- utp_user_data_free(uud);
- return 0;
- }
-
- if (uud->data.flags & UTP_FLAG_REPORT_BUSY) {
- utp_user_data_free(uud);
+ } else if (uud->data.flags & UTP_FLAG_REPORT_BUSY) {
ctx->counter = 0xFFFF;
UTP_SS_BUSY(fsg, ctx->counter);
- return 0;
+ } else if (uud->data.flags & UTP_FLAG_STATUS) {
+ printk(KERN_WARNING "%s: exit with status %d\n", __func__,
+ uud->data.status);
+ UTP_SS_EXIT(fsg, uud->data.status);
+ } else {
+ pr_debug("%s: pass\n", __func__);
+ UTP_SS_PASS(fsg);
}
-
utp_user_data_free(uud);
- UTP_SS_PASS(fsg);
-
- return -1;
+ return 0;
}
static int utp_send_status(struct fsg_dev *fsg)
@@ -470,16 +483,17 @@ static int utp_handle_message(struct fsg_dev *fsg,
case UTP_EXEC:
pr_debug("%s: EXEC\n", __func__);
data = kzalloc(fsg->data_size, GFP_KERNEL);
+ /* copy data from usb buffer to utp buffer */
utp_do_write(fsg, data, fsg->data_size);
utp_exec(fsg, data, fsg->data_size, param);
kfree(data);
break;
- case UTP_GET:
+ case UTP_GET: /* data from device to host */
pr_debug("%s: GET, %d bytes\n", __func__, fsg->data_size);
r = utp_do_read(fsg, UTP_CTX(fsg)->buffer, fsg->data_size);
UTP_SS_PASS(fsg);
break;
- case UTP_PUT:
+ case UTP_PUT: /* data from host to device */
pr_debug("%s: PUT, %d bytes\n", __func__, fsg->data_size);
uud2r = utp_user_data_alloc(fsg->data_size);
uud2r->data.bufsize = fsg->data_size;
@@ -490,6 +504,37 @@ static int utp_handle_message(struct fsg_dev *fsg,
list_add_tail(&uud2r->link, &UTP_CTX(fsg)->read);
mutex_unlock(&UTP_CTX(fsg)->lock);
wake_up(&UTP_CTX(fsg)->wq);
+ /*
+ * Return PASS or FAIL according to uuc's status
+ * Please open it if need to check uuc's status
+ * and use another version uuc
+ */
+#if 0
+ struct utp_user_data *uud = NULL;
+ struct utp_context *ctx;
+ WAIT_ACTIVITY(write);
+ ctx = UTP_CTX(fsg);
+ mutex_lock(&ctx->lock);
+
+ if (!list_empty(&ctx->write))
+ uud = list_first_entry(&ctx->write,
+ struct utp_user_data, link);
+
+ mutex_unlock(&ctx->lock);
+ if (uud) {
+ if (uud->data.flags & UTP_FLAG_STATUS) {
+ printk(KERN_WARNING "%s: exit with status %d\n",
+ __func__, uud->data.status);
+ UTP_SS_EXIT(fsg, uud->data.status);
+ } else {
+ pr_debug("%s: pass\n", __func__);
+ UTP_SS_PASS(fsg);
+ }
+ utp_user_data_free(uud);
+ } else{
+ UTP_SS_PASS(fsg);
+ }
+#endif
UTP_SS_PASS(fsg);
wait_event_interruptible(UTP_CTX(fsg)->list_full_wq,
diff --git a/drivers/usb/gadget/fsl_updater.h b/drivers/usb/gadget/fsl_updater.h
index 44329a9af58a..70e4defa1a9c 100644
--- a/drivers/usb/gadget/fsl_updater.h
+++ b/drivers/usb/gadget/fsl_updater.h
@@ -59,6 +59,7 @@ static int utp_handle_message(struct fsg_dev *fsg,
#define UTP_SS_BUSY(fsg, r) utp_set_sense(fsg, UTP_REPLY_BUSY, (u64)r)
#define UTP_SS_SIZE(fsg, r) utp_set_sense(fsg, UTP_REPLY_SIZE, (u64)r)
+/* the structure of utp message which is mapped to 16-byte SCSI CBW's CDB */
#pragma pack(1)
struct utp_msg {
u8 f0;