# HG changeset patch
# User Matt Mackall <mpm@selenic.com>
# Date 1249942085 18000
# Node ID 9dfaf7cffafc6ff2b76a7c388abf2e8826879c70
# Parent  953d9a779cd8d3ef2b30803ee70cd83c8806830f
imported patch comcerto-usb

diff -r 953d9a779cd8 -r 9dfaf7cffafc drivers/usb/Kconfig
--- a/drivers/usb/Kconfig	Mon Aug 10 17:08:05 2009 -0500
+++ b/drivers/usb/Kconfig	Mon Aug 10 17:08:05 2009 -0500
@@ -54,6 +54,7 @@
 # some non-PCI hcds implement EHCI
 config USB_ARCH_HAS_EHCI
 	boolean
+	default y if (ARCH_M821XX || ARCH_M822XX)
 	default y if PPC_83xx
 	default y if SOC_AU1200
 	default y if ARCH_IXP4XX
diff -r 953d9a779cd8 -r 9dfaf7cffafc drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Mon Aug 10 17:08:05 2009 -0500
+++ b/drivers/usb/host/ehci-hcd.c	Mon Aug 10 17:08:05 2009 -0500
@@ -1037,7 +1037,7 @@
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_LICENSE ("GPL");
 
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && (!defined(CONFIG_ARCH_M821XX) && !defined(CONFIG_ARCH_M822XX))
 #include "ehci-pci.c"
 #define	PCI_DRIVER		ehci_pci_driver
 #endif
@@ -1052,6 +1052,11 @@
 #define	PLATFORM_DRIVER		ehci_hcd_au1xxx_driver
 #endif
 
+#if defined(CONFIG_ARCH_M821XX) || defined(CONFIG_ARCH_M822XX)
+#include "ehci-m821xx.c"
+#define	PLATFORM_DRIVER		ehci_hcd_m821xx_driver
+#endif
+
 #ifdef CONFIG_PPC_PS3
 #include "ehci-ps3.c"
 #define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_driver
diff -r 953d9a779cd8 -r 9dfaf7cffafc drivers/usb/host/ehci-m821xx.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/usb/host/ehci-m821xx.c	Mon Aug 10 17:08:05 2009 -0500
@@ -0,0 +1,257 @@
+/*
+ *  linux/drivers/usb/host/ehci-m821xx.c
+ *
+ *  Copyright (C) Mindspeed Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void m821xx_start_ehc(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "Starting M821xx EHCI USB Controller\n");
+	/* Enable Clock to USB Controller */
+	if(pdev->id == 1) {
+		  // Enable Clock to USB Port 0
+		 *(volatile u32 *)COMCERTO_CLK_CLK_PWR_DWN &= ~USB0_AHBCLK_PD;
+		  // de-activate USB port 0 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  |= USB0_RST; 
+		    // de-activate USB phy 0 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  |= USB0_PHY_RST; 
+		// taking usb phy out of suspend
+		//*(volatile int *)COMCERTO_GPIO_GENERAL_CONTOL_REG  &= 0x2;
+	
+	} else if (pdev->id == 2 ) {
+		  // Enable Clock to USB Port 1
+		 *(volatile u32 *)COMCERTO_CLK_CLK_PWR_DWN &= ~USB1_AHBCLK_PD;
+		  // de-activate USB port 1 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  |= USB1_RST; 
+		    // de-activate USB phy 1 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  |= USB1_PHY_RST; 	
+		// taking usb phy out of suspend
+		//*(volatile int *)COMCERTO_GPIO_GENERAL_CONTOL_REG  &= ~0x8;	
+	}
+}
+
+static void m821xx_stop_ehc(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "Stopping M821xx EHCI USB Controller\n");
+
+	/* Disable Clock to USB Controller */
+	if(pdev->id == 1) {
+		  // disable Clock to USB Port 0
+		 *(volatile u32 *)COMCERTO_CLK_CLK_PWR_DWN |= USB0_AHBCLK_PD;
+		  // activate USB port 0 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  &= ~USB0_RST; 
+		    // activate USB phy 0 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  &= ~USB0_PHY_RST; 
+	} else if (pdev->id == 2 ) {
+		  // disable Clock to USB Port 1
+		 *(volatile u32 *)COMCERTO_CLK_CLK_PWR_DWN |= USB1_AHBCLK_PD;
+		  // activate USB port 1 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  &= ~USB1_RST; 
+		    // activate USB phy 1 reset
+		 *(volatile u32 *)COMCERTO_BLOCK_RESET_REG  &= ~USB1_PHY_RST; 
+	} 
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_ehci_m821xx_probe - initialize M821xx HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_ehci_m821xx_probe(const struct hc_driver *driver,
+			  struct platform_device *pdev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+	struct ehci_hcd *ehci;
+
+	if (pdev->num_resources != 2) {
+		dev_err(&pdev->dev,"HCD %s probe: invalid num_resources: %i\n", 
+			dev_name(&pdev->dev),pdev->num_resources);
+		return -ENODEV;
+	}
+
+	if (pdev->resource[0].flags != IORESOURCE_MEM 
+	    || pdev->resource[1].flags != IORESOURCE_IRQ) {
+		dev_err(&pdev->dev,"HCD %s probe: invalid resource type\n",dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+
+	m821xx_start_ehc(pdev);
+
+	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = pdev->resource[0].start;
+	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) {
+		dev_dbg(&pdev->dev, "request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_dbg(&pdev->dev, "ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	ehci = hcd_to_ehci(hcd);
+	ehci->caps = hcd->regs + 0x100;
+	ehci->regs = hcd->regs + 0x100 + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+	hcd->has_tt =1;
+
+	tdi_reset(ehci);
+	ehci_reset(ehci);
+	ehci->sbrn = 0x20; //just fool it
+
+	retval =
+	    usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
+	if (retval == 0)
+		return retval;
+
+	m821xx_stop_ehc(pdev);
+	iounmap(hcd->regs);
+err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_ehci_hcd_m821xx_remove - shutdown processing for M821xx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_m821xx_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_ehci_m821xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	m821xx_stop_ehc(pdev);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_m821xx_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "M821xx EHCI",
+	.hcd_priv_size = sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = ehci_init,
+	.start = ehci_run,
+#ifdef	CONFIG_PM
+	.suspend = ehci_bus_suspend,
+	.resume = ehci_bus_resume,
+#endif
+	.stop = ehci_stop,
+
+	/*
+	 * 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,
+#ifdef	CONFIG_PM
+	.hub_suspend = ehci_hub_suspend,
+	.hub_resume = ehci_hub_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hcd_m821xx_drv_probe(struct platform_device *dev)
+{
+	pr_debug("In ehci_hcd_m821xx_drv_probe\n");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	return usb_ehci_m821xx_probe(&ehci_m821xx_hc_driver, dev);
+
+}
+
+static int ehci_hcd_m821xx_drv_remove(struct platform_device *dev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+	usb_ehci_m821xx_remove(hcd, dev);
+
+	return 0;
+
+}
+
+MODULE_ALIAS("m821xx-ehci");
+static struct platform_driver ehci_hcd_m821xx_driver = {
+	.probe = ehci_hcd_m821xx_drv_probe,
+	.remove = ehci_hcd_m821xx_drv_remove,
+	.shutdown = usb_hcd_platform_shutdown,
+	/*.suspend      = ehci_hcd_m821xx_drv_suspend, */
+	/*.resume       = ehci_hcd_m821xx_drv_resume, */
+	.driver = {
+		.name = "m821xx-ehci",
+		.bus = &platform_bus_type
+	}
+};
+
