All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Add MSM USB Device Controller support
@ 2010-09-01  9:06 Pavankumar Kondeti
  2010-09-01  9:06 ` [PATCH 1/5] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
                   ` (5 more replies)
  0 siblings, 6 replies; 14+ messages in thread
From: Pavankumar Kondeti @ 2010-09-01  9:06 UTC (permalink / raw)
  To: gregkh; +Cc: linux-usb, linux-arm-msm, lockwood, swetland, Pavankumar Kondeti

This patch series adds basic support for USB device controller found in MSM
family of SOCs. This driver is already being used in Android devices.
This driver is tested with Android(ADB + Mass storage, RNDIS), ethernet,
and file storage gadgets.  All the USBCV Ch9 Tests and usbtest test cases
are passed.

This driver is originally authored by Google and is available at
http://android.git.kernel.org/?p=kernel/experimental.git

Pavankumar Kondeti (5):
  USB: Add MSM USB Device Controller driver
  USB: msm72k_udc: Add debugfs support
  USB: msm72k_udc: Add Remote wakeup support
  USB: msm72k_udc: Add Test Mode support
  USB: msm72k_udc: Add charging notification support

 drivers/usb/gadget/Kconfig        |   17 +
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/gadget/msm72k_udc.c   | 1846 +++++++++++++++++++++++++++++++++++++
 include/linux/usb/msm_hsusb.h     |   43 +
 include/linux/usb/msm_hsusb_hw.h  |  227 +++++
 6 files changed, 2142 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/gadget/msm72k_udc.c
 create mode 100644 include/linux/usb/msm_hsusb.h
 create mode 100644 include/linux/usb/msm_hsusb_hw.h


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/5] USB: Add MSM USB Device Controller driver
  2010-09-01  9:06 [PATCH 0/5] Add MSM USB Device Controller support Pavankumar Kondeti
@ 2010-09-01  9:06 ` Pavankumar Kondeti
  2010-09-01 14:03   ` Alan Stern
  2010-09-01 18:29   ` Brian Swetland
  2010-09-01  9:06 ` [PATCH 2/5] USB: msm72k_udc: Add debugfs support Pavankumar Kondeti
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 14+ messages in thread
From: Pavankumar Kondeti @ 2010-09-01  9:06 UTC (permalink / raw)
  To: gregkh
  Cc: linux-usb, linux-arm-msm, lockwood, swetland, Pavankumar Kondeti,
	Brian Swetland

This patch adds the basic support for the USB Device Controller on Qualcomm
MSM family of SOCs.  The controller supports upto 16 endpoints including the
default endpoint (ep0).  All the data transfers are driven by DMA.

VBUS line is also connected to PMIC chip.  The module controlling PMIC chip
notifies about cable connect/disconnect events.  Hence, PHY comparators
are turned off in low power mode.

This driver was originally developed by Google and is available at
http://android.git.kernel.org/?p=kernel/experimental.git.

CC: Mike Lockwood <lockwood@android.com>
CC: Brian Swetland <swetland@google.com>
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
---
 drivers/usb/gadget/Kconfig        |   17 +
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/gadget/msm72k_udc.c   | 1591 +++++++++++++++++++++++++++++++++++++
 include/linux/usb/msm_hsusb.h     |   35 +
 include/linux/usb/msm_hsusb_hw.h  |  213 +++++
 6 files changed, 1865 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/gadget/msm72k_udc.c
 create mode 100644 include/linux/usb/msm_hsusb.h
 create mode 100644 include/linux/usb/msm_hsusb_hw.h

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index cd27f9b..dbb045b 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -505,6 +505,23 @@ config USB_LANGWELL
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
+config USB_GADGET_MSM_72K
+	boolean "MSM 72K Device Controller"
+	depends on ARCH_MSM
+	select USB_GADGET_SELECTED
+	select USB_GADGET_DUALSPEED
+	help
+	   USB gadget driver for Qualcomm MSM 72K architecture.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "msm72k" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_MSM_72K
+	tristate
+	depends on USB_GADGET_MSM_72K
+	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 #
 # LAST -- dummy/emulated controller
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 27283df..7c46b24 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FSL_QE)	+= fsl_qe_udc.o
 obj-$(CONFIG_USB_CI13XXX)	+= ci13xxx_udc.o
 obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o
 obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
+obj-$(CONFIG_USB_MSM_72K)	+= msm72k_udc.o
 
 #
 # USB gadget drivers
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e511fec..a674221 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -142,6 +142,12 @@
 #define gadget_is_s3c_hsotg(g)    0
 #endif
 
+#ifdef CONFIG_USB_GADGET_MSM_72K
+#define	gadget_is_msm72k(g)	(!strcmp("msm72k_udc", (g)->name))
+#else
+#define	gadget_is_msm72k(g)	0
+#endif
+
 
 /**
  * usb_gadget_controller_number - support bcdDevice id convention
@@ -200,6 +206,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x25;
 	else if (gadget_is_s3c_hsotg(gadget))
 		return 0x26;
+	else if (gadget_is_msm72k(gadget))
+		return 0x27;
 	return -ENOENT;
 }
 
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
new file mode 100644
index 0000000..e405dc4
--- /dev/null
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -0,0 +1,1591 @@
+/*
+ * Driver for HighSpeed USB Client Controller in MSM7K
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *         Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/io.h>
+
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/msm_hsusb_hw.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/board.h>
+
+static const char driver_name[] = "msm72k_udc";
+
+/* #define DEBUG */
+/* #define VERBOSE */
+
+#define MSM_USB_BASE ((unsigned) ui->addr)
+
+#define	DRIVER_DESC		"MSM 72K USB Peripheral Controller"
+
+#define EPT_FLAG_IN        0x0001
+
+#define SETUP_BUF_SIZE      8
+
+static const char *const ep_name[] = {
+	"ep0out", "ep1out", "ep2out", "ep3out",
+	"ep4out", "ep5out", "ep6out", "ep7out",
+	"ep8out", "ep9out", "ep10out", "ep11out",
+	"ep12out", "ep13out", "ep14out", "ep15out",
+	"ep0in", "ep1in", "ep2in", "ep3in",
+	"ep4in", "ep5in", "ep6in", "ep7in",
+	"ep8in", "ep9in", "ep10in", "ep11in",
+	"ep12in", "ep13in", "ep14in", "ep15in"
+};
+
+/* current state of VBUS */
+static int vbus;
+
+struct msm_request {
+	struct usb_request req;
+
+	/* saved copy of req.complete */
+	void	(*gadget_complete)(struct usb_ep *ep,
+					struct usb_request *req);
+
+	struct usb_info *ui;
+	struct msm_request *next;
+
+	unsigned busy:1;
+	unsigned live:1;
+	unsigned alloced:1;
+
+	dma_addr_t dma;
+	dma_addr_t item_dma;
+
+	struct ept_queue_item *item;
+};
+
+#define to_msm_request(r) container_of(r, struct msm_request, req)
+#define to_msm_endpoint(r) container_of(r, struct msm_endpoint, ep)
+
+struct msm_endpoint {
+	struct usb_ep ep;
+	struct usb_info *ui;
+	struct msm_request *req; /* head of pending requests */
+	struct msm_request *last;
+	unsigned flags;
+
+	/* bit number (0-31) in various status registers
+	** as well as the index into the usb_info's array
+	** of all endpoints
+	*/
+	unsigned char bit;
+	unsigned char num;
+
+	/* pointers to DMA transfer list area */
+	/* these are allocated from the usb_info dma space */
+	struct ept_queue_head *head;
+};
+
+static void usb_do_work(struct work_struct *w);
+
+#define USB_STATE_IDLE    0
+#define USB_STATE_ONLINE  1
+#define USB_STATE_OFFLINE 2
+
+#define USB_FLAG_START          0x0001
+#define USB_FLAG_VBUS_ONLINE    0x0002
+#define USB_FLAG_VBUS_OFFLINE   0x0004
+
+struct usb_info {
+	/* lock for register/queue/device state changes */
+	spinlock_t lock;
+
+	/* single request used for handling setup transactions */
+	struct usb_request *setup_req;
+
+	struct platform_device *pdev;
+	int irq;
+	void *addr;
+
+	unsigned state;
+	unsigned flags;
+
+	unsigned	online:1;
+	unsigned	running:1;
+
+	struct dma_pool *pool;
+
+	/* dma page to back the queue heads and items */
+	unsigned char *buf;
+	dma_addr_t dma;
+
+	struct ept_queue_head *head;
+
+	/* endpoints are ordered based on their status bits,
+	** so they are OUT0, OUT1, ... OUT15, IN0, IN1, ... IN15
+	*/
+	struct msm_endpoint ept[32];
+
+	int *phy_init_seq;
+	void (*phy_reset)(void);
+	void (*hw_reset)(bool en);
+
+	struct work_struct work;
+
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+
+#define ep0out ept[0]
+#define ep0in  ept[16]
+
+	struct clk *clk;
+	struct clk *pclk;
+
+	unsigned int ep0_dir;
+};
+
+static const struct usb_ep_ops msm72k_ep_ops;
+
+static int msm72k_pullup(struct usb_gadget *_gadget, int is_active);
+static int msm72k_set_halt(struct usb_ep *_ep, int value);
+static void flush_endpoint(struct msm_endpoint *ept);
+
+static int usb_ep_get_stall(struct msm_endpoint *ept)
+{
+	unsigned int n;
+	struct usb_info *ui = ept->ui;
+
+	n = readl(USB_ENDPTCTRL(ept->num));
+	if (ept->flags & EPT_FLAG_IN)
+		return (CTRL_TXS & n) ? 1 : 0;
+	else
+		return (CTRL_RXS & n) ? 1 : 0;
+}
+
+static unsigned ulpi_read(struct usb_info *ui, unsigned reg)
+{
+	unsigned timeout = 100000;
+
+	/* initiate read operation */
+	writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout))
+		;
+
+	if (timeout == 0) {
+		ERROR("ulpi_read: timeout %08x\n", readl(USB_ULPI_VIEWPORT));
+		return 0xffffffff;
+	}
+	return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
+}
+
+static int ulpi_write(struct usb_info *ui, unsigned val, unsigned reg)
+{
+	unsigned timeout = 10000;
+
+	/* initiate write operation */
+	writel(ULPI_RUN | ULPI_WRITE |
+	       ULPI_ADDR(reg) | ULPI_DATA(val),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout))
+		;
+
+	if (timeout == 0) {
+		ERROR("ulpi_write: timeout\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void ulpi_init(struct usb_info *ui)
+{
+	int *seq = ui->phy_init_seq;
+
+	if (!seq)
+		return;
+
+	while (seq[0] >= 0) {
+		VDEBUG("ulpi: write 0x%02x to 0x%02x\n", seq[0], seq[1]);
+		ulpi_write(ui, seq[0], seq[1]);
+		seq += 2;
+	}
+}
+
+static void init_endpoints(struct usb_info *ui)
+{
+	unsigned n;
+
+	for (n = 0; n < 32; n++) {
+		struct msm_endpoint *ept = ui->ept + n;
+
+		ept->ui = ui;
+		ept->bit = n;
+		ept->num = n & 15;
+		ept->ep.name = ep_name[n];
+		ept->ep.ops = &msm72k_ep_ops;
+
+		if (ept->bit > 15) {
+			/* IN endpoint */
+			ept->head = ui->head + (ept->num << 1) + 1;
+			ept->flags = EPT_FLAG_IN;
+		} else {
+			/* OUT endpoint */
+			ept->head = ui->head + (ept->num << 1);
+			ept->flags = 0;
+		}
+
+	}
+}
+
+static void config_ept(struct msm_endpoint *ept)
+{
+	unsigned cfg = CONFIG_MAX_PKT(ept->ep.maxpacket) | CONFIG_ZLT;
+
+	if (ept->bit == 0)
+		/* ep0 out needs interrupt-on-setup */
+		cfg |= CONFIG_IOS;
+
+	ept->head->config = cfg;
+	ept->head->next = TERMINATE;
+
+	if (ept->ep.maxpacket)
+		VDEBUG("ept #%d %s max:%d head:%p bit:%d\n",
+		    ept->num, (ept->flags & EPT_FLAG_IN) ? "in" : "out",
+		    ept->ep.maxpacket, ept->head, ept->bit);
+}
+
+static void configure_endpoints(struct usb_info *ui)
+{
+	unsigned n;
+
+	for (n = 0; n < 32; n++)
+		config_ept(ui->ept + n);
+}
+
+struct usb_request *usb_ept_alloc_req(struct msm_endpoint *ept,
+			unsigned bufsize, gfp_t gfp_flags)
+{
+	struct usb_info *ui = ept->ui;
+	struct msm_request *req;
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		goto fail1;
+
+	req->item = dma_pool_alloc(ui->pool, gfp_flags, &req->item_dma);
+	if (!req->item)
+		goto fail2;
+
+	if (bufsize) {
+		req->req.buf = kmalloc(bufsize, gfp_flags);
+		if (!req->req.buf)
+			goto fail3;
+		req->alloced = 1;
+	}
+
+	return &req->req;
+
+fail3:
+	dma_pool_free(ui->pool, req->item, req->item_dma);
+fail2:
+	kfree(req);
+fail1:
+	return 0;
+}
+
+static void usb_ept_enable(struct msm_endpoint *ept, int yes,
+		unsigned char ep_type)
+{
+	struct usb_info *ui = ept->ui;
+	int in = ept->flags & EPT_FLAG_IN;
+	unsigned n;
+
+	n = readl(USB_ENDPTCTRL(ept->num));
+
+	if (in) {
+		n = (n & (~CTRL_TXT_MASK));
+		if (yes)
+			n |= CTRL_TXE | CTRL_TXR;
+		else
+			n &= (~CTRL_TXE);
+		if (yes) {
+			switch (ep_type) {
+			case USB_ENDPOINT_XFER_BULK:
+				n |= CTRL_TXT_BULK;
+				break;
+			case USB_ENDPOINT_XFER_INT:
+				n |= CTRL_TXT_INT;
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				n |= CTRL_TXT_ISOCH;
+				break;
+			default:
+				ERROR("%s: unsupported ep_type %d for %s\n",
+					__func__, ep_type, ept->ep.name);
+				break;
+			}
+		}
+	} else {
+		n = (n & (~CTRL_RXT_MASK));
+		if (yes)
+			n |= CTRL_RXE | CTRL_RXR;
+		else
+			n &= ~(CTRL_RXE);
+		if (yes) {
+			switch (ep_type) {
+			case USB_ENDPOINT_XFER_BULK:
+				n |= CTRL_RXT_BULK;
+				break;
+			case USB_ENDPOINT_XFER_INT:
+				n |= CTRL_RXT_INT;
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				n |= CTRL_RXT_ISOCH;
+				break;
+			default:
+				ERROR("%s: unsupported ep_type %d for %s\n",
+					__func__, ep_type, ept->ep.name);
+				break;
+			}
+		}
+	}
+	writel(n, USB_ENDPTCTRL(ept->num));
+
+	VDEBUG("ept %d %s %s\n",
+	       ept->num, in ? "in" : "out", yes ? "enabled" : "disabled");
+}
+
+static void usb_ept_start(struct msm_endpoint *ept)
+{
+	struct usb_info *ui = ept->ui;
+	struct msm_request *req = ept->req;
+
+	BUG_ON(req->live);
+
+	/* link the hw queue head to the request's transaction item */
+	ept->head->next = req->item_dma;
+	ept->head->info = 0;
+
+	/* start the endpoint */
+	writel(1 << ept->bit, USB_ENDPTPRIME);
+
+	/* mark this chain of requests as live */
+	while (req) {
+		req->live = 1;
+		req = req->next;
+	}
+}
+
+static int
+usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req)
+{
+	unsigned long flags;
+	struct msm_request *req = to_msm_request(_req);
+	struct msm_request *last;
+	struct usb_info *ui = ept->ui;
+	struct ept_queue_item *item = req->item;
+	unsigned length = req->req.length;
+
+	if (length > 0x4000)
+		return -EMSGSIZE;
+
+	spin_lock_irqsave(&ui->lock, flags);
+
+	if (req->busy) {
+		req->req.status = -EBUSY;
+		spin_unlock_irqrestore(&ui->lock, flags);
+		INFO("usb_ept_queue_xfer() tried to queue busy request\n");
+		return -EBUSY;
+	}
+
+	if (!ui->online && (ept->num != 0)) {
+		req->req.status = -ESHUTDOWN;
+		spin_unlock_irqrestore(&ui->lock, flags);
+		INFO("usb_ept_queue_xfer() called while offline\n");
+		return -ESHUTDOWN;
+	}
+
+	req->busy = 1;
+	req->live = 0;
+	req->next = 0;
+	req->req.status = -EBUSY;
+
+	req->dma = dma_map_single(NULL, req->req.buf, length,
+				  (ept->flags & EPT_FLAG_IN) ?
+				  DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+	/* prepare the transaction descriptor item for the hardware */
+	item->next = TERMINATE;
+	item->info = INFO_BYTES(length) | INFO_IOC | INFO_ACTIVE;
+	item->page0 = req->dma;
+	item->page1 = (req->dma + 0x1000) & 0xfffff000;
+	item->page2 = (req->dma + 0x2000) & 0xfffff000;
+	item->page3 = (req->dma + 0x3000) & 0xfffff000;
+
+	/* Add the new request to the end of the queue */
+	last = ept->last;
+	if (last) {
+		/* Already requests in the queue. add us to the
+		 * end, but let the completion interrupt actually
+		 * start things going, to avoid hw issues
+		 */
+		last->next = req;
+
+		/* only modify the hw transaction next pointer if
+		 * that request is not live
+		 */
+		if (!last->live)
+			last->item->next = req->item_dma;
+	} else {
+		/* queue was empty -- kick the hardware */
+		ept->req = req;
+		usb_ept_start(ept);
+	}
+	ept->last = req;
+
+	spin_unlock_irqrestore(&ui->lock, flags);
+	return 0;
+}
+
+/* --- endpoint 0 handling --- */
+
+static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct msm_request *r = to_msm_request(req);
+	struct msm_endpoint *ept = to_msm_endpoint(ep);
+	struct usb_info *ui = ept->ui;
+
+	req->complete = r->gadget_complete;
+	r->gadget_complete = 0;
+	if	(req->complete)
+		req->complete(&ui->ep0in.ep, req);
+}
+
+static void ep0_queue_ack_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(ep);
+
+	/* queue up the receive of the ACK response from the host */
+	if (req->status == 0) {
+		struct usb_info *ui = ept->ui;
+		req->length = 0;
+		req->complete = ep0_complete;
+		if (ui->ep0_dir == USB_DIR_IN)
+			usb_ept_queue_xfer(&ui->ep0out, req);
+		else
+			usb_ept_queue_xfer(&ui->ep0in, req);
+	} else
+		ep0_complete(ep, req);
+}
+
+static void ep0_setup_ack(struct usb_info *ui)
+{
+	struct usb_request *req = ui->setup_req;
+	req->length = 0;
+	req->complete = 0;
+	usb_ept_queue_xfer(&ui->ep0in, req);
+}
+
+static void ep0_setup_stall(struct usb_info *ui)
+{
+	writel((1<<16) | (1<<0), USB_ENDPTCTRL(0));
+}
+
+static void ep0_setup_send(struct usb_info *ui, unsigned length)
+{
+	struct usb_request *req = ui->setup_req;
+	struct msm_request *r = to_msm_request(req);
+	struct msm_endpoint *ept = &ui->ep0in;
+
+	req->length = length;
+	req->complete = ep0_queue_ack_complete;
+	r->gadget_complete = 0;
+	usb_ept_queue_xfer(ept, req);
+}
+
+static void handle_setup(struct usb_info *ui)
+{
+	struct usb_ctrlrequest ctl;
+	struct usb_request *req = ui->setup_req;
+	int ret;
+
+	memcpy(&ctl, ui->ep0out.head->setup_data, sizeof(ctl));
+	writel(EPT_RX(0), USB_ENDPTSETUPSTAT);
+
+	if (ctl.bRequestType & USB_DIR_IN)
+		ui->ep0_dir = USB_DIR_IN;
+	else
+		ui->ep0_dir = USB_DIR_OUT;
+
+	/* any pending ep0 transactions must be canceled */
+	flush_endpoint(&ui->ep0out);
+	flush_endpoint(&ui->ep0in);
+
+	VDEBUG("setup: type=%02x req=%02x val=%04x idx=%04x len=%04x\n",
+	       ctl.bRequestType, ctl.bRequest, ctl.wValue,
+	       ctl.wIndex, ctl.wLength);
+
+	if ((ctl.bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) ==
+					(USB_DIR_IN | USB_TYPE_STANDARD)) {
+		if (ctl.bRequest == USB_REQ_GET_STATUS) {
+			if (ctl.wLength != 2)
+				goto stall;
+			switch (ctl.bRequestType & USB_RECIP_MASK) {
+			case USB_RECIP_ENDPOINT:
+			{
+				struct msm_endpoint *ept;
+				unsigned num =
+					ctl.wIndex & USB_ENDPOINT_NUMBER_MASK;
+				u16 temp = 0;
+
+				if (num == 0) {
+					memset(req->buf, 0, 2);
+					break;
+				}
+				if (ctl.wIndex & USB_ENDPOINT_DIR_MASK)
+					num += 16;
+				ept = &ui->ep0out + num;
+				temp = usb_ep_get_stall(ept);
+				temp = temp << USB_ENDPOINT_HALT;
+				memcpy(req->buf, &temp, 2);
+				break;
+			}
+			case USB_RECIP_DEVICE:
+			{
+				u16 temp = 0;
+
+				temp = 1 << USB_DEVICE_SELF_POWERED;
+				memcpy(req->buf, &temp, 2);
+				break;
+			}
+			case USB_RECIP_INTERFACE:
+				memset(req->buf, 0, 2);
+				break;
+			default:
+				goto stall;
+			}
+			ep0_setup_send(ui, 2);
+			return;
+		}
+	}
+	if (ctl.bRequestType ==
+		    (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)) {
+		if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) ||
+				(ctl.bRequest == USB_REQ_SET_FEATURE)) {
+			if ((ctl.wValue == 0) && (ctl.wLength == 0)) {
+				unsigned num = ctl.wIndex & 0x0f;
+
+				if (num != 0) {
+					struct msm_endpoint *ept;
+
+					if (ctl.wIndex & 0x80)
+						num += 16;
+					ept = &ui->ep0out + num;
+
+					if (ctl.bRequest == USB_REQ_SET_FEATURE)
+						msm72k_set_halt(&ept->ep, 1);
+					else
+						msm72k_set_halt(&ept->ep, 0);
+				}
+				goto ack;
+			}
+		}
+	}
+	if (ctl.bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD)) {
+		if (ctl.bRequest == USB_REQ_SET_CONFIGURATION) {
+			ui->online = !!ctl.wValue;
+		} else if (ctl.bRequest == USB_REQ_SET_ADDRESS) {
+			/* write address delayed (will take effect
+			** after the next IN txn)
+			*/
+			writel((ctl.wValue << 25) | (1 << 24), USB_DEVICEADDR);
+			goto ack;
+		}
+	}
+
+	/* delegate if we get here */
+	if (ui->driver) {
+		ret = ui->driver->setup(&ui->gadget, &ctl);
+		if (ret >= 0)
+			return;
+	}
+
+stall:
+	/* stall ep0 on error */
+	ep0_setup_stall(ui);
+	return;
+
+ack:
+	ep0_setup_ack(ui);
+}
+
+static void handle_endpoint(struct usb_info *ui, unsigned bit)
+{
+	struct msm_endpoint *ept = ui->ept + bit;
+	struct msm_request *req;
+	unsigned long flags;
+	unsigned info;
+
+	VDEBUG("handle_endpoint() %d %s req=%p(%08x)\n",
+		ept->num, (ept->flags & EPT_FLAG_IN) ? "in" : "out",
+		ept->req, ept->req ? ept->req->item_dma : 0);
+
+	/* expire all requests that are no longer active */
+	spin_lock_irqsave(&ui->lock, flags);
+	while ((req = ept->req)) {
+		info = req->item->info;
+
+		/* if we've processed all live requests, time to
+		 * restart the hardware on the next non-live request
+		 */
+		if (!req->live) {
+			usb_ept_start(ept);
+			break;
+		}
+
+		/* if the transaction is still in-flight, stop here */
+		if (info & INFO_ACTIVE)
+			break;
+
+		/* advance ept queue to the next request */
+		ept->req = req->next;
+		if (ept->req == 0)
+			ept->last = 0;
+
+		dma_unmap_single(NULL, req->dma, req->req.length,
+				 (ept->flags & EPT_FLAG_IN) ?
+				 DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+		if (info & (INFO_HALTED | INFO_BUFFER_ERROR | INFO_TXN_ERROR)) {
+			/* XXX pass on more specific error code */
+			req->req.status = -EIO;
+			req->req.actual = 0;
+			INFO("ept %d %s error. info=%08x\n", ept->num,
+			       (ept->flags & EPT_FLAG_IN) ? "in" : "out",
+			       info);
+		} else {
+			req->req.status = 0;
+			req->req.actual =
+				req->req.length - ((info >> 16) & 0x7FFF);
+		}
+		req->busy = 0;
+		req->live = 0;
+
+		if (req->req.complete) {
+			spin_unlock_irqrestore(&ui->lock, flags);
+			req->req.complete(&ept->ep, &req->req);
+			spin_lock_irqsave(&ui->lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+#define FLUSH_WAIT_US	5
+#define FLUSH_TIMEOUT	(2 * (USEC_PER_SEC / FLUSH_WAIT_US))
+static void flush_endpoint_hw(struct usb_info *ui, unsigned bits)
+{
+	uint32_t unflushed = 0;
+	uint32_t stat = 0;
+	int cnt = 0;
+
+	/* flush endpoint, canceling transactions
+	** - this can take a "large amount of time" (per databook)
+	** - the flush can fail in some cases, thus we check STAT
+	**   and repeat if we're still operating
+	**   (does the fact that this doesn't use the tripwire matter?!)
+	*/
+	while (cnt < FLUSH_TIMEOUT) {
+		writel(bits, USB_ENDPTFLUSH);
+		while (((unflushed = readl(USB_ENDPTFLUSH)) & bits) &&
+		       cnt < FLUSH_TIMEOUT) {
+			cnt++;
+			udelay(FLUSH_WAIT_US);
+		}
+
+		stat = readl(USB_ENDPTSTAT);
+		if (cnt >= FLUSH_TIMEOUT)
+			goto err;
+		if (!(stat & bits))
+			goto done;
+		cnt++;
+		udelay(FLUSH_WAIT_US);
+	}
+
+err:
+	ERROR("%s: Could not complete flush! NOT GOOD! "
+		   "stat: %x unflushed: %x bits: %x\n", __func__,
+		   stat, unflushed, bits);
+done:
+	return;
+}
+
+static void flush_endpoint_sw(struct msm_endpoint *ept)
+{
+	struct usb_info *ui = ept->ui;
+	struct msm_request *req;
+	unsigned long flags;
+
+	/* inactive endpoints have nothing to do here */
+	if (ept->ep.maxpacket == 0)
+		return;
+
+	/* put the queue head in a sane state */
+	ept->head->info = 0;
+	ept->head->next = TERMINATE;
+
+	/* cancel any pending requests */
+	spin_lock_irqsave(&ui->lock, flags);
+	req = ept->req;
+	ept->req = 0;
+	ept->last = 0;
+	while (req != 0) {
+		req->busy = 0;
+		req->live = 0;
+		req->req.status = -ECONNRESET;
+		req->req.actual = 0;
+		if (req->req.complete) {
+			spin_unlock_irqrestore(&ui->lock, flags);
+			req->req.complete(&ept->ep, &req->req);
+			spin_lock_irqsave(&ui->lock, flags);
+		}
+		req = req->next;
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+static void flush_endpoint(struct msm_endpoint *ept)
+{
+	flush_endpoint_hw(ept->ui, (1 << ept->bit));
+	flush_endpoint_sw(ept);
+}
+
+static void flush_all_endpoints(struct usb_info *ui)
+{
+	unsigned n;
+
+	flush_endpoint_hw(ui, 0xffffffff);
+
+	for (n = 0; n < 32; n++)
+		flush_endpoint_sw(ui->ept + n);
+}
+
+static irqreturn_t usb_interrupt(int irq, void *data)
+{
+	struct usb_info *ui = data;
+	unsigned n;
+
+	n = readl(USB_USBSTS);
+	writel(n, USB_USBSTS);
+
+	/* somehow we got an IRQ while in the reset sequence: ignore it */
+	if (ui->running == 0)
+		return IRQ_HANDLED;
+
+	if (n & STS_PCI) {
+		switch (readl(USB_PORTSC) & PORTSC_PSPD_MASK) {
+		case PORTSC_PSPD_FS:
+			INFO("portchange USB_SPEED_FULL\n");
+			ui->gadget.speed = USB_SPEED_FULL;
+			break;
+		case PORTSC_PSPD_LS:
+			INFO("portchange USB_SPEED_LOW\n");
+			ui->gadget.speed = USB_SPEED_LOW;
+			break;
+		case PORTSC_PSPD_HS:
+			INFO("portchange USB_SPEED_HIGH\n");
+			ui->gadget.speed = USB_SPEED_HIGH;
+			break;
+		}
+	}
+
+	if (n & STS_URI) {
+		INFO("reset\n");
+
+		writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+		writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+		writel(0xffffffff, USB_ENDPTFLUSH);
+		writel(0, USB_ENDPTCTRL(1));
+
+		if (ui->online != 0) {
+			/* marking us offline will cause ept queue attempts
+			** to fail
+			*/
+			ui->online = 0;
+
+			flush_all_endpoints(ui);
+
+			/* XXX: we can't seem to detect going offline,
+			 * XXX:  so deconfigure on reset for the time being
+			 */
+			if (ui->driver) {
+				INFO("notify offline\n");
+				ui->driver->disconnect(&ui->gadget);
+			}
+		}
+	}
+
+	if (n & STS_SLI)
+		INFO("suspend\n");
+
+	if (n & STS_UI) {
+		n = readl(USB_ENDPTSETUPSTAT);
+		if (n & EPT_RX(0))
+			handle_setup(ui);
+
+		n = readl(USB_ENDPTCOMPLETE);
+		writel(n, USB_ENDPTCOMPLETE);
+		while (n) {
+			unsigned bit = __ffs(n);
+			handle_endpoint(ui, bit);
+			n = n & (~(1 << bit));
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static void usb_prepare(struct usb_info *ui)
+{
+	memset(ui->buf, 0, 4096);
+	ui->head = (void *) (ui->buf + 0);
+
+	/* only important for reset/reinit */
+	memset(ui->ept, 0, sizeof(ui->ept));
+
+	init_endpoints(ui);
+
+	ui->ep0in.ep.maxpacket = 64;
+	ui->ep0out.ep.maxpacket = 64;
+
+	ui->setup_req =
+		usb_ept_alloc_req(&ui->ep0in, SETUP_BUF_SIZE, GFP_KERNEL);
+
+	INIT_WORK(&ui->work, usb_do_work);
+}
+
+static void usb_suspend_phy(struct usb_info *ui)
+{
+#if defined(CONFIG_ARCH_QSD8X50)
+	/* clear VBusValid and SessionEnd rising interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x0f);
+	/* clear VBusValid and SessionEnd falling interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x12);
+
+	/* Disable 60MHz CLKOUT in serial or carkit mode */
+	ulpi_write(ui, 0x08, 0x09);
+
+	/* Enable PHY Low Power Suspend - Clock Disable (PLPSCD) */
+	writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+	mdelay(1);
+#else
+	/* clear VBusValid and SessionEnd rising interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x0f);
+	/* clear VBusValid and SessionEnd falling interrupts */
+	ulpi_write(ui, (1 << 1) | (1 << 3), 0x12);
+	/* disable interface protect circuit to drop current consumption */
+	ulpi_write(ui, (1 << 7), 0x08);
+	/* clear the SuspendM bit -> suspend the PHY */
+	ulpi_write(ui, 1 << 6, 0x06);
+#endif
+}
+
+/* If this function returns < 0, the phy reset failed and we cannot
+ * continue at this point. The only solution is to wait until the next
+ * cable disconnect/reconnect to bring the phy back */
+static int usb_phy_reset(struct usb_info *ui)
+{
+	u32 val;
+	int ret;
+	int retries;
+
+	if (!ui->phy_reset)
+		return 0;
+
+	if (ui->hw_reset)
+		ui->hw_reset(1);
+	ui->phy_reset();
+	if (ui->hw_reset)
+		ui->hw_reset(0);
+
+#if defined(CONFIG_ARCH_QSD8X50)
+	val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
+	writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+	/* XXX: only necessary for pre-45nm internal PHYs. */
+	for (retries = 3; retries > 0; retries--) {
+		ret = ulpi_write(ui, ULPI_FUNC_SUSPENDM, ULPI_FUNC_CTRL_CLR);
+		if (!ret)
+			break;
+		ui->phy_reset();
+	}
+	if (!retries)
+		return -1;
+
+	/* this reset calibrates the phy, if the above write succeeded */
+	ui->phy_reset();
+
+	/* XXX: pre-45nm internal phys have a known issue which can cause them
+	 * to lockup on reset. If ULPI accesses fail, try resetting the phy
+	 * again */
+	for (retries = 3; retries > 0; retries--) {
+		ret = ulpi_read(ui, ULPI_DEBUG_REG);
+		if (ret != 0xffffffff)
+			break;
+		ui->phy_reset();
+	}
+	if (!retries)
+		return -1;
+#endif
+	INFO("msm_hsusb_phy_reset: success\n");
+	return 0;
+}
+
+static void usb_reset(struct usb_info *ui)
+{
+	unsigned long flags;
+
+	INFO("reset controller\n");
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->running = 0;
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	/* To prevent phantom packets being received by the usb core on
+	 * some devices, put the controller into reset prior to
+	 * resetting the phy. */
+	writel(2, USB_USBCMD);
+	usleep_range(10000, 12000);
+
+	if (usb_phy_reset(ui) < 0)
+		ERROR("%s: Phy reset failed!\n", __func__);
+
+	msleep(100);
+
+	/* toggle non-driving mode after phy reset to ensure that
+	 * we cause a disconnect event to the host */
+	ulpi_write(ui, 0x18, 0x6);
+	usleep_range(1000, 1200);
+	ulpi_write(ui, 0x8, 0x5);
+	usleep_range(1000, 1200);
+
+	/* RESET */
+	writel(2, USB_USBCMD);
+	usleep_range(10000, 12000);
+
+#ifdef CONFIG_ARCH_MSM7X00A
+	/* INCR4 BURST mode */
+	writel(0x01, USB_SBUSCFG);
+#else
+	/* bursts of unspecified length. */
+	writel(0, USB_AHBBURST);
+	/* Use the AHB transactor */
+	writel(0, USB_AHBMODE);
+#endif
+
+	/* select DEVICE mode */
+	writel(0x12, USB_USBMODE);
+	usleep_range(1000, 1200);
+
+	/* select ULPI phy */
+	writel(0x80000000, USB_PORTSC);
+
+	ulpi_init(ui);
+
+	writel(ui->dma, USB_ENDPOINTLISTADDR);
+
+	configure_endpoints(ui);
+
+	/* marking us offline will cause ept queue attempts to fail */
+	ui->online = 0;
+
+	/* terminate any pending transactions */
+	flush_all_endpoints(ui);
+
+	if (ui->driver) {
+		INFO("notify offline\n");
+		ui->driver->disconnect(&ui->gadget);
+	}
+
+	/* enable interrupts */
+	writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR);
+
+	/* go to RUN mode (D+ pullup enable) */
+	msm72k_pullup(&ui->gadget, 1);
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->running = 1;
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+static void usb_start(struct usb_info *ui)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->flags |= USB_FLAG_START;
+	schedule_work(&ui->work);
+	spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+static struct usb_info *the_usb_info;
+
+static int usb_free(struct usb_info *ui, int ret)
+{
+	INFO("usb_free(%d)\n", ret);
+
+	if (ui->irq)
+		free_irq(ui->irq, 0);
+	if (ui->pool)
+		dma_pool_destroy(ui->pool);
+	if (ui->dma)
+		dma_free_coherent(&ui->pdev->dev, 4096, ui->buf, ui->dma);
+	if (ui->addr)
+		iounmap(ui->addr);
+	if (ui->clk)
+		clk_put(ui->clk);
+	if (ui->pclk)
+		clk_put(ui->pclk);
+	kfree(ui);
+	return ret;
+}
+
+static void usb_do_work_check_vbus(struct usb_info *ui)
+{
+	unsigned long iflags;
+
+	spin_lock_irqsave(&ui->lock, iflags);
+	if (vbus)
+		ui->flags |= USB_FLAG_VBUS_ONLINE;
+	else
+		ui->flags |= USB_FLAG_VBUS_OFFLINE;
+	spin_unlock_irqrestore(&ui->lock, iflags);
+}
+
+static void usb_do_work(struct work_struct *w)
+{
+	struct usb_info *ui = container_of(w, struct usb_info, work);
+	unsigned long iflags;
+	unsigned flags, _vbus;
+
+	for (;;) {
+		spin_lock_irqsave(&ui->lock, iflags);
+		flags = ui->flags;
+		ui->flags = 0;
+		_vbus = vbus;
+		spin_unlock_irqrestore(&ui->lock, iflags);
+
+		/* give up if we have nothing to do */
+		if (flags == 0)
+			break;
+
+		switch (ui->state) {
+		case USB_STATE_IDLE:
+			if (flags & USB_FLAG_START) {
+				INFO("IDLE -> ONLINE\n");
+				clk_enable(ui->clk);
+				clk_enable(ui->pclk);
+				usb_reset(ui);
+
+				ui->state = USB_STATE_ONLINE;
+				usb_do_work_check_vbus(ui);
+			}
+			break;
+		case USB_STATE_ONLINE:
+			/* If at any point when we were online, we received
+			 * the signal to go offline, we must honor it
+			 */
+			if (flags & USB_FLAG_VBUS_OFFLINE) {
+				INFO("ONLINE -> OFFLINE\n");
+
+				/* synchronize with irq context */
+				spin_lock_irqsave(&ui->lock, iflags);
+				ui->running = 0;
+				ui->online = 0;
+				msm72k_pullup(&ui->gadget, 0);
+				spin_unlock_irqrestore(&ui->lock, iflags);
+
+				/* terminate any transactions, etc */
+				flush_all_endpoints(ui);
+
+				if (ui->driver) {
+					INFO("notify offline\n");
+					ui->driver->disconnect(&ui->gadget);
+				}
+
+				usb_phy_reset(ui);
+
+				/* power down phy, clock down usb */
+				spin_lock_irqsave(&ui->lock, iflags);
+				usb_suspend_phy(ui);
+				clk_disable(ui->pclk);
+				clk_disable(ui->clk);
+				spin_unlock_irqrestore(&ui->lock, iflags);
+
+				ui->state = USB_STATE_OFFLINE;
+				usb_do_work_check_vbus(ui);
+				break;
+			}
+			break;
+		case USB_STATE_OFFLINE:
+			/* If we were signaled to go online and vbus is still
+			 * present when we received the signal, go online.
+			 */
+			if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
+				INFO("OFFLINE -> ONLINE\n");
+				clk_enable(ui->clk);
+				clk_enable(ui->pclk);
+				usb_reset(ui);
+
+				ui->state = USB_STATE_ONLINE;
+				usb_do_work_check_vbus(ui);
+			}
+			break;
+		}
+	}
+}
+
+/* FIXME - the callers of this function should use a gadget API instead.
+ * This is called from htc_battery.c and board-halibut.c
+ * WARNING - this can get called before this driver is initialized.
+ */
+void msm_hsusb_set_vbus_state(int online)
+{
+	unsigned long flags = 0;
+	struct usb_info *ui = the_usb_info;
+
+	if (ui)
+		spin_lock_irqsave(&ui->lock, flags);
+	if (vbus != online) {
+		vbus = online;
+		if (ui) {
+			if (online)
+				ui->flags |= USB_FLAG_VBUS_ONLINE;
+			else
+				ui->flags |= USB_FLAG_VBUS_OFFLINE;
+			schedule_work(&ui->work);
+		}
+	}
+	if (ui)
+		spin_unlock_irqrestore(&ui->lock, flags);
+}
+
+static int
+msm72k_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+	unsigned char ep_type =
+			desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+	if (ep_type == USB_ENDPOINT_XFER_BULK)
+		_ep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	else
+		_ep->maxpacket = le16_to_cpu(64);
+	config_ept(ept);
+	usb_ept_enable(ept, 1, ep_type);
+	return 0;
+}
+
+static int msm72k_disable(struct usb_ep *_ep)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+
+	usb_ept_enable(ept, 0, 0);
+	return 0;
+}
+
+static struct usb_request *
+msm72k_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	return usb_ept_alloc_req(to_msm_endpoint(_ep), 0, gfp_flags);
+}
+
+static void
+msm72k_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct msm_request *req = to_msm_request(_req);
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+	struct usb_info *ui = ept->ui;
+
+	/* request should not be busy */
+	BUG_ON(req->busy);
+
+	if (req->alloced)
+		kfree(req->req.buf);
+	dma_pool_free(ui->pool, req->item, req->item_dma);
+	kfree(req);
+}
+
+static int
+msm72k_queue(struct usb_ep *_ep, struct usb_request *req, gfp_t gfp_flags)
+{
+	struct msm_endpoint *ep = to_msm_endpoint(_ep);
+	struct usb_info *ui = ep->ui;
+
+	if (ep == &ui->ep0in) {
+		struct msm_request *r = to_msm_request(req);
+		if (!req->length)
+			goto ep_queue_done;
+		else {
+			if (ui->ep0_dir == USB_DIR_OUT) {
+				ep = &ui->ep0out;
+				ep->ep.driver_data = ui->ep0in.ep.driver_data;
+			}
+			/* ep0_queue_ack_complete queue a receive for ACK before
+			** calling req->complete
+			*/
+			r->gadget_complete = req->complete;
+			req->complete = ep0_queue_ack_complete;
+		}
+	}
+ep_queue_done:
+	return usb_ept_queue_xfer(ep, req);
+}
+
+static int msm72k_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct msm_endpoint *ep = to_msm_endpoint(_ep);
+	struct msm_request *req = to_msm_request(_req);
+	struct usb_info *ui = ep->ui;
+
+	struct msm_request *cur, *prev;
+	unsigned long flags;
+
+	if (!_ep || !_req)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	cur = ep->req;
+	prev = NULL;
+
+	while (cur != 0) {
+		if (cur == req) {
+			req->busy = 0;
+			req->live = 0;
+			req->req.status = -ECONNRESET;
+			req->req.actual = 0;
+			if (req->req.complete) {
+				spin_unlock_irqrestore(&ui->lock, flags);
+				req->req.complete(&ep->ep, &req->req);
+				spin_lock_irqsave(&ui->lock, flags);
+			}
+			/* remove from linked list */
+			if (prev)
+				prev->next = cur->next;
+			else
+				ep->req = cur->next;
+			if (ep->last == cur)
+				ep->last = prev;
+			/* break from loop */
+			cur = NULL;
+		} else {
+			prev = cur;
+			cur = cur->next;
+		}
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return 0;
+}
+
+static int
+msm72k_set_halt(struct usb_ep *_ep, int value)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+	struct usb_info *ui = ept->ui;
+	unsigned int in = ept->flags & EPT_FLAG_IN;
+	unsigned int n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	n = readl(USB_ENDPTCTRL(ept->num));
+
+	if (in) {
+		if (value)
+			n |= CTRL_TXS;
+		else {
+			n &= ~CTRL_TXS;
+			n |= CTRL_TXR;
+		}
+	} else {
+		if (value)
+			n |= CTRL_RXS;
+		else {
+			n &= ~CTRL_RXS;
+			n |= CTRL_RXR;
+		}
+	}
+	writel(n, USB_ENDPTCTRL(ept->num));
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return 0;
+}
+
+static void
+msm72k_fifo_flush(struct usb_ep *_ep)
+{
+	flush_endpoint(to_msm_endpoint(_ep));
+}
+
+static const struct usb_ep_ops msm72k_ep_ops = {
+	.enable		= msm72k_enable,
+	.disable	= msm72k_disable,
+
+	.alloc_request	= msm72k_alloc_request,
+	.free_request	= msm72k_free_request,
+
+	.queue		= msm72k_queue,
+	.dequeue	= msm72k_dequeue,
+
+	.set_halt	= msm72k_set_halt,
+	.fifo_flush	= msm72k_fifo_flush,
+};
+
+static int msm72k_get_frame(struct usb_gadget *_gadget)
+{
+	struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+
+	/* frame number is in bits 13:3 */
+	return (readl(USB_FRINDEX) >> 3) & 0x000007FF;
+}
+
+/* VBUS reporting logically comes from a transceiver */
+static int msm72k_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	msm_hsusb_set_vbus_state(is_active);
+	return 0;
+}
+
+/* drivers may have software control over D+ pullup */
+static int msm72k_pullup(struct usb_gadget *_gadget, int is_active)
+{
+	struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+
+	u32 cmd = (8 << 16);
+
+	/* disable/enable D+ pullup */
+	if (is_active) {
+		INFO("enable pullup\n");
+		writel(cmd | 1, USB_USBCMD);
+	} else {
+		INFO("disable pullup\n");
+		writel(cmd, USB_USBCMD);
+
+#if defined(CONFIG_ARCH_QSD8X50)
+		ulpi_write(ui, 0x48, 0x04);
+#endif
+	}
+
+	return 0;
+}
+
+static const struct usb_gadget_ops msm72k_ops = {
+	.get_frame	= msm72k_get_frame,
+	.vbus_session	= msm72k_udc_vbus_session,
+	.pullup		= msm72k_pullup,
+};
+
+static int msm72k_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct usb_info *ui;
+	int irq;
+	int ret;
+
+	INFO("msm72k_probe\n");
+	ui = kzalloc(sizeof(struct usb_info), GFP_KERNEL);
+	if (!ui)
+		return -ENOMEM;
+
+	spin_lock_init(&ui->lock);
+	ui->pdev = pdev;
+
+	if (pdev->dev.platform_data) {
+		struct msm_hsusb_platform_data *pdata = pdev->dev.platform_data;
+		ui->phy_reset = pdata->phy_reset;
+		ui->phy_init_seq = pdata->phy_init_seq;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res || (irq < 0))
+		return usb_free(ui, -ENODEV);
+
+	ui->addr = ioremap(res->start, 4096);
+	if (!ui->addr)
+		return usb_free(ui, -ENOMEM);
+
+	ui->buf = dma_alloc_coherent(&pdev->dev, 4096, &ui->dma, GFP_KERNEL);
+	if (!ui->buf)
+		return usb_free(ui, -ENOMEM);
+
+	ui->pool = dma_pool_create("msm72k_udc", NULL, 32, 32, 0);
+	if (!ui->pool)
+		return usb_free(ui, -ENOMEM);
+
+	INFO("msm72k_probe() io=%p, irq=%d, dma=%p(%x)\n",
+	       ui->addr, irq, ui->buf, ui->dma);
+
+	ui->clk = clk_get(&pdev->dev, "usb_hs_clk");
+	if (IS_ERR(ui->clk))
+		return usb_free(ui, PTR_ERR(ui->clk));
+
+	ui->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
+	if (IS_ERR(ui->pclk))
+		return usb_free(ui, PTR_ERR(ui->pclk));
+
+	/* clear interrupts before requesting irq */
+	clk_enable(ui->clk);
+	clk_enable(ui->pclk);
+	writel(0, USB_USBINTR);
+	writel(0, USB_OTGSC);
+	clk_disable(ui->pclk);
+	clk_disable(ui->clk);
+
+	ret = request_irq(irq, usb_interrupt, 0, pdev->name, ui);
+	if (ret)
+		return usb_free(ui, ret);
+	enable_irq_wake(irq);
+	ui->irq = irq;
+
+	ui->gadget.ops = &msm72k_ops;
+	ui->gadget.is_dualspeed = 1;
+	device_initialize(&ui->gadget.dev);
+	dev_set_name(&ui->gadget.dev, "gadget");
+	ui->gadget.dev.parent = &pdev->dev;
+	ui->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	the_usb_info = ui;
+
+	usb_prepare(ui);
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_info *ui = the_usb_info;
+	int			retval, n;
+
+	if (!driver
+			|| driver->speed < USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->disconnect
+			|| !driver->setup)
+		return -EINVAL;
+	if (!ui)
+		return -ENODEV;
+	if (ui->driver)
+		return -EBUSY;
+
+	/* first hook up the driver ... */
+	ui->driver = driver;
+	ui->gadget.dev.driver = &driver->driver;
+	ui->gadget.name = driver_name;
+	INIT_LIST_HEAD(&ui->gadget.ep_list);
+	ui->gadget.ep0 = &ui->ep0in.ep;
+	INIT_LIST_HEAD(&ui->gadget.ep0->ep_list);
+	ui->gadget.speed = USB_SPEED_UNKNOWN;
+
+	for (n = 1; n < 16; n++) {
+		struct msm_endpoint *ept = ui->ept + n;
+		list_add_tail(&ept->ep.ep_list, &ui->gadget.ep_list);
+		ept->ep.maxpacket = 512;
+	}
+	for (n = 17; n < 32; n++) {
+		struct msm_endpoint *ept = ui->ept + n;
+		list_add_tail(&ept->ep.ep_list, &ui->gadget.ep_list);
+		ept->ep.maxpacket = 512;
+	}
+
+	retval = device_add(&ui->gadget.dev);
+	if (retval)
+		goto fail;
+
+	retval = driver->bind(&ui->gadget);
+	if (retval) {
+		INFO("bind to driver %s --> error %d\n",
+				driver->driver.name, retval);
+		device_del(&ui->gadget.dev);
+		goto fail;
+	}
+
+	INFO("registered gadget driver '%s'\n", driver->driver.name);
+
+	usb_start(ui);
+
+	return 0;
+
+fail:
+	ui->driver = NULL;
+	ui->gadget.dev.driver = NULL;
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_info *dev = the_usb_info;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver || !driver->unbind)
+		return -EINVAL;
+
+	driver->unbind(&dev->gadget);
+	dev->gadget.dev.driver = NULL;
+	dev->driver = NULL;
+
+	device_del(&dev->gadget.dev);
+
+	VDEBUG("unregistered gadget driver '%s'\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static struct platform_driver usb_driver = {
+	.probe = msm72k_probe,
+	.driver = { .name = "msm_hsusb", },
+};
+
+static int __init msm72k_udc_init(void)
+{
+	return platform_driver_register(&usb_driver);
+}
+module_init(msm72k_udc_init);
+
+static void __exit msm72k_udc_cleanup(void)
+{
+	platform_driver_unregister(&usb_driver);
+}
+module_exit(msm72k_udc_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Mike Lockwood, Brian Swetland");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
new file mode 100644
index 0000000..534db4e
--- /dev/null
+++ b/include/linux/usb/msm_hsusb.h
@@ -0,0 +1,35 @@
+/* linux/include/asm-arm/arch-msm/hsusb.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_HSUSB_H
+#define __ASM_ARCH_MSM_HSUSB_H
+
+#include <linux/types.h>
+
+/* platform device data for msm_hsusb driver */
+
+struct msm_hsusb_platform_data {
+	/* hard reset the ULPI PHY */
+	void (*phy_reset)(void);
+
+	/* (de)assert the reset to the usb core */
+	void (*hw_reset)(bool enable);
+
+	/* val, reg pairs terminated by -1 */
+	int *phy_init_seq;
+};
+
+#endif
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
new file mode 100644
index 0000000..ab28be6
--- /dev/null
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__
+#define __LINUX_USB_GADGET_MSM72K_UDC_H__
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(level, fmt, args...) \
+	printk(level "%s: " fmt , driver_name , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(fmt, args...) \
+	xprintk(KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(fmt, args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG DEBUG
+#else
+#define VDEBUG(fmt, args...) \
+	do { } while (0)
+#endif	/* VERBOSE */
+
+#define ERROR(fmt, args...) \
+	xprintk(KERN_ERR , fmt , ## args)
+#define INFO(fmt, args...) \
+	xprintk(KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+
+#define USB_ID               (MSM_USB_BASE + 0x0000)
+#define USB_HWGENERAL        (MSM_USB_BASE + 0x0004)
+#define USB_HWHOST           (MSM_USB_BASE + 0x0008)
+#define USB_HWDEVICE         (MSM_USB_BASE + 0x000C)
+#define USB_HWTXBUF          (MSM_USB_BASE + 0x0010)
+#define USB_HWRXBUF          (MSM_USB_BASE + 0x0014)
+
+#ifdef CONFIG_ARCH_MSM7X00A
+#define USB_SBUSCFG          (MSM_USB_BASE + 0x0090)
+#else
+#define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
+#define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
+#endif
+
+#define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HCIVERSION       (MSM_USB_BASE + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS        (MSM_USB_BASE + 0x0104)
+#define USB_HCCPARAMS        (MSM_USB_BASE + 0x0108)
+#define USB_DCIVERSION       (MSM_USB_BASE + 0x0120) /* 16 bit */
+#define USB_USBCMD           (MSM_USB_BASE + 0x0140)
+#define USB_USBSTS           (MSM_USB_BASE + 0x0144)
+#define USB_USBINTR          (MSM_USB_BASE + 0x0148)
+#define USB_FRINDEX          (MSM_USB_BASE + 0x014C)
+#define USB_DEVICEADDR       (MSM_USB_BASE + 0x0154)
+#define USB_ENDPOINTLISTADDR (MSM_USB_BASE + 0x0158)
+#define USB_BURSTSIZE        (MSM_USB_BASE + 0x0160)
+#define USB_TXFILLTUNING     (MSM_USB_BASE + 0x0164)
+#define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
+#define USB_ENDPTNAK         (MSM_USB_BASE + 0x0178)
+#define USB_ENDPTNAKEN       (MSM_USB_BASE + 0x017C)
+#define USB_PORTSC           (MSM_USB_BASE + 0x0184)
+#define USB_OTGSC            (MSM_USB_BASE + 0x01A4)
+#define USB_USBMODE          (MSM_USB_BASE + 0x01A8)
+#define USB_ENDPTSETUPSTAT   (MSM_USB_BASE + 0x01AC)
+#define USB_ENDPTPRIME       (MSM_USB_BASE + 0x01B0)
+#define USB_ENDPTFLUSH       (MSM_USB_BASE + 0x01B4)
+#define USB_ENDPTSTAT        (MSM_USB_BASE + 0x01B8)
+#define USB_ENDPTCOMPLETE    (MSM_USB_BASE + 0x01BC)
+#define USB_ENDPTCTRL(n)     (MSM_USB_BASE + 0x01C0 + (4 * (n)))
+
+
+#define USBCMD_RESET   2
+#define USBCMD_ATTACH  1
+#define USBCMD_ATDTW   (1 << 14)
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST   3
+
+struct ept_queue_head {
+	unsigned config;
+	unsigned active; /* read-only */
+
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved_0;
+
+	unsigned char setup_data[8];
+
+	unsigned reserved_1;
+	unsigned reserved_2;
+	unsigned reserved_3;
+	unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)     ((n) << 16)
+#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
+#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+
+struct ept_queue_item {
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved;
+};
+
+#define TERMINATE 1
+
+#define INFO_BYTES(n)         ((n) << 16)
+#define INFO_IOC              (1 << 15)
+#define INFO_ACTIVE           (1 << 7)
+#define INFO_HALTED           (1 << 6)
+#define INFO_BUFFER_ERROR     (1 << 5)
+#define INFO_TXN_ERROR        (1 << 3)
+
+
+#define STS_NAKI              (1 << 16)  /* */
+#define STS_SLI               (1 << 8)   /* R/WC - suspend state entered */
+#define STS_SRI               (1 << 7)   /* R/WC - SOF recv'd */
+#define STS_URI               (1 << 6)   /* R/WC - RESET recv'd */
+#define STS_FRI               (1 << 3)   /* R/WC - Frame List Rollover */
+#define STS_PCI               (1 << 2)   /* R/WC - Port Change Detect */
+#define STS_UEI               (1 << 1)   /* R/WC - USB Error */
+#define STS_UI                (1 << 0)   /* R/WC - USB Transaction Complete */
+
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+
+#define CTRL_TXE              (1 << 23)
+#define CTRL_TXR              (1 << 22)
+#define CTRL_TXI              (1 << 21)
+#define CTRL_TXD              (1 << 17)
+#define CTRL_TXS              (1 << 16)
+#define CTRL_RXE              (1 << 7)
+#define CTRL_RXR              (1 << 6)
+#define CTRL_RXI              (1 << 5)
+#define CTRL_RXD              (1 << 1)
+#define CTRL_RXS              (1 << 0)
+
+#define CTRL_TXT_MASK         (3 << 18)
+#define CTRL_TXT_CTRL         (0 << 18)
+#define CTRL_TXT_ISOCH        (1 << 18)
+#define CTRL_TXT_BULK         (2 << 18)
+#define CTRL_TXT_INT          (3 << 18)
+#define CTRL_TXT_EP_TYPE_SHIFT 18
+
+#define CTRL_RXT_MASK         (3 << 2)
+#define CTRL_RXT_CTRL         (0 << 2)
+#define CTRL_RXT_ISOCH        (1 << 2)
+#define CTRL_RXT_BULK         (2 << 2)
+#define CTRL_RXT_INT          (3 << 2)
+#define CTRL_RXT_EP_TYPE_SHIFT 2
+
+#define ULPI_WAKEUP           (1 << 31)
+#define ULPI_RUN              (1 << 30)
+#define ULPI_WRITE            (1 << 29)
+#define ULPI_READ             (0 << 29)
+#define ULPI_STATE_NORMAL     (1 << 27)
+#define ULPI_ADDR(n)          (((n) & 255) << 16)
+#define ULPI_DATA(n)          ((n) & 255)
+#define ULPI_DATA_READ(n)     (((n) >> 8) & 255)
+
+#define ULPI_DEBUG_REG        (0x15)
+#define ULPI_SCRATCH_REG      (0x16)
+
+#define ULPI_FUNC_CTRL_CLR    (0x06)
+#define   ULPI_FUNC_SUSPENDM  (1 << 6)
+
+
+/* USB_PORTSC bits for determining port speed */
+#define PORTSC_PSPD_FS        (0 << 26)
+#define PORTSC_PSPD_LS        (1 << 26)
+#define PORTSC_PSPD_HS        (2 << 26)
+#define PORTSC_PSPD_MASK      (3 << 26)
+
+#define PORTSC_PTS_MASK       (3 << 30)
+#define PORTSC_PTS_ULPI       (2 << 30)
+#define PORTSC_PTS_SERIAL     (3 << 30)
+
+#define PORTSC_CCS             (1 << 0)  /* current connect status */
+#define PORTSC_PORT_RESET      (1 << 8)
+#define PORTSC_LS              (3 << 10) /* Read - Port's Line status */
+#define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
+
+#endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
-- 
1.7.1

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/5] USB: msm72k_udc: Add debugfs support
  2010-09-01  9:06 [PATCH 0/5] Add MSM USB Device Controller support Pavankumar Kondeti
  2010-09-01  9:06 ` [PATCH 1/5] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
@ 2010-09-01  9:06 ` Pavankumar Kondeti
  2010-09-01  9:06 ` [PATCH 3/5] USB: msm72k_udc: Add Remote wakeup support Pavankumar Kondeti
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Pavankumar Kondeti @ 2010-09-01  9:06 UTC (permalink / raw)
  To: gregkh
  Cc: linux-usb, linux-arm-msm, lockwood, swetland, Pavankumar Kondeti,
	Brian Swetland

Provide debugfs files for reading endpoint registers and associated
requests info, re-enumeration and resetting the hardware.

This patch was originally developed by Google and is available at
http://android.git.kernel.org/?p=kernel/experimental.git.

CC: Mike Lockwood <lockwood@android.com>
CC: Brian Swetland <swetland@google.com>
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
---
 drivers/usb/gadget/msm72k_udc.c |  135 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 135 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index e405dc4..84315a2 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -26,6 +26,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/platform_device.h>
+#include <linux/debugfs.h>
 #include <linux/workqueue.h>
 #include <linux/clk.h>
 
@@ -118,6 +119,7 @@ static void usb_do_work(struct work_struct *w);
 #define USB_FLAG_START          0x0001
 #define USB_FLAG_VBUS_ONLINE    0x0002
 #define USB_FLAG_VBUS_OFFLINE   0x0004
+#define USB_FLAG_RESET          0x0008
 
 struct usb_info {
 	/* lock for register/queue/device state changes */
@@ -1152,6 +1154,12 @@ static void usb_do_work(struct work_struct *w)
 				usb_do_work_check_vbus(ui);
 				break;
 			}
+			if (flags & USB_FLAG_RESET) {
+				INFO("ONLINE -> RESET\n");
+				usb_reset(ui);
+				INFO("RESET -> ONLINE\n");
+				break;
+			}
 			break;
 		case USB_STATE_OFFLINE:
 			/* If we were signaled to go online and vbus is still
@@ -1196,6 +1204,131 @@ void msm_hsusb_set_vbus_state(int online)
 		spin_unlock_irqrestore(&ui->lock, flags);
 }
 
+#if defined(CONFIG_DEBUG_FS)
+void usb_function_reenumerate(void)
+{
+	struct usb_info *ui = the_usb_info;
+
+	/* disable and re-enable the D+ pullup */
+	msm72k_pullup(&ui->gadget, false);
+	usleep_range(10000, 12000);
+	msm72k_pullup(&ui->gadget, true);
+}
+
+static char debug_buffer[PAGE_SIZE];
+
+static ssize_t debug_read_status(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	char *buf = debug_buffer;
+	unsigned long flags;
+	struct msm_endpoint *ept;
+	struct msm_request *req;
+	int n;
+	int i = 0;
+
+	spin_lock_irqsave(&ui->lock, flags);
+
+	i += scnprintf(buf + i, PAGE_SIZE - i,
+		       "regs: setup=%08x prime=%08x stat=%08x done=%08x\n",
+		       readl(USB_ENDPTSETUPSTAT),
+		       readl(USB_ENDPTPRIME),
+		       readl(USB_ENDPTSTAT),
+		       readl(USB_ENDPTCOMPLETE));
+	i += scnprintf(buf + i, PAGE_SIZE - i,
+		       "regs:   cmd=%08x   sts=%08x intr=%08x port=%08x\n\n",
+		       readl(USB_USBCMD),
+		       readl(USB_USBSTS),
+		       readl(USB_USBINTR),
+		       readl(USB_PORTSC));
+
+
+	for (n = 0; n < 32; n++) {
+		ept = ui->ept + n;
+		if (ept->ep.maxpacket == 0)
+			continue;
+
+		i += scnprintf(buf + i, PAGE_SIZE - i,
+			       "ept%d %s cfg=%08x active=%08x next=%08x"
+			       "info=%08x\n", ept->num,
+			       (ept->flags & EPT_FLAG_IN) ? "in " : "out",
+			       ept->head->config, ept->head->active,
+			       ept->head->next, ept->head->info);
+
+		for (req = ept->req; req; req = req->next)
+			i += scnprintf(buf + i, PAGE_SIZE - i,
+				       "  req @%08x next=%08x info=%08x"
+				       "page0=%08x %c %c\n",
+				       req->item_dma, req->item->next,
+				       req->item->info, req->item->page0,
+				       req->busy ? 'B' : ' ',
+				       req->live ? 'L' : ' '
+				);
+	}
+
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return simple_read_from_buffer(ubuf, count, ppos, buf, i);
+}
+
+static ssize_t debug_write_reset(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ui->flags |= USB_FLAG_RESET;
+	schedule_work(&ui->work);
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return count;
+}
+
+static ssize_t debug_write_cycle(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	usb_function_reenumerate();
+	return count;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+const struct file_operations debug_stat_ops = {
+	.open = debug_open,
+	.read = debug_read_status,
+};
+
+const struct file_operations debug_reset_ops = {
+	.open = debug_open,
+	.write = debug_write_reset,
+};
+
+const struct file_operations debug_cycle_ops = {
+	.open = debug_open,
+	.write = debug_write_cycle,
+};
+
+static void usb_debugfs_init(struct usb_info *ui)
+{
+	struct dentry *dent;
+	dent = debugfs_create_dir("usb", 0);
+	if (IS_ERR(dent))
+		return;
+
+	debugfs_create_file("status", 0444, dent, ui, &debug_stat_ops);
+	debugfs_create_file("reset", 0220, dent, ui, &debug_reset_ops);
+	debugfs_create_file("cycle", 0220, dent, ui, &debug_cycle_ops);
+}
+#else
+static void usb_debugfs_init(struct usb_info *ui) {}
+#endif			/* CONFIG_DEBUG_FS */
+
 static int
 msm72k_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
@@ -1483,6 +1616,8 @@ static int msm72k_probe(struct platform_device *pdev)
 
 	the_usb_info = ui;
 
+	usb_debugfs_init(ui);
+
 	usb_prepare(ui);
 
 	return 0;
-- 
1.7.1

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/5] USB: msm72k_udc: Add Remote wakeup support
  2010-09-01  9:06 [PATCH 0/5] Add MSM USB Device Controller support Pavankumar Kondeti
  2010-09-01  9:06 ` [PATCH 1/5] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
  2010-09-01  9:06 ` [PATCH 2/5] USB: msm72k_udc: Add debugfs support Pavankumar Kondeti
@ 2010-09-01  9:06 ` Pavankumar Kondeti
  2010-09-01  9:06 ` [PATCH 4/5] USB: msm72k_udc: Add Test Mode support Pavankumar Kondeti
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Pavankumar Kondeti @ 2010-09-01  9:06 UTC (permalink / raw)
  To: gregkh
  Cc: linux-usb, linux-arm-msm, lockwood, swetland, Pavankumar Kondeti,
	Vamsi Krishna

Process device remote wakeup set/clear feature requests and implement
wakeup method of usb_gadget_ops.  This patch also provides a sysfs file
to initiate remote wakeup from user space.  Remote wakeup can be generated
by poking into /sys/devices/platform/msm_hsusb/gadget/wakeup file.

Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Vamsi Krishna <vskrishn@codeaurora.org>
---
 drivers/usb/gadget/msm72k_udc.c  |   57 ++++++++++++++++++++++++++++++++++++++
 include/linux/usb/msm_hsusb_hw.h |    3 ++
 2 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 84315a2..9922d3d 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -167,6 +167,7 @@ struct usb_info {
 	struct clk *pclk;
 
 	unsigned int ep0_dir;
+	u8 remote_wakeup;
 };
 
 static const struct usb_ep_ops msm72k_ep_ops;
@@ -585,6 +586,8 @@ static void handle_setup(struct usb_info *ui)
 				u16 temp = 0;
 
 				temp = 1 << USB_DEVICE_SELF_POWERED;
+				temp |= (ui->remote_wakeup <<
+						USB_DEVICE_REMOTE_WAKEUP);
 				memcpy(req->buf, &temp, 2);
 				break;
 			}
@@ -630,6 +633,16 @@ static void handle_setup(struct usb_info *ui)
 			*/
 			writel((ctl.wValue << 25) | (1 << 24), USB_DEVICEADDR);
 			goto ack;
+		} else if (ctl.bRequest == USB_REQ_SET_FEATURE) {
+			switch (ctl.wValue) {
+			case USB_DEVICE_REMOTE_WAKEUP:
+				ui->remote_wakeup = 1;
+				goto ack;
+			}
+		} else if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) &&
+				(ctl.wValue == USB_DEVICE_REMOTE_WAKEUP)) {
+			ui->remote_wakeup = 0;
+			goto ack;
 		}
 	}
 
@@ -1538,12 +1551,49 @@ static int msm72k_pullup(struct usb_gadget *_gadget, int is_active)
 	return 0;
 }
 
+static int msm72k_wakeup(struct usb_gadget *_gadget)
+{
+	struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+	unsigned long flags;
+
+	if (!ui->remote_wakeup) {
+		ERROR("%s: remote wakeup not supported\n", __func__);
+		return -ENOTSUPP;
+	}
+
+	if (!ui->online) {
+		ERROR("%s: device is not configured\n", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&ui->lock, flags);
+	if ((readl(USB_PORTSC) & PORTSC_SUSP) == PORTSC_SUSP) {
+		INFO("%s: enabling force resume\n", __func__);
+		writel(readl(USB_PORTSC) | PORTSC_FPR, USB_PORTSC);
+	}
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return 0;
+}
+
 static const struct usb_gadget_ops msm72k_ops = {
 	.get_frame	= msm72k_get_frame,
 	.vbus_session	= msm72k_udc_vbus_session,
 	.pullup		= msm72k_pullup,
+	.wakeup		= msm72k_wakeup,
 };
 
+static ssize_t usb_remote_wakeup(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct usb_info *ui = the_usb_info;
+
+	msm72k_wakeup(&ui->gadget);
+
+	return count;
+}
+static DEVICE_ATTR(wakeup, S_IWUSR, 0, usb_remote_wakeup);
+
 static int msm72k_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -1673,6 +1723,12 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 
 	INFO("registered gadget driver '%s'\n", driver->driver.name);
 
+	/* create sysfs node for remote wakeup */
+	retval = device_create_file(&ui->gadget.dev, &dev_attr_wakeup);
+	if (retval != 0)
+		INFO("failed to create sysfs entry: (wakeup) error: (%d)\n",
+					retval);
+
 	usb_start(ui);
 
 	return 0;
@@ -1693,6 +1749,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	if (!driver || driver != dev->driver || !driver->unbind)
 		return -EINVAL;
 
+	device_remove_file(&dev->gadget.dev, &dev_attr_wakeup);
 	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index ab28be6..ae13342 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -200,6 +200,9 @@ struct ept_queue_item {
 #define PORTSC_PSPD_LS        (1 << 26)
 #define PORTSC_PSPD_HS        (2 << 26)
 #define PORTSC_PSPD_MASK      (3 << 26)
+/* suspend and remote wakeup */
+#define PORTSC_FPR             (1 << 6)
+#define PORTSC_SUSP            (1 << 7)
 
 #define PORTSC_PTS_MASK       (3 << 30)
 #define PORTSC_PTS_ULPI       (2 << 30)
-- 
1.7.1

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/5] USB: msm72k_udc: Add Test Mode support
  2010-09-01  9:06 [PATCH 0/5] Add MSM USB Device Controller support Pavankumar Kondeti
                   ` (2 preceding siblings ...)
  2010-09-01  9:06 ` [PATCH 3/5] USB: msm72k_udc: Add Remote wakeup support Pavankumar Kondeti
@ 2010-09-01  9:06 ` Pavankumar Kondeti
  2010-09-01  9:06 ` [PATCH 5/5] USB: msm72k_udc: Add charging notification support Pavankumar Kondeti
  2010-09-01 22:52 ` [PATCH 0/5] Add MSM USB Device Controller support David Lanzendörfer
  5 siblings, 0 replies; 14+ messages in thread
From: Pavankumar Kondeti @ 2010-09-01  9:06 UTC (permalink / raw)
  To: gregkh
  Cc: linux-usb, linux-arm-msm, lockwood, swetland, Pavankumar Kondeti,
	Vamsi Krishna

Implement the test modes mentioned in 7.1.20 section of USB 2.0
specification.  High-speed capable devices must support these test
modes to facilitate compliance testing.

Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Vamsi Krishna <vskrishn@codeaurora.org>
---
 drivers/usb/gadget/msm72k_udc.c  |   49 +++++++++++++++++++++++++++++++++++++-
 include/linux/usb/msm_hsusb_hw.h |   11 ++++++++
 2 files changed, 59 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 9922d3d..dadb7c2 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -168,6 +168,7 @@ struct usb_info {
 
 	unsigned int ep0_dir;
 	u8 remote_wakeup;
+	u16 test_mode;
 };
 
 static const struct usb_ep_ops msm72k_ep_ops;
@@ -509,11 +510,47 @@ static void ep0_queue_ack_complete(struct usb_ep *ep, struct usb_request *req)
 		ep0_complete(ep, req);
 }
 
+static void ep0_setup_ack_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(ep);
+	struct usb_info *ui = ept->ui;
+	unsigned int temp;
+
+	if (!ui->test_mode)
+		return;
+
+	switch (ui->test_mode) {
+	case J_TEST:
+		INFO("usb electrical test mode: (J)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_J_STATE, USB_PORTSC);
+		break;
+
+	case K_TEST:
+		INFO("usb electrical test mode: (K)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_K_STATE, USB_PORTSC);
+		break;
+
+	case SE0_NAK_TEST:
+		INFO("usb electrical test mode: (SE0-NAK)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_SE0_NAK, USB_PORTSC);
+		break;
+
+	case TST_PKT_TEST:
+		INFO("usb electrical test mode: (TEST_PKT)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_TST_PKT, USB_PORTSC);
+		break;
+	}
+}
+
 static void ep0_setup_ack(struct usb_info *ui)
 {
 	struct usb_request *req = ui->setup_req;
 	req->length = 0;
-	req->complete = 0;
+	req->complete = ep0_setup_ack_complete;
 	usb_ept_queue_xfer(&ui->ep0in, req);
 }
 
@@ -635,6 +672,16 @@ static void handle_setup(struct usb_info *ui)
 			goto ack;
 		} else if (ctl.bRequest == USB_REQ_SET_FEATURE) {
 			switch (ctl.wValue) {
+			case USB_DEVICE_TEST_MODE:
+				switch (ctl.wIndex) {
+				case J_TEST:
+				case K_TEST:
+				case SE0_NAK_TEST:
+				case TST_PKT_TEST:
+					ui->test_mode = ctl.wIndex;
+					goto ack;
+				}
+				goto stall;
 			case USB_DEVICE_REMOTE_WAKEUP:
 				ui->remote_wakeup = 1;
 				goto ack;
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index ae13342..22360c2 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -204,6 +204,17 @@ struct ept_queue_item {
 #define PORTSC_FPR             (1 << 6)
 #define PORTSC_SUSP            (1 << 7)
 
+/* test mode support */
+#define J_TEST			(0x0100)
+#define K_TEST			(0x0200)
+#define SE0_NAK_TEST		(0x0300)
+#define TST_PKT_TEST		(0x0400)
+#define PORTSC_PTC		(0xf << 16)
+#define PORTSC_PTC_J_STATE	(0x01 << 16)
+#define PORTSC_PTC_K_STATE	(0x02 << 16)
+#define PORTSC_PTC_SE0_NAK	(0x03 << 16)
+#define PORTSC_PTC_TST_PKT	(0x04 << 16)
+
 #define PORTSC_PTS_MASK       (3 << 30)
 #define PORTSC_PTS_ULPI       (2 << 30)
 #define PORTSC_PTS_SERIAL     (3 << 30)
-- 
1.7.1

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/5] USB: msm72k_udc: Add charging notification support
  2010-09-01  9:06 [PATCH 0/5] Add MSM USB Device Controller support Pavankumar Kondeti
                   ` (3 preceding siblings ...)
  2010-09-01  9:06 ` [PATCH 4/5] USB: msm72k_udc: Add Test Mode support Pavankumar Kondeti
@ 2010-09-01  9:06 ` Pavankumar Kondeti
  2010-09-01 22:52 ` [PATCH 0/5] Add MSM USB Device Controller support David Lanzendörfer
  5 siblings, 0 replies; 14+ messages in thread
From: Pavankumar Kondeti @ 2010-09-01  9:06 UTC (permalink / raw)
  To: gregkh
  Cc: linux-usb, linux-arm-msm, lockwood, swetland, Pavankumar Kondeti,
	Brian Swetland

Provide Host PC (after configured), Wall charger notifications.
Typically Battery/Charger driver is subscribed to these notifications
and responsible for notifying user space and drawing the current.

This patch was originally developed by Google and is available at
http://android.git.kernel.org/?p=kernel/experimental.git.

CC: Mike Lockwood <lockwood@android.com>
CC: Brian Swetland <swetland@google.com>
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
---
 drivers/usb/gadget/msm72k_udc.c |   16 ++++++++++++++++
 include/linux/usb/msm_hsusb.h   |    8 ++++++++
 2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index dadb7c2..e048b6a 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -155,6 +155,9 @@ struct usb_info {
 	void (*phy_reset)(void);
 	void (*hw_reset)(bool en);
 
+	/* for notification when USB is connected or disconnected */
+	void (*usb_connected)(int);
+
 	struct work_struct work;
 
 	struct usb_gadget		gadget;
@@ -664,6 +667,8 @@ static void handle_setup(struct usb_info *ui)
 	if (ctl.bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD)) {
 		if (ctl.bRequest == USB_REQ_SET_CONFIGURATION) {
 			ui->online = !!ctl.wValue;
+			if (ui->online && ui->usb_connected)
+				ui->usb_connected(USB_CHG_HOST);
 		} else if (ctl.bRequest == USB_REQ_SET_ADDRESS) {
 			/* write address delayed (will take effect
 			** after the next IN txn)
@@ -1193,6 +1198,9 @@ static void usb_do_work(struct work_struct *w)
 				msm72k_pullup(&ui->gadget, 0);
 				spin_unlock_irqrestore(&ui->lock, iflags);
 
+				if (ui->usb_connected)
+					ui->usb_connected(USB_CHG_NONE);
+
 				/* terminate any transactions, etc */
 				flush_all_endpoints(ui);
 
@@ -1231,6 +1239,13 @@ static void usb_do_work(struct work_struct *w)
 				clk_enable(ui->pclk);
 				usb_reset(ui);
 
+				/* detect shorted D+/D-, indicating AC power */
+				usleep_range(10000, 12000);
+				if ((readl(USB_PORTSC) & PORTSC_LS) ==
+						PORTSC_LS)
+					if (ui->usb_connected)
+						ui->usb_connected(USB_CHG_WALL);
+
 				ui->state = USB_STATE_ONLINE;
 				usb_do_work_check_vbus(ui);
 			}
@@ -1660,6 +1675,7 @@ static int msm72k_probe(struct platform_device *pdev)
 		struct msm_hsusb_platform_data *pdata = pdev->dev.platform_data;
 		ui->phy_reset = pdata->phy_reset;
 		ui->phy_init_seq = pdata->phy_init_seq;
+		ui->usb_connected = pdata->usb_connected;
 	}
 
 	irq = platform_get_irq(pdev, 0);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 534db4e..4d75a3d 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -19,6 +19,11 @@
 
 #include <linux/types.h>
 
+/* USB charger types */
+#define USB_CHG_NONE	0
+#define USB_CHG_HOST	1
+#define USB_CHG_WALL	2
+
 /* platform device data for msm_hsusb driver */
 
 struct msm_hsusb_platform_data {
@@ -28,6 +33,9 @@ struct msm_hsusb_platform_data {
 	/* (de)assert the reset to the usb core */
 	void (*hw_reset)(bool enable);
 
+	/* for notification when USB is connected or disconnected */
+	void (*usb_connected)(int);
+
 	/* val, reg pairs terminated by -1 */
 	int *phy_init_seq;
 };
-- 
1.7.1

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/5] USB: Add MSM USB Device Controller driver
  2010-09-01  9:06 ` [PATCH 1/5] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
@ 2010-09-01 14:03   ` Alan Stern
  2010-09-01 15:05     ` Pavan Kondeti
  2010-09-01 16:04     ` pkondeti
  2010-09-01 18:29   ` Brian Swetland
  1 sibling, 2 replies; 14+ messages in thread
From: Alan Stern @ 2010-09-01 14:03 UTC (permalink / raw)
  To: Pavankumar Kondeti
  Cc: gregkh, linux-usb, linux-arm-msm, lockwood, swetland, Brian Swetland

On Wed, 1 Sep 2010, Pavankumar Kondeti wrote:

> This patch adds the basic support for the USB Device Controller on Qualcomm
> MSM family of SOCs.  The controller supports upto 16 endpoints including the
> default endpoint (ep0).  All the data transfers are driven by DMA.
> 
> VBUS line is also connected to PMIC chip.  The module controlling PMIC chip
> notifies about cable connect/disconnect events.  Hence, PHY comparators
> are turned off in low power mode.
> 
> This driver was originally developed by Google and is available at
> http://android.git.kernel.org/?p=kernel/experimental.git.

...

> +static const struct usb_ep_ops msm72k_ep_ops = {
> +	.enable		= msm72k_enable,
> +	.disable	= msm72k_disable,
> +
> +	.alloc_request	= msm72k_alloc_request,
> +	.free_request	= msm72k_free_request,
> +
> +	.queue		= msm72k_queue,
> +	.dequeue	= msm72k_dequeue,
> +
> +	.set_halt	= msm72k_set_halt,
> +	.fifo_flush	= msm72k_fifo_flush,
> +};

The .set_wedge method is missing.

Alan Stern


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/5] USB: Add MSM USB Device Controller driver
  2010-09-01 14:03   ` Alan Stern
@ 2010-09-01 15:05     ` Pavan Kondeti
  2010-09-01 16:04     ` pkondeti
  1 sibling, 0 replies; 14+ messages in thread
From: Pavan Kondeti @ 2010-09-01 15:05 UTC (permalink / raw)
  To: Alan Stern
  Cc: gregkh, linux-usb, linux-arm-msm, lockwood, swetland, Brian Swetland

On Wed, Sep 01, 2010 at 10:03:54AM -0400, Alan Stern wrote:
> On Wed, 1 Sep 2010, Pavankumar Kondeti wrote:
> 
> > This patch adds the basic support for the USB Device Controller on Qualcomm
> > MSM family of SOCs.  The controller supports upto 16 endpoints including the
> > default endpoint (ep0).  All the data transfers are driven by DMA.
> > 
> > VBUS line is also connected to PMIC chip.  The module controlling PMIC chip
> > notifies about cable connect/disconnect events.  Hence, PHY comparators
> > are turned off in low power mode.
> > 
> > This driver was originally developed by Google and is available at
> > http://android.git.kernel.org/?p=kernel/experimental.git.
> 
> ...
> 
> > +static const struct usb_ep_ops msm72k_ep_ops = {
> > +	.enable		= msm72k_enable,
> > +	.disable	= msm72k_disable,
> > +
> > +	.alloc_request	= msm72k_alloc_request,
> > +	.free_request	= msm72k_free_request,
> > +
> > +	.queue		= msm72k_queue,
> > +	.dequeue	= msm72k_dequeue,
> > +
> > +	.set_halt	= msm72k_set_halt,
> > +	.fifo_flush	= msm72k_fifo_flush,
> > +};
> 
> The .set_wedge method is missing.
 
Thanks for pointing this out. I will implement this method.

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/5] USB: Add MSM USB Device Controller driver
  2010-09-01 14:03   ` Alan Stern
  2010-09-01 15:05     ` Pavan Kondeti
@ 2010-09-01 16:04     ` pkondeti
  1 sibling, 0 replies; 14+ messages in thread
From: pkondeti @ 2010-09-01 16:04 UTC (permalink / raw)
  To: Alan Stern
  Cc: Pavankumar Kondeti, gregkh, linux-usb, linux-arm-msm, lockwood,
	swetland, Brian Swetland

> On Wed, 1 Sep 2010, Pavankumar Kondeti wrote:
>
>> This patch adds the basic support for the USB Device Controller on
>> Qualcomm
>> MSM family of SOCs.  The controller supports upto 16 endpoints including
>> the
>> default endpoint (ep0).  All the data transfers are driven by DMA.
>>
>> VBUS line is also connected to PMIC chip.  The module controlling PMIC
>> chip
>> notifies about cable connect/disconnect events.  Hence, PHY comparators
>> are turned off in low power mode.
>>
>> This driver was originally developed by Google and is available at
>> http://android.git.kernel.org/?p=kernel/experimental.git.
>
> ...
>
>> +static const struct usb_ep_ops msm72k_ep_ops = {
>> +	.enable		= msm72k_enable,
>> +	.disable	= msm72k_disable,
>> +
>> +	.alloc_request	= msm72k_alloc_request,
>> +	.free_request	= msm72k_free_request,
>> +
>> +	.queue		= msm72k_queue,
>> +	.dequeue	= msm72k_dequeue,
>> +
>> +	.set_halt	= msm72k_set_halt,
>> +	.fifo_flush	= msm72k_fifo_flush,
>> +};
>
> The .set_wedge method is missing.
>

Thanks for pointing this out. I will implement this method.

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/5] USB: Add MSM USB Device Controller driver
  2010-09-01  9:06 ` [PATCH 1/5] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
  2010-09-01 14:03   ` Alan Stern
@ 2010-09-01 18:29   ` Brian Swetland
  1 sibling, 0 replies; 14+ messages in thread
From: Brian Swetland @ 2010-09-01 18:29 UTC (permalink / raw)
  To: Pavankumar Kondeti; +Cc: gregkh, linux-usb, linux-arm-msm, lockwood

On Wed, Sep 1, 2010 at 2:06 AM, Pavankumar Kondeti
<pkondeti@codeaurora.org> wrote:
>
> This patch adds the basic support for the USB Device Controller on Qualcomm
> MSM family of SOCs.  The controller supports upto 16 endpoints including the
> default endpoint (ep0).  All the data transfers are driven by DMA.
>
> VBUS line is also connected to PMIC chip.  The module controlling PMIC chip
> notifies about cable connect/disconnect events.  Hence, PHY comparators
> are turned off in low power mode.
>
> This driver was originally developed by Google and is available at
> http://android.git.kernel.org/?p=kernel/experimental.git.
>
> CC: Mike Lockwood <lockwood@android.com>
> CC: Brian Swetland <swetland@google.com>
> Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>


> +++ b/drivers/usb/gadget/msm72k_udc.c
> @@ -0,0 +1,1591 @@
> +/*
> + * Driver for HighSpeed USB Client Controller in MSM7K
> + *
> + * Copyright (C) 2008 Google, Inc.
> + * Author: Mike Lockwood <lockwood@android.com>
> + *         Brian Swetland <swetland@google.com>

Given that you guys have done a bunch of work on this, it might make
sense to slap a codeaurora/quicinc copyright on there as well.
Might also make sense to drop the old Author: lines and/or update them.

> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/5] Add MSM USB Device Controller support
  2010-09-01  9:06 [PATCH 0/5] Add MSM USB Device Controller support Pavankumar Kondeti
                   ` (4 preceding siblings ...)
  2010-09-01  9:06 ` [PATCH 5/5] USB: msm72k_udc: Add charging notification support Pavankumar Kondeti
@ 2010-09-01 22:52 ` David Lanzendörfer
  2010-09-02  4:29   ` Pavan Kondeti
  5 siblings, 1 reply; 14+ messages in thread
From: David Lanzendörfer @ 2010-09-01 22:52 UTC (permalink / raw)
  To: linux-arm-msm

[-- Attachment #1: Type: Text/Plain, Size: 419 bytes --]

Hi
I tried your patchset with https://www.codeaurora.org/gitweb/quic/kernel/?p=dwalker/linux-msm.git;a=shortlog;h=refs/heads/for-next
But somehow, usb networking doesnt seem to come up? O_o
I'm sure, if you have tested it, the mistake has to be on my side.
Could I try /your/ kernel config? (With leviathan-incoming [htc-msm-2.6.32-fork for GNU/Linux] the device comes up on bootup)

Thanks and best regards
	leviathan

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/5] Add MSM USB Device Controller support
  2010-09-01 22:52 ` [PATCH 0/5] Add MSM USB Device Controller support David Lanzendörfer
@ 2010-09-02  4:29   ` Pavan Kondeti
  2010-09-02 12:19     ` David Lanzendörfer
  2010-09-02 16:29     ` David Lanzendörfer
  0 siblings, 2 replies; 14+ messages in thread
From: Pavan Kondeti @ 2010-09-02  4:29 UTC (permalink / raw)
  To: David Lanzendörfer; +Cc: linux-arm-msm

On Thu, Sep 02, 2010 at 12:52:43AM +0200, David Lanzendörfer wrote:
> Hi
> I tried your patchset with https://www.codeaurora.org/gitweb/quic/kernel/?p=dwalker/linux-msm.git;a=shortlog;h=refs/heads/for-next
> But somehow, usb networking doesnt seem to come up? O_o
> I'm sure, if you have tested it, the mistake has to be on my side.
> Could I try /your/ kernel config? (With leviathan-incoming [htc-msm-2.6.32-fork for GNU/Linux] the device comes up on bootup)
> 

Do you know which chipset(7x01/7x27/8x50) is used in your device? We have to
setup the platform data and device in the respective board file. I have tested
USB on 8x50 and it works fine. I will post a patch to add usb support for 8x50
today. Which gadget (android/ethernet) are you using? Also VBUS detection
happens on Peripheral processor and Apps processor gets a RPC notification.
But RPC infrastructure is not present in upstream msm. So you need to call
msm_hsusb_vbus_state(1) after adding your platform device. I will see if I can
add a debugfs file in the driver to manipulate vbus state.

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/5] Add MSM USB Device Controller support
  2010-09-02  4:29   ` Pavan Kondeti
@ 2010-09-02 12:19     ` David Lanzendörfer
  2010-09-02 16:29     ` David Lanzendörfer
  1 sibling, 0 replies; 14+ messages in thread
From: David Lanzendörfer @ 2010-09-02 12:19 UTC (permalink / raw)
  To: Pavan Kondeti, linux-arm-msm

[-- Attachment #1: Type: Text/Plain, Size: 1287 bytes --]

>Do you know which chipset(7x01/7x27/8x50) is used in your device?
Yes. Of course.
Its the htcdream, so chipset MSM7201A.

>We have to setup the platform data and device in the respective board file.
I tried that, but I've got overlooked something...

>I have tested USB on 8x50 and it works fine.
Wonderfull! ^_^

>I will post a patch to add usb support for 8x50 today.
Hmm. Ok.

>Which gadget (android/ethernet) are you using?
Ethernet (I'm developing for SHR - GNU/Linux)

>Also VBUS detection happens on Peripheral processor and Apps processor gets a RPC notification.
I'm not that fan of RPC but if its required...

>But RPC infrastructure is not present in upstream msm.
Yes. I've already tried to port it, but gave up and decided to wait,
until someone does it, who understands more of it. :-)

>So you need to call msm_hsusb_vbus_state(1) after adding your platform device.
>I will see if I can add a debugfs file in the driver to manipulate vbus state.
I would be very glad about cooperation.
ATM only GNUtoo, mickey and me are working on making GNU/Linux running on HTC-Dream.
http://gitorious.org/htc-msm-2-6-32/leviathan-incoming/commits/msm-gnuconform
Would be cool, if upstream - with its much cleaner codebase - would fully support
htcdream. :-D


best regards
	leviathan

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/5] Add MSM USB Device Controller support
  2010-09-02  4:29   ` Pavan Kondeti
  2010-09-02 12:19     ` David Lanzendörfer
@ 2010-09-02 16:29     ` David Lanzendörfer
  1 sibling, 0 replies; 14+ messages in thread
From: David Lanzendörfer @ 2010-09-02 16:29 UTC (permalink / raw)
  To: linux-arm-msm

[-- Attachment #1: Type: Text/Plain, Size: 146 bytes --]

Additional question:
>We have to setup the platform data and device in the respective board file.
How do I do that? ^_^"

thx&&regards
	leviathan

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2010-09-02 16:26 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-01  9:06 [PATCH 0/5] Add MSM USB Device Controller support Pavankumar Kondeti
2010-09-01  9:06 ` [PATCH 1/5] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
2010-09-01 14:03   ` Alan Stern
2010-09-01 15:05     ` Pavan Kondeti
2010-09-01 16:04     ` pkondeti
2010-09-01 18:29   ` Brian Swetland
2010-09-01  9:06 ` [PATCH 2/5] USB: msm72k_udc: Add debugfs support Pavankumar Kondeti
2010-09-01  9:06 ` [PATCH 3/5] USB: msm72k_udc: Add Remote wakeup support Pavankumar Kondeti
2010-09-01  9:06 ` [PATCH 4/5] USB: msm72k_udc: Add Test Mode support Pavankumar Kondeti
2010-09-01  9:06 ` [PATCH 5/5] USB: msm72k_udc: Add charging notification support Pavankumar Kondeti
2010-09-01 22:52 ` [PATCH 0/5] Add MSM USB Device Controller support David Lanzendörfer
2010-09-02  4:29   ` Pavan Kondeti
2010-09-02 12:19     ` David Lanzendörfer
2010-09-02 16:29     ` David Lanzendörfer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.