Hi, thanks for the .config, that helped getting my dev system setup a lot.
Anyway, attached is a backport against the android-msm-htc-2.6.25 branch; I
can't guarantee it'll work properly as the kernel EHCI stack has definitely
changed a bit since .25. It compiles though, what more testing do we need?
:)

I'm only going to support the standard linux USB host + gadget frameworks:
that's what all the linux USB OTG support is based on, and I can't be
bothered porting all that to the android specific USB_FUNCTION stuff. If
someone else does though, I've no objections!

I'm going to start reading up on OTG drivers to take this beyond the
prototype stage.

-- 
unsubscribe: android-kernel+unsubscr...@googlegroups.com
website: http://groups.google.com/group/android-kernel
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index b51b307..d2006d3 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -55,6 +55,7 @@ config USB_ARCH_HAS_EHCI
 	default y if PPC_83xx
 	default y if SOC_AU1200
 	default y if ARCH_IXP4XX
+	default y if ARCH_MSM7X00A
 	default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
diff --git a/drivers/usb/function/Kconfig b/drivers/usb/function/Kconfig
index 7e5d043..58384ff 100644
--- a/drivers/usb/function/Kconfig
+++ b/drivers/usb/function/Kconfig
@@ -14,7 +14,7 @@ choice
 	
 config USB_FUNCTION_MSM_HSUSB
 	boolean "MSM7K Highspeed USB Peripheral Controller"
-	depends on ARCH_MSM7X00A
+	depends on ARCH_MSM7X00A && (!USB_EHCI_MSM7201)
 
 endchoice
 
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index bf8be2a..02b6547 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -75,6 +75,13 @@ config USB_EHCI_FSL
 	---help---
 	  Variation of ARC USB block used in some Freescale chips.
 
+config USB_EHCI_MSM7201
+	bool "Support for Qualcomm MSM7201 on-chip EHCI USB controller"
+	depends on USB_EHCI_HCD && ARCH_MSM7X00A && (!USB_FUNCTION)
+	select USB_EHCI_ROOT_HUB_TT
+	---help---
+	  Variation of ARC USB block used in Qualcomm MSM7201 chips.
+
 config USB_EHCI_HCD_PPC_OF
 	bool "EHCI support for PPC USB controller on OF platform bus"
 	depends on USB_EHCI_HCD && PPC_OF
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 46ee7f4..5926e86 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1043,6 +1043,11 @@ MODULE_LICENSE ("GPL");
 #define	PLATFORM_DRIVER		ixp4xx_ehci_driver
 #endif
 
+#ifdef CONFIG_ARCH_MSM7X00A
+#include "ehci-msm7201.c"
+#define	PLATFORM_DRIVER		ehci_msm7201_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
 #error "missing bus glue for ehci-hcd"
diff --git a/drivers/usb/host/ehci-msm7201.c b/drivers/usb/host/ehci-msm7201.c
new file mode 100644
index 0000000..621c714
--- /dev/null
+++ b/drivers/usb/host/ehci-msm7201.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2010 Andrew de Quincey
+ *
+ * (heavily) based on ehci-fsl.c, which is:
+ * 
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Ported to 834x by Randy Vinson <rvin...@mvista.com> using code provided
+ * by Hunter Wu.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/msm_hsusb.h>
+
+#include "ehci-msm7201.h"
+
+static void ulpi_write(struct usb_hcd *hcd, 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)
+		printk(KERN_WARNING "%s: timeout: reg: 0x%X, var: 0x%X\n",
+		__func__, reg, val);
+}
+
+static void msm7201_setup_phy(struct usb_hcd *hcd)
+{
+	struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+
+  	int *seq = msm7201->phy_init_seq;
+
+	if (!seq)
+		return;
+
+	while (seq[0] >= 0) {
+		ulpi_write(hcd, seq[0], seq[1]);
+		seq += 2;
+	}
+}
+
+static void msm7201_shutdown_phy(struct usb_hcd *hcd)
+{
+	struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+	
+	/* disable interface protect circuit to drop current consumption */
+	ulpi_write(hcd, (1 << 7), 0x08);
+	/* clear the SuspendM bit -> suspend the PHY */
+	ulpi_write(hcd, 1 << 6, 0x06);
+}
+
+static void msm7201_usb_setup(struct usb_hcd *hcd)
+{
+	struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+	int i;
+
+	/* INCR8 BURST mode */
+	writel(0x02, USB_SBUSCFG);	/*boost performance to fix CRC error.*/
+
+	/* select ULPI phy */
+	writel(0x80000000, USB_PORTSC);
+
+	if (msm7201->phy_reset)
+		msm7201->phy_reset();
+	msm7201_setup_phy(hcd);
+}
+
+/* called after powerup, by probe or system-pm "wakeup" */
+static int ehci_msm7201_reinit(struct ehci_hcd *ehci)
+{
+	msm7201_usb_setup(ehci_to_hcd(ehci));
+	ehci_port_power(ehci, 0);
+
+	return 0;
+}
+
+/* called during probe() after chip reset completes */
+static int ehci_msm7201_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int retval;
+
+	/* EHCI registers start at offset 0x100 */
+	ehci->caps = hcd->regs + 0x100;
+	ehci->regs = hcd->regs + 0x100 +
+	    HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+	/* configure other settings */
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+	ehci->is_tdi_rh_tt = 1;
+	ehci->sbrn = 0x20;
+
+	/* reset and halt controller */
+	ehci_reset(ehci);
+	retval = ehci_halt(ehci);
+	if (retval)
+		return retval;
+
+	/* data structure init */
+	retval = ehci_init(hcd);
+	if (retval)
+		return retval;
+        
+	ehci_reset(ehci);
+
+	retval = ehci_msm7201_reinit(ehci);
+	return retval;
+}
+
+static const struct hc_driver ehci_msm7201_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "Qualcomm MSM7201 On-Chip EHCI Host Controller",
+	.hcd_priv_size = sizeof(struct ehci_hcd) + sizeof(struct msm7201_usb_priv),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_USB2 | HCD_MEMORY | HCD_LOCAL_MEM,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = ehci_msm7201_setup,
+	.start = ehci_run,
+	.stop = ehci_stop,
+	.shutdown = ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ehci_urb_enqueue,
+	.urb_dequeue = ehci_urb_dequeue,
+	.endpoint_disable = ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ehci_hub_status_data,
+	.hub_control = ehci_hub_control,
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
+	.relinquish_port = ehci_relinquish_port,
+};
+
+/**
+ * usb_hcd_msm7201_remove - shutdown processing for MSM7201-based HCDs
+ * @pdev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_msm7201_probe().
+ *
+ */
+static int usb_hcd_msm7201_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd);
+
+	usb_remove_hcd(hcd);
+	msm7201_shutdown_phy(hcd);
+	clk_put(msm7201->clk);
+	clk_put(msm7201->pclk);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	
+	return 0;
+}
+
+/**
+ * usb_hcd_msm7201_probe - initialize MSM7201-based HCDs
+ * @pdev: USB Host Controller being probed
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller.
+ *
+ */
+static int usb_hcd_msm7201_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct resource *res;
+	struct msm7201_usb_priv *msm7201;
+	int irq;
+	int retval;
+	const struct hc_driver *driver = &ehci_msm7201_hc_driver;
+	struct msm_hsusb_platform_data *pdata = pdev->dev.platform_data;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	pr_debug("initializing MSM7201 USB Controller\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no IRQ. Check %s setup!\n",
+			pdev->dev.bus_id);
+		return -ENODEV;
+	}
+	irq = res->start;
+
+	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto err1;
+	}
+	
+	msm7201 = hcd_to_msm7201(hcd);
+	if (pdata) {
+		msm7201->phy_reset = pdata->phy_reset;
+		msm7201->phy_init_seq = pdata->phy_init_seq;
+	}
+	
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no register addr. Check %s setup!\n",
+			pdev->dev.bus_id);
+		retval = -ENODEV;
+		goto err2;
+	}
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = res->end - res->start + 1;
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+				driver->description)) {
+		dev_dbg(&pdev->dev, "controller already in use\n");
+		retval = -EBUSY;
+		goto err2;
+	}
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+
+	if (hcd->regs == NULL) {
+		dev_dbg(&pdev->dev, "error mapping memory\n");
+		retval = -EFAULT;
+		goto err3;
+	}
+	
+	msm7201->clk = clk_get(&pdev->dev, "usb_hs_clk");
+	if (IS_ERR(msm7201->clk)) {
+		dev_dbg(&pdev->dev, "error getting usb_hs_clk\n");
+		retval = -EFAULT;
+		goto err4;	  
+	}
+
+	msm7201->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
+	if (IS_ERR(msm7201->pclk)) {
+		dev_dbg(&pdev->dev, "error getting usb_hs_pclk\n");
+		retval = -EFAULT;
+		goto err5;	  
+	}
+
+        clk_enable(msm7201->clk);
+        clk_enable(msm7201->pclk);
+
+        /* wait for a while after enable usb clk*/
+        msleep(5);
+
+	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+	if (retval != 0)
+		goto err6;
+	return retval;
+
+      err6:
+	clk_put(msm7201->pclk);
+      err5:
+	clk_put(msm7201->clk);
+      err4:
+	iounmap(hcd->regs);	
+      err3:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+      err2:
+	usb_put_hcd(hcd);
+      err1:
+	dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
+	return retval;
+}
+
+MODULE_ALIAS("platform:msm_hsusb");
+
+static struct platform_driver ehci_msm7201_driver = {
+	.probe = usb_hcd_msm7201_probe,
+	.remove = usb_hcd_msm7201_remove,
+	.shutdown = usb_hcd_platform_shutdown,
+	.driver = {
+		   .name = "msm_hsusb",
+	},
+};
diff --git a/drivers/usb/host/ehci-msm7201.h b/drivers/usb/host/ehci-msm7201.h
new file mode 100644
index 0000000..5824e21
--- /dev/null
+++ b/drivers/usb/host/ehci-msm7201.h
@@ -0,0 +1,88 @@
+/* 
+ * Copyright (c) 2010 Andrew de Quincey
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _EHCI_MSM7201_H
+#define _EHCI_MSM7201_H
+
+struct msm7201_usb_priv 
+{
+	struct clk *clk;
+	struct clk *pclk;
+
+	int *phy_init_seq;
+	void (*phy_reset)(void);
+	void (*phy_shutdown)(void);
+};
+
+static inline struct msm7201_usb_priv *hcd_to_msm7201(struct usb_hcd *hcd)
+{
+	return (struct msm7201_usb_priv *) (hcd->hcd_priv) + sizeof(struct ehci_hcd);
+}
+
+#define MSM_USB_BASE	     ((unsigned) hcd->regs)
+
+#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)
+#define USB_SBUSCFG          (MSM_USB_BASE + 0x0090)
+
+#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
+
+#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)
+
+#endif				/* _EHCI_MSM7201_H */

Reply via email to