linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] Add MSM USB Device Controller support
@ 2010-11-09 11:18 Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH v2] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
                   ` (4 more replies)
  0 siblings, 5 replies; 26+ messages in thread
From: Pavankumar Kondeti @ 2010-11-09 11:18 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, 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. Tested against v2.6.37-rc1

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

Changelog:
V1-->V2
1. Data structure comments are annotated as per kernel-doc
2. Replaced custom macros with dev_info/dev_err/dev_dbg
3. Implemented set_wedge method
4. Implemented "vbus" debugfs file to simulate cable connect and disconnect
5. Fixed a bug in remote wakeup support where remote wakeup condition is not
cleared upon reset

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   | 1978 +++++++++++++++++++++++++++++++++++++
 include/linux/usb/msm_hsusb.h     |   54 +
 include/linux/usb/msm_hsusb_hw.h  |  198 ++++
 6 files changed, 2256 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] 26+ messages in thread

* [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 11:18 [PATCH v2] Add MSM USB Device Controller support Pavankumar Kondeti
@ 2010-11-09 11:18 ` Pavankumar Kondeti
  2010-11-09 11:40   ` Matthieu CASTET
                     ` (2 more replies)
  2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add debugfs support Pavankumar Kondeti
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 26+ messages in thread
From: Pavankumar Kondeti @ 2010-11-09 11:18 UTC (permalink / raw)
  To: greg
  Cc: linux-usb, linux-arm-msm, Pavankumar Kondeti, Mike Lockwood,
	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   | 1685 +++++++++++++++++++++++++++++++++++++
 include/linux/usb/msm_hsusb.h     |   38 +
 include/linux/usb/msm_hsusb_hw.h  |  184 ++++
 6 files changed, 1933 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 b739ca8..9e37782 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -495,6 +495,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 5780db4..8a07462 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -24,6 +24,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..3fa4192
--- /dev/null
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -0,0 +1,1685 @@
+/*
+ * Driver for HighSpeed USB Client Controller in MSM7K
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * 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>
+
+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 - MSM request structure.
+ * @req: USB endpoint request.
+ * @gadget_complete: saved copy req.complete. useful for ep0 requests.
+ * @ui: private data.
+ * @next: pointer to next queued msm_request.
+ * @busy: request is already in queue.
+ * @live: request is submitted to hardware.
+ * @alloced: request memory is allocated by udc. used when freeing the request.
+ * @dma: DMA address of request memory.
+ * @item_dma: DMA address of endpoint queue item (dTD).
+ * @item: pointer to endpoint queue item (dTD).
+ *
+ */
+struct msm_request {
+	struct usb_request req;
+
+	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 - MSM endpoint structure.
+ * @ep: USB endpoint.
+ * @ui: private data.
+ * @req: head of pending requests.
+ * @last: tail of pending requests.
+ * @flags: flags indicate endpoint characteristics like direction.
+ * @bit: bit number (0-31) in various status registers as well as the index
+ *       into the usb_info's array of all endpoints.
+ * @num: endpoint number (0-15).
+ * @wedged: endpoint wedge status (usb_ep_set_wedge is called on this ep).
+ * @head: pointer to endpoint queue head (dQH). allocated from dma pool.
+ *
+ */
+struct msm_endpoint {
+	struct usb_ep ep;
+	struct usb_info *ui;
+	struct msm_request *req;
+	struct msm_request *last;
+	unsigned flags;
+
+	unsigned char bit;
+	unsigned char num;
+
+	unsigned wedged:1;
+
+	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: privated data of this driver.
+ * @lock: spinlock used for register/queue/device state changes.
+ * @setup_req: request used for handling setup transactions.
+ * @pdev: pointer to platform device. used for allocating DMA pool and
+ *        print messages using dev_ macros.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @addr: ioremaped address of HSUSB registers memory region.
+ * @state: present  state.
+ *         USB_STATE_IDLE: gadget driver is not registered yet.
+ *         USB_STATE_ONLINE: connected to host/charger.
+ *         USB_STATE_OFFLINE: not attached.
+ * @flags: flags indicate state transition requests.
+ *         USB_FLAG_START: set upon gadget driver registration.
+ *         USB_FLAG_VBUS_ONLINE: set upon VBUS presence.
+ *         USB_FLAG_VBUS_OFFLINE: set upon VBUS absence.
+ * @online: indicates USB configured state. set upon set_config request.
+ * @running: indicates pull-up state.
+ * @pool: DMA pool for allocating endpoint queue items (dTD).
+ * @buf: non-cached memory allocated via dma_alloc_coherent API for endpoint
+ *       queue head memory (dQH).
+ * @dma: DMA address of endpoint queue head memory (dQH).
+ * @head: head pointer of endpoint queue head structures (dQH).
+ * @ept: array of endpoints. endpoints are ordered based on their status bits.
+ *       so they are OUT0, OUT1, ... OUT15, IN0, IN1, ... IN15.
+ * @phy_init_seq: phy configuration data comes from platform data.
+ * @phy_reset: function pointer to assert followed by de-assert of PHY.
+ *             comes from platform data.
+ * @hw_reset: function pointer to assert/de-assert of link.
+ *            comes from platform data.
+ * @work: work_struct for state transitions.
+ * @gadget: gadget struct of this driver.
+ * @driver: gadget driver bound to this driver.
+ * @clk: clock struct of usb_hs_clk.
+ * @pclk: clock struct of usb_hs_pclk.
+ * @ep0_dir: direction of ep0 setup data transfer.
+ *
+ */
+struct usb_info {
+	spinlock_t lock;
+
+	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;
+
+	unsigned char *buf;
+	dma_addr_t dma;
+
+	struct ept_queue_head *head;
+
+	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) {
+		dev_err(&ui->pdev->dev, "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) {
+		dev_err(&ui->pdev->dev, "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) {
+		dev_vdbg(&ui->pdev->dev, "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;
+	struct usb_info *ui = ept->ui;
+
+	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)
+		dev_vdbg(&ui->pdev->dev, "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:
+				dev_err(&ui->pdev->dev, "%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:
+				dev_err(&ui->pdev->dev, "%s: unsupported"
+					"ep_type %d for %s\n",
+					__func__, ep_type, ept->ep.name);
+				break;
+			}
+		}
+	}
+	writel(n, USB_ENDPTCTRL(ept->num));
+
+	dev_vdbg(&ui->pdev->dev, "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);
+		dev_info(&ui->pdev->dev, "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);
+		dev_info(&ui->pdev->dev, "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);
+
+	dev_vdbg(&ui->pdev->dev, "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 (ept->wedged)
+						goto ack;
+
+					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;
+
+	dev_vdbg(&ui->pdev->dev, "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)) {
+			/* FIXME pass on more specific error code */
+			req->req.status = -EIO;
+			req->req.actual = 0;
+			dev_info(&ui->pdev->dev, "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:
+	dev_err(&ui->pdev->dev, "%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:
+			dev_info(&ui->pdev->dev, "portchange USB_SPEED_FULL\n");
+			ui->gadget.speed = USB_SPEED_FULL;
+			break;
+		case PORTSC_PSPD_LS:
+			dev_info(&ui->pdev->dev, "portchange USB_SPEED_LOW\n");
+			ui->gadget.speed = USB_SPEED_LOW;
+			break;
+		case PORTSC_PSPD_HS:
+			dev_info(&ui->pdev->dev, "portchange USB_SPEED_HIGH\n");
+			ui->gadget.speed = USB_SPEED_HIGH;
+			break;
+		}
+	}
+
+	if (n & STS_URI) {
+		dev_info(&ui->pdev->dev, "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);
+
+			/* FIXME: we can't seem to detect going offline,
+			 * FIXME:  so deconfigure on reset for the time being
+			 */
+			if (ui->driver) {
+				dev_info(&ui->pdev->dev, "notify offline\n");
+				ui->driver->disconnect(&ui->gadget);
+			}
+		}
+	}
+
+	if (n & STS_SLI)
+		dev_info(&ui->pdev->dev, "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);
+
+	/* FIXME: 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();
+
+	/* FIXME: 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
+	dev_info(&ui->pdev->dev, "msm_hsusb_phy_reset: success\n");
+	return 0;
+}
+
+static void usb_reset(struct usb_info *ui)
+{
+	unsigned long flags;
+
+	dev_info(&ui->pdev->dev, "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)
+		dev_err(&ui->pdev->dev, "%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) {
+		dev_info(&ui->pdev->dev, "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)
+{
+	dev_info(&ui->pdev->dev, "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) {
+				dev_info(&ui->pdev->dev, "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) {
+				dev_info(&ui->pdev->dev, "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) {
+					dev_info(&ui->pdev->dev,
+						"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) {
+				dev_info(&ui->pdev->dev, "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;
+		}
+	}
+}
+
+/**
+ * msm_hsusb_set_vbus_state - Report VBUS state.
+ * @online: indicates VBUS presence or absence.
+ *
+ * VBUS line is also connected to PMIC hardware. Module controlling PMIC
+ * can use this function to repost VBUS state. USB state transition happens
+ * based on VBUS state. This function may get called before this driver is
+ * initialized. VBUS state is stored and state transition will happen
+ * accordingly after driver is initialized.
+ *
+ * TODO: This function should be movied to OTG driver when we have one. OTG
+ * driver use vbus_session method to start/stop udc.
+ */
+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);
+	ept->wedged = 0;
+	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));
+	if (!value)
+		ept->wedged = 0;
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return 0;
+}
+
+static void
+msm72k_fifo_flush(struct usb_ep *_ep)
+{
+	flush_endpoint(to_msm_endpoint(_ep));
+}
+
+static int msm72k_set_wedge(struct usb_ep *_ep)
+{
+	struct msm_endpoint *ept = to_msm_endpoint(_ep);
+	struct usb_info *ui = ept->ui;
+	unsigned long flags;
+
+	if (ept->num == 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ui->lock, flags);
+	ept->wedged = 1;
+	spin_unlock_irqrestore(&ui->lock, flags);
+
+	return msm72k_set_halt(_ep, 1);
+}
+
+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,
+	.set_wedge	= msm72k_set_wedge,
+	.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) {
+		dev_info(&ui->pdev->dev, "enable pullup\n");
+		writel(cmd | 1, USB_USBCMD);
+	} else {
+		dev_info(&ui->pdev->dev, "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;
+
+	dev_dbg(&pdev->dev, "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);
+
+	dev_info(&ui->pdev->dev, "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_probe_driver(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *))
+{
+	struct usb_info *ui = the_usb_info;
+	int			retval, n;
+
+	if (!driver || driver->speed < USB_SPEED_FULL
+			|| !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 = bind(&ui->gadget);
+	if (retval) {
+		dev_info(&ui->pdev->dev, "bind to driver %s --> error %d\n",
+				driver->driver.name, retval);
+		device_del(&ui->gadget.dev);
+		goto fail;
+	}
+
+	dev_info(&ui->pdev->dev, "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_probe_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);
+
+	dev_vdbg(&dev->pdev->dev, "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..758d140
--- /dev/null
+++ b/include/linux/usb/msm_hsusb.h
@@ -0,0 +1,38 @@
+/* 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>
+
+/**
+ * struct msm_hsusb_platform_data - platform device data
+ *              for msm72k_udc driver.
+ * @phy_reset:	assert followed by de-assert of PHY.
+ * @hw_reset:	if enable is true, assert link otherwise
+ *              de-assert link.
+ * @phy_init_seq: PHY configuration sequence. val, reg pairs
+ *              terminated by -1.
+ *
+ */
+struct msm_hsusb_platform_data {
+	void (*phy_reset)(void);
+	void (*hw_reset)(bool enable);
+	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..cfbd0aa
--- /dev/null
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -0,0 +1,184 @@
+/*
+ * 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 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] 26+ messages in thread

* [PATCH v2] USB: msm72k_udc: Add debugfs support
  2010-11-09 11:18 [PATCH v2] Add MSM USB Device Controller support Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH v2] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
@ 2010-11-09 11:18 ` Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add Remote wakeup support Pavankumar Kondeti
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 26+ messages in thread
From: Pavankumar Kondeti @ 2010-11-09 11:18 UTC (permalink / raw)
  To: greg
  Cc: linux-usb, linux-arm-msm, Pavankumar Kondeti, Mike Lockwood,
	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 |  164 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 164 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 3fa4192..6ec1a32 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -27,8 +27,10 @@
 #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>
+#include <linux/uaccess.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -138,6 +140,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: privated data of this driver.
@@ -155,6 +158,7 @@ static void usb_do_work(struct work_struct *w);
  *         USB_FLAG_START: set upon gadget driver registration.
  *         USB_FLAG_VBUS_ONLINE: set upon VBUS presence.
  *         USB_FLAG_VBUS_OFFLINE: set upon VBUS absence.
+ *         USB_FLAG_RESET: set upon reset request from debug file.
  * @online: indicates USB configured state. set upon set_config request.
  * @running: indicates pull-up state.
  * @pool: DMA pool for allocating endpoint queue items (dTD).
@@ -1216,6 +1220,12 @@ static void usb_do_work(struct work_struct *w)
 				usb_do_work_check_vbus(ui);
 				break;
 			}
+			if (flags & USB_FLAG_RESET) {
+				dev_info(&ui->pdev->dev, "ONLINE -> RESET\n");
+				usb_reset(ui);
+				dev_info(&ui->pdev->dev, "RESET -> ONLINE\n");
+				break;
+			}
 			break;
 		case USB_STATE_OFFLINE:
 			/* If we were signaled to go online and vbus is still
@@ -1269,6 +1279,158 @@ 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 ssize_t debug_write_vbus(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	char kbuf[8];
+	size_t len;
+
+	len = min(count, sizeof(kbuf) - 1);
+	if (copy_from_user(kbuf, buf, len))
+		return -EFAULT;
+	kbuf[len] = '\0';
+
+	if (strncmp(kbuf, "on", 2) == 0)
+		msm_hsusb_set_vbus_state(1);
+	else if (strncmp(kbuf, "off", 3) == 0)
+		msm_hsusb_set_vbus_state(0);
+	else
+		return -EINVAL;
+
+	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,
+};
+
+const struct file_operations debug_vbus_ops = {
+	.open = debug_open,
+	.write = debug_write_vbus,
+};
+
+static void usb_debugfs_init(struct usb_info *ui)
+{
+	struct dentry *dent;
+	dent = debugfs_create_dir(dev_name(&ui->pdev->dev), 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);
+	debugfs_create_file("vbus", 0220, dent, ui, &debug_vbus_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)
 {
@@ -1576,6 +1738,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] 26+ messages in thread

* [PATCH v2] USB: msm72k_udc: Add Remote wakeup support
  2010-11-09 11:18 [PATCH v2] Add MSM USB Device Controller support Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH v2] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add debugfs support Pavankumar Kondeti
@ 2010-11-09 11:18 ` Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add Test Mode support Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH] USB: msm72k_udc: Add charging notification support Pavankumar Kondeti
  4 siblings, 0 replies; 26+ messages in thread
From: Pavankumar Kondeti @ 2010-11-09 11:18 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, 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  |   62 ++++++++++++++++++++++++++++++++++++++
 include/linux/usb/msm_hsusb_hw.h |    3 ++
 2 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 6ec1a32..51e9f2e 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -179,6 +179,7 @@ static void usb_do_work(struct work_struct *w);
  * @clk: clock struct of usb_hs_clk.
  * @pclk: clock struct of usb_hs_pclk.
  * @ep0_dir: direction of ep0 setup data transfer.
+ * @remote_wakeup: indicates remote wakeup capability enabled by host
  *
  */
 struct usb_info {
@@ -221,6 +222,7 @@ struct usb_info {
 	struct clk *pclk;
 
 	unsigned int ep0_dir;
+	u8 remote_wakeup;
 };
 
 static const struct usb_ep_ops msm72k_ep_ops;
@@ -647,6 +649,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;
 			}
@@ -695,6 +699,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;
 		}
 	}
 
@@ -900,6 +914,7 @@ static irqreturn_t usb_interrupt(int irq, void *data)
 		writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
 		writel(0xffffffff, USB_ENDPTFLUSH);
 		writel(0, USB_ENDPTCTRL(1));
+		ui->remote_wakeup = 0;
 
 		if (ui->online != 0) {
 			/* marking us offline will cause ept queue attempts
@@ -1660,12 +1675,52 @@ 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) {
+		dev_err(&ui->pdev->dev, "%s: remote wakeup not supported\n",
+				__func__);
+		return -ENOTSUPP;
+	}
+
+	if (!ui->online) {
+		dev_err(&ui->pdev->dev, "%s: device is not configured\n",
+				__func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&ui->lock, flags);
+	if ((readl(USB_PORTSC) & PORTSC_SUSP) == PORTSC_SUSP) {
+		dev_info(&ui->pdev->dev, "%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;
@@ -1795,6 +1850,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	dev_info(&ui->pdev->dev, "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)
+		dev_info(&ui->pdev->dev, "failed to create sysfs entry:"
+				"(wakeup) error: (%d)\n", retval);
+
 	usb_start(ui);
 
 	return 0;
@@ -1815,6 +1876,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 cfbd0aa..6f54268 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -171,6 +171,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] 26+ messages in thread

* [PATCH v2] USB: msm72k_udc: Add Test Mode support
  2010-11-09 11:18 [PATCH v2] Add MSM USB Device Controller support Pavankumar Kondeti
                   ` (2 preceding siblings ...)
  2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add Remote wakeup support Pavankumar Kondeti
@ 2010-11-09 11:18 ` Pavankumar Kondeti
  2010-11-09 11:18 ` [PATCH] USB: msm72k_udc: Add charging notification support Pavankumar Kondeti
  4 siblings, 0 replies; 26+ messages in thread
From: Pavankumar Kondeti @ 2010-11-09 11:18 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, 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  |   52 +++++++++++++++++++++++++++++++++++++-
 include/linux/usb/msm_hsusb_hw.h |   11 ++++++++
 2 files changed, 62 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 51e9f2e..2b476a6 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -180,6 +180,7 @@ static void usb_do_work(struct work_struct *w);
  * @pclk: clock struct of usb_hs_pclk.
  * @ep0_dir: direction of ep0 setup data transfer.
  * @remote_wakeup: indicates remote wakeup capability enabled by host
+ * @test_mode: electrical test mode set by host
  *
  */
 struct usb_info {
@@ -223,6 +224,7 @@ struct usb_info {
 
 	unsigned int ep0_dir;
 	u8 remote_wakeup;
+	u16 test_mode;
 };
 
 static const struct usb_ep_ops msm72k_ep_ops;
@@ -571,11 +573,49 @@ 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:
+		dev_info(&ui->pdev->dev, "usb electrical test mode: (J)\n");
+		temp = readl(USB_PORTSC) & (~PORTSC_PTC);
+		writel(temp | PORTSC_PTC_J_STATE, USB_PORTSC);
+		break;
+
+	case K_TEST:
+		dev_info(&ui->pdev->dev, "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:
+		dev_info(&ui->pdev->dev, "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:
+		dev_info(&ui->pdev->dev, "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);
 }
 
@@ -701,6 +741,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 6f54268..743e6b9 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -175,6 +175,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] 26+ messages in thread

* [PATCH] USB: msm72k_udc: Add charging notification support
  2010-11-09 11:18 [PATCH v2] Add MSM USB Device Controller support Pavankumar Kondeti
                   ` (3 preceding siblings ...)
  2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add Test Mode support Pavankumar Kondeti
@ 2010-11-09 11:18 ` Pavankumar Kondeti
  4 siblings, 0 replies; 26+ messages in thread
From: Pavankumar Kondeti @ 2010-11-09 11:18 UTC (permalink / raw)
  To: greg; +Cc: linux-usb, linux-arm-msm, Pavankumar Kondeti

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.

Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
---
 drivers/usb/gadget/msm72k_udc.c |   17 +++++++++++++++++
 include/linux/usb/msm_hsusb.h   |   16 ++++++++++++++++
 2 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 2b476a6..80f6003 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -173,6 +173,8 @@ static void usb_do_work(struct work_struct *w);
  *             comes from platform data.
  * @hw_reset: function pointer to assert/de-assert of link.
  *            comes from platform data.
+ * @usb_connected: callback function registered to receive charger type
+ *                 notifications. comes from platform data.
  * @work: work_struct for state transitions.
  * @gadget: gadget struct of this driver.
  * @driver: gadget driver bound to this driver.
@@ -211,6 +213,8 @@ struct usb_info {
 	void (*phy_reset)(void);
 	void (*hw_reset)(bool en);
 
+	void (*usb_connected)(int);
+
 	struct work_struct work;
 
 	struct usb_gadget		gadget;
@@ -733,6 +737,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)
@@ -1263,6 +1269,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);
 
@@ -1302,6 +1311,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);
 			}
@@ -1790,6 +1806,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 758d140..f95b62c 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -20,11 +20,26 @@
 #include <linux/types.h>
 
 /**
+ * USB charger types.
+ *
+ * USB_CHG_NONE         Charger is not connected.
+ * USB_CHG_HOST         Connected to Host PC.
+ * USB_CHG_WALL         Connected to Wall charger.
+ *
+ */
+enum usb_chg_type {
+	USB_CHG_NONE = 0,
+	USB_CHG_HOST,
+	USB_CHG_WALL,
+};
+
+/**
  * struct msm_hsusb_platform_data - platform device data
  *              for msm72k_udc driver.
  * @phy_reset:	assert followed by de-assert of PHY.
  * @hw_reset:	if enable is true, assert link otherwise
  *              de-assert link.
+ * @usb_connected: callback function to receive usb charger type notifications.
  * @phy_init_seq: PHY configuration sequence. val, reg pairs
  *              terminated by -1.
  *
@@ -32,6 +47,7 @@
 struct msm_hsusb_platform_data {
 	void (*phy_reset)(void);
 	void (*hw_reset)(bool enable);
+	void (*usb_connected)(int);
 	int *phy_init_seq;
 };
 
-- 
1.7.1


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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 11:18 ` [PATCH v2] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
@ 2010-11-09 11:40   ` Matthieu CASTET
  2010-11-09 12:16     ` Pavan Kondeti
  2010-11-09 13:25   ` Heikki Krogerus
  2010-11-09 13:52   ` Matthieu CASTET
  2 siblings, 1 reply; 26+ messages in thread
From: Matthieu CASTET @ 2010-11-09 11:40 UTC (permalink / raw)
  To: Pavankumar Kondeti
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

Pavankumar Kondeti a écrit :
> 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.
> 
> +
> +#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
> +
>
This look like the arc/chipidea/mips ehci otg core.

Why can't you reuse the ci13xxx_udc.c driver ?
Or if ci13xxx_udc.c is too bad, rewrite a new generic version for this core.


Matthieu

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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 11:40   ` Matthieu CASTET
@ 2010-11-09 12:16     ` Pavan Kondeti
  2010-11-09 13:36       ` Matthieu CASTET
  0 siblings, 1 reply; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-09 12:16 UTC (permalink / raw)
  To: Matthieu CASTET
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

On Tue, Nov 09, 2010 at 12:40:17PM +0100, Matthieu CASTET wrote:

Hi Matthieu,

> Pavankumar Kondeti a écrit :
>> 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.
>>
>> +
>> +#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
>> +
>>
> This look like the arc/chipidea/mips ehci otg core.

Yes. It is chipidea core for ARM.
>
> Why can't you reuse the ci13xxx_udc.c driver ?
> Or if ci13xxx_udc.c is too bad, rewrite a new generic version for this core.
>
ci13xxx_udc.c driver registers with PCI subsytem (ours is a platform subsystem),
does not manage clocks. msm72k_udc.c also takes care of initializing the
integrated PHY. We also need to program special registers (MSM-ARM specific)
upon resetting the hardware.

Thanks,
Pavan

-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 11:18 ` [PATCH v2] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
  2010-11-09 11:40   ` Matthieu CASTET
@ 2010-11-09 13:25   ` Heikki Krogerus
  2010-11-09 13:52   ` Matthieu CASTET
  2 siblings, 0 replies; 26+ messages in thread
From: Heikki Krogerus @ 2010-11-09 13:25 UTC (permalink / raw)
  To: ext Pavankumar Kondeti
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

On Tue, Nov 09, 2010 at 12:18:10PM +0100, ext 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.
> 
> 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   | 1685 +++++++++++++++++++++++++++++++++++++
>  include/linux/usb/msm_hsusb.h     |   38 +
>  include/linux/usb/msm_hsusb_hw.h  |  184 ++++
>  6 files changed, 1933 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

<snip>

> +#define ULPI_DEBUG_REG        (0x15)
> +#define ULPI_SCRATCH_REG      (0x16)
> +
> +#define ULPI_FUNC_CTRL_CLR    (0x06)
> +#define   ULPI_FUNC_SUSPENDM  (1 << 6)

No more redefinitions of ulpi regs. Just include usb/ulpi.h.

-- 
heikki

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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 12:16     ` Pavan Kondeti
@ 2010-11-09 13:36       ` Matthieu CASTET
  2010-11-10  2:12         ` Pavan Kondeti
  0 siblings, 1 reply; 26+ messages in thread
From: Matthieu CASTET @ 2010-11-09 13:36 UTC (permalink / raw)
  To: Pavan Kondeti
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

Hi Pavan,

Pavan Kondeti a écrit :
> On Tue, Nov 09, 2010 at 12:40:17PM +0100, Matthieu CASTET wrote:
> 
> Hi Matthieu,
> 
>>>
>> This look like the arc/chipidea/mips ehci otg core.
> 
> Yes. It is chipidea core for ARM.
>> Why can't you reuse the ci13xxx_udc.c driver ?
>> Or if ci13xxx_udc.c is too bad, rewrite a new generic version for this core.
>>
> ci13xxx_udc.c driver registers with PCI subsytem (ours is a platform subsystem),
> does not manage clocks. msm72k_udc.c also takes care of initializing the
> integrated PHY. We also need to program special registers (MSM-ARM specific)
> upon resetting the hardware.
Yes, but why not adding this to ci13xxx_udc.c instead of doing a new driver.
For example adding platform subsystem is less than 150 lines of code.

I am not sure doing n drivers for a same hardware is a good idea.

May be ci13xxx_udc.c isn't enough generic, but in this case don't do the 
same mistake with the new driver.

Make a generic core, and make the ulpi stuff (or other specific stuff) 
in a glue around this code.

Look at host ehci : you don't need to rewrite ehci core. You only add a 
glue around it.


Matthieu

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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 11:18 ` [PATCH v2] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
  2010-11-09 11:40   ` Matthieu CASTET
  2010-11-09 13:25   ` Heikki Krogerus
@ 2010-11-09 13:52   ` Matthieu CASTET
  2010-11-09 15:36     ` Igor Grinberg
  2010-11-10  2:17     ` Pavan Kondeti
  2 siblings, 2 replies; 26+ messages in thread
From: Matthieu CASTET @ 2010-11-09 13:52 UTC (permalink / raw)
  To: Pavankumar Kondeti
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

Hi,

Pavankumar Kondeti a écrit :

> diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
> new file mode 100644
> index 0000000..3fa4192
> --- /dev/null
> +++ b/drivers/usb/gadget/msm72k_udc.c

> +
> +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) {
> +               dev_err(&ui->pdev->dev, "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) {
> +               dev_err(&ui->pdev->dev, "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) {
> +               dev_vdbg(&ui->pdev->dev, "ulpi: write 0x%02x to 0x%02x\n",
> +                               seq[0], seq[1]);
> +               ulpi_write(ui, seq[0], seq[1]);
> +               seq += 2;
> +       }
> +}
> +


--- /dev/null
+++ b/drivers/usb/otg/msm72k_otg.c

+
+#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
+static int ulpi_read(struct otg_transceiver *otg, u32 reg)
+{
+       int cnt = 0;
+
+       /* initiate read operation */
+       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+              USB_ULPI_VIEWPORT);
+
+       /* wait for completion */
+       while (cnt < ULPI_IO_TIMEOUT_USEC) {
+               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
+                       break;
+               udelay(1);
+               cnt++;
+       }
+
+       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+               dev_err(otg->dev, "ulpi_read: timeout %08x\n",
+                       readl(USB_ULPI_VIEWPORT));
+               return -ETIMEDOUT;
+       }
+       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
+}
+
+static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+{
+       int cnt = 0;
+
+       /* initiate write operation */
+       writel(ULPI_RUN | ULPI_WRITE |
+              ULPI_ADDR(reg) | ULPI_DATA(val),
+              USB_ULPI_VIEWPORT);
+
+       /* wait for completion */
+       while (cnt < ULPI_IO_TIMEOUT_USEC) {
+               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
+                       break;
+               udelay(1);
+               cnt++;
+       }
+
+       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+               dev_err(otg->dev, "ulpi_write: timeout\n");
+               return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static struct otg_io_access_ops msm_otg_io_ops = {
+       .read = ulpi_read,
+       .write = ulpi_write,
+};
+
+static void ulpi_init(struct msm_otg *motg)
+{
+       struct msm_otg_platform_data *pdata = motg->pdata;
+       int *seq = pdata->phy_init_seq;
+
+       if (!seq)
+               return;
+
+       while (seq[0] >= 0) {
+               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
+                               seq[0], seq[1]);
+               ulpi_write(&motg->otg, seq[0], seq[1]);
+               seq += 2;
+       }
+}


can't you share the ulpi fonctions from udc and otg ?

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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 13:52   ` Matthieu CASTET
@ 2010-11-09 15:36     ` Igor Grinberg
  2010-11-10  2:19       ` Pavan Kondeti
  2010-11-10  2:17     ` Pavan Kondeti
  1 sibling, 1 reply; 26+ messages in thread
From: Igor Grinberg @ 2010-11-09 15:36 UTC (permalink / raw)
  To: Matthieu CASTET
  Cc: Pavankumar Kondeti, greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland



On 11/09/10 15:52, Matthieu CASTET wrote:
> Hi,
>
> Pavankumar Kondeti a écrit :
>
>> diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
>> new file mode 100644
>> index 0000000..3fa4192
>> --- /dev/null
>> +++ b/drivers/usb/gadget/msm72k_udc.c
>
>> +
>> +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) {
>> +               dev_err(&ui->pdev->dev, "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) {
>> +               dev_err(&ui->pdev->dev, "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) {
>> +               dev_vdbg(&ui->pdev->dev, "ulpi: write 0x%02x to 0x%02x\n",
>> +                               seq[0], seq[1]);
>> +               ulpi_write(ui, seq[0], seq[1]);
>> +               seq += 2;
>> +       }
>> +}
>> +
>
>
> --- /dev/null
> +++ b/drivers/usb/otg/msm72k_otg.c
>
> +
> +#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
> +static int ulpi_read(struct otg_transceiver *otg, u32 reg)
> +{
> +       int cnt = 0;
> +
> +       /* initiate read operation */
> +       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
> +              USB_ULPI_VIEWPORT);
> +
> +       /* wait for completion */
> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> +                       break;
> +               udelay(1);
> +               cnt++;
> +       }
> +
> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> +               dev_err(otg->dev, "ulpi_read: timeout %08x\n",
> +                       readl(USB_ULPI_VIEWPORT));
> +               return -ETIMEDOUT;
> +       }
> +       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
> +}
> +
> +static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
> +{
> +       int cnt = 0;
> +
> +       /* initiate write operation */
> +       writel(ULPI_RUN | ULPI_WRITE |
> +              ULPI_ADDR(reg) | ULPI_DATA(val),
> +              USB_ULPI_VIEWPORT);
> +
> +       /* wait for completion */
> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> +                       break;
> +               udelay(1);
> +               cnt++;
> +       }
> +
> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> +               dev_err(otg->dev, "ulpi_write: timeout\n");
> +               return -ETIMEDOUT;
> +       }
> +       return 0;
> +}
> +
> +static struct otg_io_access_ops msm_otg_io_ops = {
> +       .read = ulpi_read,
> +       .write = ulpi_write,
> +};
> +
> +static void ulpi_init(struct msm_otg *motg)
> +{
> +       struct msm_otg_platform_data *pdata = motg->pdata;
> +       int *seq = pdata->phy_init_seq;
> +
> +       if (!seq)
> +               return;
> +
> +       while (seq[0] >= 0) {
> +               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
> +                               seq[0], seq[1]);
> +               ulpi_write(&motg->otg, seq[0], seq[1]);
> +               seq += 2;
> +       }
> +}
>
>
> can't you share the ulpi fonctions from udc and otg ?

The best would be to use the usb/otg/ulpi.c driver for the ulpi access.

-- 
Regards,
Igor.


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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 13:36       ` Matthieu CASTET
@ 2010-11-10  2:12         ` Pavan Kondeti
  2010-11-10  2:54           ` David Brownell
  0 siblings, 1 reply; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-10  2:12 UTC (permalink / raw)
  To: Matthieu CASTET
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

On Tue, Nov 09, 2010 at 02:36:57PM +0100, Matthieu CASTET wrote:
> Hi Pavan,
>
> Pavan Kondeti a écrit :
>> On Tue, Nov 09, 2010 at 12:40:17PM +0100, Matthieu CASTET wrote:
>>
>> Hi Matthieu,
>>
>>>>
>>> This look like the arc/chipidea/mips ehci otg core.
>>
>> Yes. It is chipidea core for ARM.
>>> Why can't you reuse the ci13xxx_udc.c driver ?
>>> Or if ci13xxx_udc.c is too bad, rewrite a new generic version for this core.
>>>
>> ci13xxx_udc.c driver registers with PCI subsytem (ours is a platform subsystem),
>> does not manage clocks. msm72k_udc.c also takes care of initializing the
>> integrated PHY. We also need to program special registers (MSM-ARM specific)
>> upon resetting the hardware.
> Yes, but why not adding this to ci13xxx_udc.c instead of doing a new driver.
> For example adding platform subsystem is less than 150 lines of code.

I agree.
>
> I am not sure doing n drivers for a same hardware is a good idea.
>
> May be ci13xxx_udc.c isn't enough generic, but in this case don't do the  
> same mistake with the new driver.
>
Sure. Thanks for the advice.

> Make a generic core, and make the ulpi stuff (or other specific stuff)  
> in a glue around this code.
>
IMHO, generic core should handle the controller stuff (endpoint operations,
interrupts processing etc...) and leave the transceiver interaction to the
individual device controller driver.
> Look at host ehci : you don't need to rewrite ehci core. You only add a  
> glue around it.
>
Thanks for pointing to EHCI. ehci-hcd can support PCI/platform/PS3 buses.
It takes care of most of the things and yet gives flexibility to HCD to
implement their own methods.

I will hack ci13xxx_udc.c (platform bus support) and see how it goes. If
it works, I will see how ci13xxx_ stuff can be reused efficiently.

-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 13:52   ` Matthieu CASTET
  2010-11-09 15:36     ` Igor Grinberg
@ 2010-11-10  2:17     ` Pavan Kondeti
  1 sibling, 0 replies; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-10  2:17 UTC (permalink / raw)
  To: Matthieu CASTET
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

On Tue, Nov 09, 2010 at 02:52:09PM +0100, Matthieu CASTET wrote:
> Hi,
>
> Pavankumar Kondeti a écrit :
>
>> diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
>> new file mode 100644
>> index 0000000..3fa4192
>> --- /dev/null
>> +++ b/drivers/usb/gadget/msm72k_udc.c
>
>> +
>> +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) {
>> +               dev_err(&ui->pdev->dev, "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) {
>> +               dev_err(&ui->pdev->dev, "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) {
>> +               dev_vdbg(&ui->pdev->dev, "ulpi: write 0x%02x to 0x%02x\n",
>> +                               seq[0], seq[1]);
>> +               ulpi_write(ui, seq[0], seq[1]);
>> +               seq += 2;
>> +       }
>> +}
>> +
>
>
> --- /dev/null
> +++ b/drivers/usb/otg/msm72k_otg.c
>
> +
> +#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
> +static int ulpi_read(struct otg_transceiver *otg, u32 reg)
> +{
> +       int cnt = 0;
> +
> +       /* initiate read operation */
> +       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
> +              USB_ULPI_VIEWPORT);
> +
> +       /* wait for completion */
> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> +                       break;
> +               udelay(1);
> +               cnt++;
> +       }
> +
> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> +               dev_err(otg->dev, "ulpi_read: timeout %08x\n",
> +                       readl(USB_ULPI_VIEWPORT));
> +               return -ETIMEDOUT;
> +       }
> +       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
> +}
> +
> +static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
> +{
> +       int cnt = 0;
> +
> +       /* initiate write operation */
> +       writel(ULPI_RUN | ULPI_WRITE |
> +              ULPI_ADDR(reg) | ULPI_DATA(val),
> +              USB_ULPI_VIEWPORT);
> +
> +       /* wait for completion */
> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> +                       break;
> +               udelay(1);
> +               cnt++;
> +       }
> +
> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> +               dev_err(otg->dev, "ulpi_write: timeout\n");
> +               return -ETIMEDOUT;
> +       }
> +       return 0;
> +}
> +
> +static struct otg_io_access_ops msm_otg_io_ops = {
> +       .read = ulpi_read,
> +       .write = ulpi_write,
> +};
> +
> +static void ulpi_init(struct msm_otg *motg)
> +{
> +       struct msm_otg_platform_data *pdata = motg->pdata;
> +       int *seq = pdata->phy_init_seq;
> +
> +       if (!seq)
> +               return;
> +
> +       while (seq[0] >= 0) {
> +               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
> +                               seq[0], seq[1]);
> +               ulpi_write(&motg->otg, seq[0], seq[1]);
> +               seq += 2;
> +       }
> +}
>
>
> can't you share the ulpi fonctions from udc and otg ?

Yes. udc can use the ulpi ops defined by the otg. But in udc patch series, otg
stuff is not integrated. I will post another patch to make udc work with
otg. or you want me to add otg integration in the 1st patch series it self?
-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-09 15:36     ` Igor Grinberg
@ 2010-11-10  2:19       ` Pavan Kondeti
  2010-11-10  6:47         ` Igor Grinberg
  0 siblings, 1 reply; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-10  2:19 UTC (permalink / raw)
  To: Igor Grinberg
  Cc: Matthieu CASTET, greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

On Tue, Nov 09, 2010 at 05:36:28PM +0200, Igor Grinberg wrote:
> 
> 
> On 11/09/10 15:52, Matthieu CASTET wrote:
> > Hi,
> >
> > Pavankumar Kondeti a écrit :
> >
> >> diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
> >> new file mode 100644
> >> index 0000000..3fa4192
> >> --- /dev/null
> >> +++ b/drivers/usb/gadget/msm72k_udc.c
> >
> >> +
> >> +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) {
> >> +               dev_err(&ui->pdev->dev, "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) {
> >> +               dev_err(&ui->pdev->dev, "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) {
> >> +               dev_vdbg(&ui->pdev->dev, "ulpi: write 0x%02x to 0x%02x\n",
> >> +                               seq[0], seq[1]);
> >> +               ulpi_write(ui, seq[0], seq[1]);
> >> +               seq += 2;
> >> +       }
> >> +}
> >> +
> >
> >
> > --- /dev/null
> > +++ b/drivers/usb/otg/msm72k_otg.c
> >
> > +
> > +#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
> > +static int ulpi_read(struct otg_transceiver *otg, u32 reg)
> > +{
> > +       int cnt = 0;
> > +
> > +       /* initiate read operation */
> > +       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
> > +              USB_ULPI_VIEWPORT);
> > +
> > +       /* wait for completion */
> > +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> > +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> > +                       break;
> > +               udelay(1);
> > +               cnt++;
> > +       }
> > +
> > +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> > +               dev_err(otg->dev, "ulpi_read: timeout %08x\n",
> > +                       readl(USB_ULPI_VIEWPORT));
> > +               return -ETIMEDOUT;
> > +       }
> > +       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
> > +}
> > +
> > +static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
> > +{
> > +       int cnt = 0;
> > +
> > +       /* initiate write operation */
> > +       writel(ULPI_RUN | ULPI_WRITE |
> > +              ULPI_ADDR(reg) | ULPI_DATA(val),
> > +              USB_ULPI_VIEWPORT);
> > +
> > +       /* wait for completion */
> > +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> > +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> > +                       break;
> > +               udelay(1);
> > +               cnt++;
> > +       }
> > +
> > +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> > +               dev_err(otg->dev, "ulpi_write: timeout\n");
> > +               return -ETIMEDOUT;
> > +       }
> > +       return 0;
> > +}
> > +
> > +static struct otg_io_access_ops msm_otg_io_ops = {
> > +       .read = ulpi_read,
> > +       .write = ulpi_write,
> > +};
> > +
> > +static void ulpi_init(struct msm_otg *motg)
> > +{
> > +       struct msm_otg_platform_data *pdata = motg->pdata;
> > +       int *seq = pdata->phy_init_seq;
> > +
> > +       if (!seq)
> > +               return;
> > +
> > +       while (seq[0] >= 0) {
> > +               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
> > +                               seq[0], seq[1]);
> > +               ulpi_write(&motg->otg, seq[0], seq[1]);
> > +               seq += 2;
> > +       }
> > +}
> >
> >
> > can't you share the ulpi fonctions from udc and otg ?
> 
> The best would be to use the usb/otg/ulpi.c driver for the ulpi access.
> 
This driver will eventually use msm72k_otg.c transceiver.

-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-10  2:12         ` Pavan Kondeti
@ 2010-11-10  2:54           ` David Brownell
  2010-11-10  6:22             ` Brian Swetland
  0 siblings, 1 reply; 26+ messages in thread
From: David Brownell @ 2010-11-10  2:54 UTC (permalink / raw)
  To: Matthieu CASTET, Pavan Kondeti
  Cc: greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland



--- On Tue, 11/9/10, Pavan Kondeti <pkondeti@codeaurora.org> wrote:

> >> Hi Matthieu,
> >>
> >>> This look like the arc/chipidea/mips ehci otg
> core.
> >>
> >> Yes. It is chipidea core for ARM.
> >>> Why can't you reuse the ci13xxx_udc.c driver

That basic approach is FAR PREFERABLE.  Fix
the bugs once, tune once, and so forth, reuse
the ULPI support, etc.  Work on more
platforms, since the silicon IP is reused.

You'll end up with more folk who can help
maintain the driver too, since the pool of
potential helpers won't be limited to those
who have/use MSM hardware.

Just be sure to cleanly factor the bus
(PCI vs MSM-s ARM platform flavor and
SoC glues (bus-related).  That factoring
will likely be the hardest part; but there
are examples of similar stuff in Linux today.

> ?
> >>> Or if ci13xxx_udc.c is too bad, rewrite a new
> generic version for this core.
> >>>
> > Yes, but why not adding this to ci13xxx_udc.c instead
> of doing a new driver.
> > For example adding platform subsystem is less than 150
> lines of code.
> 
> I agree.
> >
> > I am not sure doing n drivers for a same hardware is a
> good idea.

I'm pretty sure it is a BAD idea, myself.
Same IP/hardware means only bus/SoC glue
really needs to differ (including power and
reset management).

- Dave


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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-10  2:54           ` David Brownell
@ 2010-11-10  6:22             ` Brian Swetland
  2010-11-19 17:16               ` Matthieu CASTET
  0 siblings, 1 reply; 26+ messages in thread
From: Brian Swetland @ 2010-11-10  6:22 UTC (permalink / raw)
  To: David Brownell
  Cc: Matthieu CASTET, Pavan Kondeti, greg@kroah.com,
	linux-usb@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	Mike Lockwood

On Tue, Nov 9, 2010 at 6:54 PM, David Brownell <david-b@pacbell.net> wrote:
>
>
> --- On Tue, 11/9/10, Pavan Kondeti <pkondeti@codeaurora.org> wrote:
>
>> >> Hi Matthieu,
>> >>
>> >>> This look like the arc/chipidea/mips ehci otg
>> core.
>> >>
>> >> Yes. It is chipidea core for ARM.
>> >>> Why can't you reuse the ci13xxx_udc.c driver
>
> That basic approach is FAR PREFERABLE.  Fix
> the bugs once, tune once, and so forth, reuse
> the ULPI support, etc.  Work on more
> platforms, since the silicon IP is reused.
>
> You'll end up with more folk who can help
> maintain the driver too, since the pool of
> potential helpers won't be limited to those
> who have/use MSM hardware.
>
> Just be sure to cleanly factor the bus
> (PCI vs MSM-s ARM platform flavor and
> SoC glues (bus-related).  That factoring
> will likely be the hardest part; but there
> are examples of similar stuff in Linux today.

The main headache is that this particular IP has different bugs in
different instantiations (I know, for example, it exists in Tegra with
a different set of issues around fetching descriptor heads and cache
alignment, on MSM7201A after extensive testing we discovered there was
no reliable way of adding a descriptor to a list of transactions once
that queue was active, etc...), so things that work in one SoC may
break another, etc, etc, but that's part of the adventure I suppose.
I certainly agree that one unified driver is the way to go if you can
make it all work.

Brian

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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-10  2:19       ` Pavan Kondeti
@ 2010-11-10  6:47         ` Igor Grinberg
  2010-11-11  2:10           ` Pavan Kondeti
  0 siblings, 1 reply; 26+ messages in thread
From: Igor Grinberg @ 2010-11-10  6:47 UTC (permalink / raw)
  To: Pavan Kondeti
  Cc: Matthieu CASTET, greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

 On 11/10/10 04:19, Pavan Kondeti wrote:
> On Tue, Nov 09, 2010 at 05:36:28PM +0200, Igor Grinberg wrote:
>>
>> On 11/09/10 15:52, Matthieu CASTET wrote:
>>> Hi,
>>>
>>> Pavankumar Kondeti a écrit :
>>>
>>>> diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
>>>> new file mode 100644
>>>> index 0000000..3fa4192
>>>> --- /dev/null
>>>> +++ b/drivers/usb/gadget/msm72k_udc.c
>>>> +
>>>> +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) {
>>>> +               dev_err(&ui->pdev->dev, "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) {
>>>> +               dev_err(&ui->pdev->dev, "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) {
>>>> +               dev_vdbg(&ui->pdev->dev, "ulpi: write 0x%02x to 0x%02x\n",
>>>> +                               seq[0], seq[1]);
>>>> +               ulpi_write(ui, seq[0], seq[1]);
>>>> +               seq += 2;
>>>> +       }
>>>> +}
>>>> +
>>>
>>> --- /dev/null
>>> +++ b/drivers/usb/otg/msm72k_otg.c
>>>
>>> +
>>> +#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
>>> +static int ulpi_read(struct otg_transceiver *otg, u32 reg)
>>> +{
>>> +       int cnt = 0;
>>> +
>>> +       /* initiate read operation */
>>> +       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
>>> +              USB_ULPI_VIEWPORT);
>>> +
>>> +       /* wait for completion */
>>> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
>>> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
>>> +                       break;
>>> +               udelay(1);
>>> +               cnt++;
>>> +       }
>>> +
>>> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
>>> +               dev_err(otg->dev, "ulpi_read: timeout %08x\n",
>>> +                       readl(USB_ULPI_VIEWPORT));
>>> +               return -ETIMEDOUT;
>>> +       }
>>> +       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
>>> +}
>>> +
>>> +static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
>>> +{
>>> +       int cnt = 0;
>>> +
>>> +       /* initiate write operation */
>>> +       writel(ULPI_RUN | ULPI_WRITE |
>>> +              ULPI_ADDR(reg) | ULPI_DATA(val),
>>> +              USB_ULPI_VIEWPORT);
>>> +
>>> +       /* wait for completion */
>>> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
>>> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
>>> +                       break;
>>> +               udelay(1);
>>> +               cnt++;
>>> +       }
>>> +
>>> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
>>> +               dev_err(otg->dev, "ulpi_write: timeout\n");
>>> +               return -ETIMEDOUT;
>>> +       }
>>> +       return 0;
>>> +}
>>> +
>>> +static struct otg_io_access_ops msm_otg_io_ops = {
>>> +       .read = ulpi_read,
>>> +       .write = ulpi_write,
>>> +};
>>> +
>>> +static void ulpi_init(struct msm_otg *motg)
>>> +{
>>> +       struct msm_otg_platform_data *pdata = motg->pdata;
>>> +       int *seq = pdata->phy_init_seq;
>>> +
>>> +       if (!seq)
>>> +               return;
>>> +
>>> +       while (seq[0] >= 0) {
>>> +               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
>>> +                               seq[0], seq[1]);
>>> +               ulpi_write(&motg->otg, seq[0], seq[1]);
>>> +               seq += 2;
>>> +       }
>>> +}
>>>
>>>
>>> can't you share the ulpi fonctions from udc and otg ?
>> The best would be to use the usb/otg/ulpi.c driver for the ulpi access.
>>
> This driver will eventually use msm72k_otg.c transceiver.

Well, I mean, in addition to defining the struct otg_io_access_ops in some place,
where both device and host drivers can share the same ops code, you can also
use the ulpi generic driver as the protocol driver, instead of writing private code.
If the generic driver still lack some functionality, I can try to help you with this.

-- 
Regards,
Igor.


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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-10  6:47         ` Igor Grinberg
@ 2010-11-11  2:10           ` Pavan Kondeti
  2010-11-19  5:50             ` Pavan Kondeti
  0 siblings, 1 reply; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-11  2:10 UTC (permalink / raw)
  To: Igor Grinberg
  Cc: Matthieu CASTET, greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

Hi Igor,

On Wed, Nov 10, 2010 at 08:47:16AM +0200, Igor Grinberg wrote:
>  On 11/10/10 04:19, Pavan Kondeti wrote:
> > On Tue, Nov 09, 2010 at 05:36:28PM +0200, Igor Grinberg wrote:
> >>
> >> On 11/09/10 15:52, Matthieu CASTET wrote:
> >>> Hi,
> >>>
> >>> Pavankumar Kondeti a écrit :
> >>>
> >>>> diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
> >>>> new file mode 100644
> >>>> index 0000000..3fa4192
> >>>> --- /dev/null
> >>>> +++ b/drivers/usb/gadget/msm72k_udc.c
> >>>> +
> >>>> +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) {
> >>>> +               dev_err(&ui->pdev->dev, "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) {
> >>>> +               dev_err(&ui->pdev->dev, "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) {
> >>>> +               dev_vdbg(&ui->pdev->dev, "ulpi: write 0x%02x to 0x%02x\n",
> >>>> +                               seq[0], seq[1]);
> >>>> +               ulpi_write(ui, seq[0], seq[1]);
> >>>> +               seq += 2;
> >>>> +       }
> >>>> +}
> >>>> +
> >>>
> >>> --- /dev/null
> >>> +++ b/drivers/usb/otg/msm72k_otg.c
> >>>
> >>> +
> >>> +#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
> >>> +static int ulpi_read(struct otg_transceiver *otg, u32 reg)
> >>> +{
> >>> +       int cnt = 0;
> >>> +
> >>> +       /* initiate read operation */
> >>> +       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
> >>> +              USB_ULPI_VIEWPORT);
> >>> +
> >>> +       /* wait for completion */
> >>> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> >>> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> >>> +                       break;
> >>> +               udelay(1);
> >>> +               cnt++;
> >>> +       }
> >>> +
> >>> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> >>> +               dev_err(otg->dev, "ulpi_read: timeout %08x\n",
> >>> +                       readl(USB_ULPI_VIEWPORT));
> >>> +               return -ETIMEDOUT;
> >>> +       }
> >>> +       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
> >>> +}
> >>> +
> >>> +static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
> >>> +{
> >>> +       int cnt = 0;
> >>> +
> >>> +       /* initiate write operation */
> >>> +       writel(ULPI_RUN | ULPI_WRITE |
> >>> +              ULPI_ADDR(reg) | ULPI_DATA(val),
> >>> +              USB_ULPI_VIEWPORT);
> >>> +
> >>> +       /* wait for completion */
> >>> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> >>> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> >>> +                       break;
> >>> +               udelay(1);
> >>> +               cnt++;
> >>> +       }
> >>> +
> >>> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> >>> +               dev_err(otg->dev, "ulpi_write: timeout\n");
> >>> +               return -ETIMEDOUT;
> >>> +       }
> >>> +       return 0;
> >>> +}
> >>> +
> >>> +static struct otg_io_access_ops msm_otg_io_ops = {
> >>> +       .read = ulpi_read,
> >>> +       .write = ulpi_write,
> >>> +};
> >>> +
> >>> +static void ulpi_init(struct msm_otg *motg)
> >>> +{
> >>> +       struct msm_otg_platform_data *pdata = motg->pdata;
> >>> +       int *seq = pdata->phy_init_seq;
> >>> +
> >>> +       if (!seq)
> >>> +               return;
> >>> +
> >>> +       while (seq[0] >= 0) {
> >>> +               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
> >>> +                               seq[0], seq[1]);
> >>> +               ulpi_write(&motg->otg, seq[0], seq[1]);
> >>> +               seq += 2;
> >>> +       }
> >>> +}
> >>>
> >>>
> >>> can't you share the ulpi fonctions from udc and otg ?
> >> The best would be to use the usb/otg/ulpi.c driver for the ulpi access.
> >>
> > This driver will eventually use msm72k_otg.c transceiver.
> 
> Well, I mean, in addition to defining the struct otg_io_access_ops in some place,
> where both device and host drivers can share the same ops code, you can also
> use the ulpi generic driver as the protocol driver, instead of writing private code.

I have not looked at generic ULPI driver. I will see if we can re-use it in
our msm72k_otg.c.

> If the generic driver still lack some functionality, I can try to help you with this.
> 
Sure. Thanks for offering help.
-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-11  2:10           ` Pavan Kondeti
@ 2010-11-19  5:50             ` Pavan Kondeti
  2010-11-21  8:09               ` Igor Grinberg
  0 siblings, 1 reply; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-19  5:50 UTC (permalink / raw)
  To: Igor Grinberg
  Cc: Matthieu CASTET, greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

Hi Igor,

On Thu, Nov 11, 2010 at 07:40:28AM +0530, Pavan Kondeti wrote:
> Hi Igor,
> 
> On Wed, Nov 10, 2010 at 08:47:16AM +0200, Igor Grinberg wrote:
> >  On 11/10/10 04:19, Pavan Kondeti wrote:
> > > On Tue, Nov 09, 2010 at 05:36:28PM +0200, Igor Grinberg wrote:
> > >>
> > >> On 11/09/10 15:52, Matthieu CASTET wrote:
> > >>> Hi,
> > >>>
> > >>> Pavankumar Kondeti a écrit :
> > >>>
> > >>>> diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
> > >>>> new file mode 100644
> > >>>> index 0000000..3fa4192
> > >>>> --- /dev/null
> > >>>> +++ b/drivers/usb/gadget/msm72k_udc.c
> > >>>> +
> > >>>> +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) {
> > >>>> +               dev_err(&ui->pdev->dev, "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) {
> > >>>> +               dev_err(&ui->pdev->dev, "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) {
> > >>>> +               dev_vdbg(&ui->pdev->dev, "ulpi: write 0x%02x to 0x%02x\n",
> > >>>> +                               seq[0], seq[1]);
> > >>>> +               ulpi_write(ui, seq[0], seq[1]);
> > >>>> +               seq += 2;
> > >>>> +       }
> > >>>> +}
> > >>>> +
> > >>>
> > >>> --- /dev/null
> > >>> +++ b/drivers/usb/otg/msm72k_otg.c
> > >>>
> > >>> +
> > >>> +#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
> > >>> +static int ulpi_read(struct otg_transceiver *otg, u32 reg)
> > >>> +{
> > >>> +       int cnt = 0;
> > >>> +
> > >>> +       /* initiate read operation */
> > >>> +       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
> > >>> +              USB_ULPI_VIEWPORT);
> > >>> +
> > >>> +       /* wait for completion */
> > >>> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> > >>> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> > >>> +                       break;
> > >>> +               udelay(1);
> > >>> +               cnt++;
> > >>> +       }
> > >>> +
> > >>> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> > >>> +               dev_err(otg->dev, "ulpi_read: timeout %08x\n",
> > >>> +                       readl(USB_ULPI_VIEWPORT));
> > >>> +               return -ETIMEDOUT;
> > >>> +       }
> > >>> +       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
> > >>> +}
> > >>> +
> > >>> +static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
> > >>> +{
> > >>> +       int cnt = 0;
> > >>> +
> > >>> +       /* initiate write operation */
> > >>> +       writel(ULPI_RUN | ULPI_WRITE |
> > >>> +              ULPI_ADDR(reg) | ULPI_DATA(val),
> > >>> +              USB_ULPI_VIEWPORT);
> > >>> +
> > >>> +       /* wait for completion */
> > >>> +       while (cnt < ULPI_IO_TIMEOUT_USEC) {
> > >>> +               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
> > >>> +                       break;
> > >>> +               udelay(1);
> > >>> +               cnt++;
> > >>> +       }
> > >>> +
> > >>> +       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
> > >>> +               dev_err(otg->dev, "ulpi_write: timeout\n");
> > >>> +               return -ETIMEDOUT;
> > >>> +       }
> > >>> +       return 0;
> > >>> +}
> > >>> +
> > >>> +static struct otg_io_access_ops msm_otg_io_ops = {
> > >>> +       .read = ulpi_read,
> > >>> +       .write = ulpi_write,
> > >>> +};
> > >>> +
> > >>> +static void ulpi_init(struct msm_otg *motg)
> > >>> +{
> > >>> +       struct msm_otg_platform_data *pdata = motg->pdata;
> > >>> +       int *seq = pdata->phy_init_seq;
> > >>> +
> > >>> +       if (!seq)
> > >>> +               return;
> > >>> +
> > >>> +       while (seq[0] >= 0) {
> > >>> +               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
> > >>> +                               seq[0], seq[1]);
> > >>> +               ulpi_write(&motg->otg, seq[0], seq[1]);
> > >>> +               seq += 2;
> > >>> +       }
> > >>> +}
> > >>>
> > >>>
> > >>> can't you share the ulpi fonctions from udc and otg ?
> > >> The best would be to use the usb/otg/ulpi.c driver for the ulpi access.
> > >>
> > > This driver will eventually use msm72k_otg.c transceiver.
> > 
> > Well, I mean, in addition to defining the struct otg_io_access_ops in some place,
> > where both device and host drivers can share the same ops code, you can also
> > use the ulpi generic driver as the protocol driver, instead of writing private code.
> 
> I have not looked at generic ULPI driver. I will see if we can re-use it in
> our msm72k_otg.c.
> 
The generic ULPI driver seems to be supporting initializing the PHY,
configuring the PHY in Host mode and driving VBUS.

The PHY we have in our MSM chips does not have an integrated charge pump. So we
depend on external voltage regulators driver VBUS. So can not use ulpi_set_vbus
method.

IMO, ulpi_set_host is useful for only Hosts but not OTG (i.e support both gadget
and host). We kick OTG state machine only after both gadget and host are
registered. So we use our own set_host method and can not use ulpi_set_host.

-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-10  6:22             ` Brian Swetland
@ 2010-11-19 17:16               ` Matthieu CASTET
  2010-11-27 14:00                 ` Pavan Kondeti
  2010-12-07 12:44                 ` Pavan Kondeti
  0 siblings, 2 replies; 26+ messages in thread
From: Matthieu CASTET @ 2010-11-19 17:16 UTC (permalink / raw)
  To: Brian Swetland
  Cc: David Brownell, Pavan Kondeti, greg@kroah.com,
	linux-usb@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	Mike Lockwood

[-- Attachment #1: Type: text/plain, Size: 2019 bytes --]

Hi,

Brian Swetland a écrit :
> On Tue, Nov 9, 2010 at 6:54 PM, David Brownell <david-b@pacbell.net> wrote:
>>
>> --- On Tue, 11/9/10, Pavan Kondeti <pkondeti@codeaurora.org> wrote:
>>
>>>>> Hi Matthieu,
>>>>>
>>>>>> This look like the arc/chipidea/mips ehci otg
>>> core.
>>>>> Yes. It is chipidea core for ARM.
>>>>>> Why can't you reuse the ci13xxx_udc.c driver
>> That basic approach is FAR PREFERABLE.  Fix
>> the bugs once, tune once, and so forth, reuse
>> the ULPI support, etc.  Work on more
>> platforms, since the silicon IP is reused.
>>
>> You'll end up with more folk who can help
>> maintain the driver too, since the pool of
>> potential helpers won't be limited to those
>> who have/use MSM hardware.
>>
>> Just be sure to cleanly factor the bus
>> (PCI vs MSM-s ARM platform flavor and
>> SoC glues (bus-related).  That factoring
>> will likely be the hardest part; but there
>> are examples of similar stuff in Linux today.
> 
> The main headache is that this particular IP has different bugs in
> different instantiations (I know, for example, it exists in Tegra with
> a different set of issues around fetching descriptor heads and cache
> alignment, on MSM7201A after extensive testing we discovered there was
> no reliable way of adding a descriptor to a list of transactions once
> that queue was active, etc...), so things that work in one SoC may
> break another, etc, etc, but that's part of the adventure I suppose.
> I certainly agree that one unified driver is the way to go if you can
> make it all work.
> 
The best way to handle this is to introduce flags in the driver. For 
example look at drivers/mmc/host/sdhci.c (quirk flags).

But for now, let's make work msm version. We can add workaround for 
other controller later.

Now you should check if it is better to start on ci13xxx_udc or make 
generic your driver.

I had worked a bit on ci13xxx_udc, and the code is sometimes messy, hard 
to understand.
Also to making work on our core, we need to the attached patch.


Matthieu



[-- Attachment #2: diff --]
[-- Type: text/plain, Size: 1112 bytes --]

diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 0252bbc..5a65cda 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2140,6 +2140,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
 	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
 	int retval = 0;
 	unsigned long flags;
+	int empty;
 
 	trace("%p, %p, %X", ep, req, gfp_flags);
 
@@ -2170,15 +2171,18 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
 
 	dbg_queue(_usb_addr(mEp), req, retval);
 
+	empty = list_empty(&mEp->qh[mEp->dir].queue);
 	/* push request */
 	mReq->req.status = -EINPROGRESS;
 	mReq->req.actual = 0;
 	list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue);
 
-	retval = _hardware_enqueue(mEp, mReq);
-	if (retval == -EALREADY || retval == -EBUSY) {
-		dbg_event(_usb_addr(mEp), "QUEUE", retval);
-		retval = 0;
+	if (empty) {
+		retval = _hardware_enqueue(mEp, mReq);
+		if (retval == -EALREADY || retval == -EBUSY) {
+			dbg_event(_usb_addr(mEp), "QUEUE", retval);
+			retval = 0;
+		}
 	}
 
  done:

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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-19  5:50             ` Pavan Kondeti
@ 2010-11-21  8:09               ` Igor Grinberg
  0 siblings, 0 replies; 26+ messages in thread
From: Igor Grinberg @ 2010-11-21  8:09 UTC (permalink / raw)
  To: Pavan Kondeti
  Cc: Matthieu CASTET, greg@kroah.com, linux-usb@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, Mike Lockwood, Brian Swetland

 On 11/19/10 07:50, Pavan Kondeti wrote:
> Hi Igor,
>
> On Thu, Nov 11, 2010 at 07:40:28AM +0530, Pavan Kondeti wrote:
>> Hi Igor,
>>
>> On Wed, Nov 10, 2010 at 08:47:16AM +0200, Igor Grinberg wrote:
>>>  On 11/10/10 04:19, Pavan Kondeti wrote:
>>>> On Tue, Nov 09, 2010 at 05:36:28PM +0200, Igor Grinberg wrote:
>>>>> On 11/09/10 15:52, Matthieu CASTET wrote:
>>>>>> +static void ulpi_init(struct msm_otg *motg)
>>>>>> +{
>>>>>> +       struct msm_otg_platform_data *pdata = motg->pdata;
>>>>>> +       int *seq = pdata->phy_init_seq;
>>>>>> +
>>>>>> +       if (!seq)
>>>>>> +               return;
>>>>>> +
>>>>>> +       while (seq[0] >= 0) {
>>>>>> +               dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
>>>>>> +                               seq[0], seq[1]);
>>>>>> +               ulpi_write(&motg->otg, seq[0], seq[1]);
>>>>>> +               seq += 2;
>>>>>> +       }
>>>>>> +}
>>>>>>
>>>>>>
>>>>>> can't you share the ulpi fonctions from udc and otg ?
>>>>> The best would be to use the usb/otg/ulpi.c driver for the ulpi access.
>>>> This driver will eventually use msm72k_otg.c transceiver.
>>> Well, I mean, in addition to defining the struct otg_io_access_ops in some place,
>>> where both device and host drivers can share the same ops code, you can also
>>> use the ulpi generic driver as the protocol driver, instead of writing private code.
>> I have not looked at generic ULPI driver. I will see if we can re-use it in
>> our msm72k_otg.c.
> The generic ULPI driver seems to be supporting initializing the PHY,
> configuring the PHY in Host mode and driving VBUS.

Currently, yes, it is correct.
The reason I haven't added some more functionality
(e.g. set_peripheral()) is because I don't have a h/w that supports it.

> The PHY we have in our MSM chips does not have an integrated charge pump. So we
> depend on external voltage regulators driver VBUS. So can not use ulpi_set_vbus
> method.

You don't have to...
ulpi driver relies on otg_transceiver, so if you don't call otg_set_vbus(),
ulpi_set_vbus() will not be called and instead you can do your own set_vbus().

> IMO, ulpi_set_host is useful for only Hosts but not OTG (i.e support both gadget
> and host). We kick OTG state machine only after both gadget and host are
> registered. So we use our own set_host method and can not use ulpi_set_host.

IMHO, ULPI driver is not meant to somehow affect the OTG state machine.
I think the initial design of the ULPI driver was a mistake.
It should not have implemented the OTG transceiver, but only the communication
with the ULPI transceiver and implementation of the ULPI standard.
It should be used only for setting up/changing modes of ULPI transceivers.

It already has the ability to detect/check reliability of view port of the ULPI transceiver,
supply the wiring information to the ULPI transceiver.
I thought also of giving it the ability to reset the ULPI transceiver, and also add
set_peripheral() routine, but the h/w I have does not support peripheral mode
and does not need to reset the transceiver.
I can work on adding those, if someone find it useful.

Bottom line, I'd expect the communication with the ULPI transceiver handled by the
ULPI driver and the rest by the OTG implementation (core or platform).

-- 
Regards,
Igor.


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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-19 17:16               ` Matthieu CASTET
@ 2010-11-27 14:00                 ` Pavan Kondeti
  2010-11-28  6:30                   ` David Brownell
  2010-12-07 12:44                 ` Pavan Kondeti
  1 sibling, 1 reply; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-27 14:00 UTC (permalink / raw)
  To: Matthieu CASTET
  Cc: Brian Swetland, David Brownell, greg@kroah.com,
	linux-usb@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	Mike Lockwood

On 11/19/2010 10:46 PM, Matthieu CASTET wrote:
> Hi,
>
> Brian Swetland a écrit :
>> On Tue, Nov 9, 2010 at 6:54 PM, David Brownell <david-b@pacbell.net>
>> wrote:
>>>
>>> --- On Tue, 11/9/10, Pavan Kondeti <pkondeti@codeaurora.org> wrote:
>>>
>>>>>> Hi Matthieu,
>>>>>>
>>>>>>> This look like the arc/chipidea/mips ehci otg
>>>> core.
>>>>>> Yes. It is chipidea core for ARM.
>>>>>>> Why can't you reuse the ci13xxx_udc.c driver
>>> That basic approach is FAR PREFERABLE. Fix
>>> the bugs once, tune once, and so forth, reuse
>>> the ULPI support, etc. Work on more
>>> platforms, since the silicon IP is reused.
>>>
>>> You'll end up with more folk who can help
>>> maintain the driver too, since the pool of
>>> potential helpers won't be limited to those
>>> who have/use MSM hardware.
>>>
>>> Just be sure to cleanly factor the bus
>>> (PCI vs MSM-s ARM platform flavor and
>>> SoC glues (bus-related). That factoring
>>> will likely be the hardest part; but there
>>> are examples of similar stuff in Linux today.
>>
>> The main headache is that this particular IP has different bugs in
>> different instantiations (I know, for example, it exists in Tegra with
>> a different set of issues around fetching descriptor heads and cache
>> alignment, on MSM7201A after extensive testing we discovered there was
>> no reliable way of adding a descriptor to a list of transactions once
>> that queue was active, etc...), so things that work in one SoC may
>> break another, etc, etc, but that's part of the adventure I suppose.
>> I certainly agree that one unified driver is the way to go if you can
>> make it all work.
>>
> The best way to handle this is to introduce flags in the driver. For
> example look at drivers/mmc/host/sdhci.c (quirk flags).
>
> But for now, let's make work msm version. We can add workaround for
> other controller later.
>
I am working on separating PCI stuff from ci13xxx_udc driver and 
implementing specific hooks needed for MSM. I am relying on 
gadget_is_xxx() macro for MSM specific workarounds.

-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-27 14:00                 ` Pavan Kondeti
@ 2010-11-28  6:30                   ` David Brownell
  2010-11-28 12:09                     ` Pavan Kondeti
  0 siblings, 1 reply; 26+ messages in thread
From: David Brownell @ 2010-11-28  6:30 UTC (permalink / raw)
  To: Pavan Kondeti
  Cc: Matthieu CASTET, Brian Swetland, greg@kroah.com,
	linux-usb@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	Mike Lockwood


> implementing specific hooks needed for MSM. I am relying on 
> gadget_is_xxx() macro for MSM specific workarounds.

NEVER DO THAT from inside controller drivers.

(If the code isn't specific to the msm silicon, and works on
other vendors' implementations too, it'd misbehave anyway.

Those calls are for gadget drivers, e.g. to embed knowledge about
controller issues which can't be detected by looking at
what's advertised by the gadget controller device.  Using them isn't
encouraged.


Controller drivers should see what hardware they're talking to by
actually talking to the chip  and detecting any quirks (be they
revision-specific or otherwise).  In some cases platform_data will
be the way to package such information.

- Dave



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

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-28  6:30                   ` David Brownell
@ 2010-11-28 12:09                     ` Pavan Kondeti
  0 siblings, 0 replies; 26+ messages in thread
From: Pavan Kondeti @ 2010-11-28 12:09 UTC (permalink / raw)
  To: David Brownell
  Cc: Matthieu CASTET, Brian Swetland, greg@kroah.com,
	linux-usb@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	Mike Lockwood

Hi Dave,

On 11/28/2010 12:00 PM, David Brownell wrote:
>
>> implementing specific hooks needed for MSM. I am relying on
>> gadget_is_xxx() macro for MSM specific workarounds.
>
> NEVER DO THAT from inside controller drivers.

Here we are using the macro in ci13xxx_udc core which is included by
two gadget controller drivers.

>
> (If the code isn't specific to the msm silicon, and works on
> other vendors' implementations too, it'd misbehave anyway.
>
> Those calls are for gadget drivers, e.g. to embed knowledge about
> controller issues which can't be detected by looking at
> what's advertised by the gadget controller device.  Using them isn't
> encouraged.
>
>
> Controller drivers should see what hardware they're talking to by
> actually talking to the chip  and detecting any quirks (be they
> revision-specific or otherwise).  In some cases platform_data will
> be the way to package such information.
>

We need the following hooks/extension in ci13xxx_udc for MSM SoC.

1. MSM USB device controller depends on OTG driver for clocks, Low power 
mode,
and PHY initialization. So udc_probe() must fail if 
otg_get_transceiver() fails.
2. By default streaming mode is enabled in ci13xxx controller. It has to be
disabled due to some known issues.
3. Currently, pull-up is enabled upon gadget driver registration. But we 
want
to enable only upon VBUS presence. also controller must be reset before 
enabling
the pull-up as the controller was in host mode before.
4. Hardware registers should not be accessed in udc_probe()

I have started with flags to achieve the above and ended up with following:

TRANSCEIVER_IS_REQUIRED: Fail udc_probe() if otg_get_transceiver() == NULL
SKIP_RESET_IN_PROBE: avoid resetting the hardware in udc_prob()
ENABLE_PULLUP_UPON_VBUS: Enable pull-up upon VBUS
RESET_BEFORE_PULLUP: Reset the hardware before pull-up
DISABLE_STREAM_MODE: Disable streaming mode
A post reset callback to write into special registers after reset

I thought introducing this many flags may not be a good idea and used 
gadget_is_xxx()
macro to achieve the same. if tomorrow, some gadget controller wants to 
fail udc_probe()
if otg_get_tranceiver(), they can too OR their gadget_is_xxx() macro. If 
you say using
flags is not _bad_, I will take that approach.

Thanks,
Pavan

-- 
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] 26+ messages in thread

* Re: [PATCH v2] USB: Add MSM USB Device Controller driver
  2010-11-19 17:16               ` Matthieu CASTET
  2010-11-27 14:00                 ` Pavan Kondeti
@ 2010-12-07 12:44                 ` Pavan Kondeti
  1 sibling, 0 replies; 26+ messages in thread
From: Pavan Kondeti @ 2010-12-07 12:44 UTC (permalink / raw)
  To: Matthieu CASTET
  Cc: Brian Swetland, David Brownell, greg@kroah.com,
	linux-usb@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	Mike Lockwood

Hi Matthieu,

On 11/19/2010 10:46 PM, Matthieu CASTET wrote:
> The best way to handle this is to introduce flags in the driver. For 
> example look at drivers/mmc/host/sdhci.c (quirk flags).
> 
> But for now, let's make work msm version. We can add workaround for 
> other controller later.
> 
> Now you should check if it is better to start on ci13xxx_udc or make 
> generic your driver.
> 
> I had worked a bit on ci13xxx_udc, and the code is sometimes messy, hard 
> to understand.
> Also to making work on our core, we need to the attached patch.
> 
> 

ci13xxx_udc is working fine on MSM SoC without the attached patch.
According to hardware doc, When endpoint is in primed state the
corresponding bit of either ENDPTRPIME or ENDPTSTAT will be set. The
driver is assuming the same. So I don't see a problem.

The current driver, one dTD is given to the hardware at a time. We can
improve it by adding hardware queuing functionality or adopt msm72k_udc
algorithm.

I have submitted patches to separate PCI stuff out of ci13xxx_udc. I
have submitted MSM bus glue driver which makes use of ci13xxx_udc. I
have tested it on MSM SoC. But I don't have ci13xxx PCI hardware. Can
you help me in testing my patches (5-11 of [PATCH V3 00/11] Add MSM USB
controller driver)

Thanks in advance,
Pavan


-- 
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] 26+ messages in thread

end of thread, other threads:[~2010-12-07 12:45 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-11-09 11:18 [PATCH v2] Add MSM USB Device Controller support Pavankumar Kondeti
2010-11-09 11:18 ` [PATCH v2] USB: Add MSM USB Device Controller driver Pavankumar Kondeti
2010-11-09 11:40   ` Matthieu CASTET
2010-11-09 12:16     ` Pavan Kondeti
2010-11-09 13:36       ` Matthieu CASTET
2010-11-10  2:12         ` Pavan Kondeti
2010-11-10  2:54           ` David Brownell
2010-11-10  6:22             ` Brian Swetland
2010-11-19 17:16               ` Matthieu CASTET
2010-11-27 14:00                 ` Pavan Kondeti
2010-11-28  6:30                   ` David Brownell
2010-11-28 12:09                     ` Pavan Kondeti
2010-12-07 12:44                 ` Pavan Kondeti
2010-11-09 13:25   ` Heikki Krogerus
2010-11-09 13:52   ` Matthieu CASTET
2010-11-09 15:36     ` Igor Grinberg
2010-11-10  2:19       ` Pavan Kondeti
2010-11-10  6:47         ` Igor Grinberg
2010-11-11  2:10           ` Pavan Kondeti
2010-11-19  5:50             ` Pavan Kondeti
2010-11-21  8:09               ` Igor Grinberg
2010-11-10  2:17     ` Pavan Kondeti
2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add debugfs support Pavankumar Kondeti
2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add Remote wakeup support Pavankumar Kondeti
2010-11-09 11:18 ` [PATCH v2] USB: msm72k_udc: Add Test Mode support Pavankumar Kondeti
2010-11-09 11:18 ` [PATCH] USB: msm72k_udc: Add charging notification support Pavankumar Kondeti

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).