USB: renamed ehci-rk.c -> ehci-rkhsic.c for support HSIC and EHCI
authorwlf <wulf@rock-chips.com>
Tue, 4 Mar 2014 07:30:07 +0000 (15:30 +0800)
committerwlf <wulf@rock-chips.com>
Tue, 4 Mar 2014 07:30:07 +0000 (15:30 +0800)
drivers/usb/dwc_otg_310/usbdev_rk30.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-rk.c
drivers/usb/host/ehci-rkhsic.c [new file with mode: 0755]

index e994e8a1ec86d9bc53bd43e1e4af979950390b5b..447a723eb9c9f1c7c5a22e1353e7f0267f458a3b 100755 (executable)
@@ -283,7 +283,7 @@ struct dwc_otg_platform_data usb20host_pdata = {
 };
 #endif
 
-#ifdef CONFIG_USB_EHCI_RK
+#ifdef CONFIG_USB_EHCI_RKHSIC
 void rk_hsic_hw_init(void)
 {
        unsigned int * phy_con0 = (control_usb->grf_uoc0_base);
index cbb1c88a471b340b2ca691fc99760aafd686a073..f70e0f0af0b3ccb3195161ea9d73fcc0137df523 100644 (file)
@@ -100,12 +100,19 @@ config USB_FSL_MPH_DR_OF
 
 if USB_EHCI_HCD
 
-config USB_EHCI_RK
+config USB_EHCI_RKHSIC
        tristate "Rockchip EHCI HSIC support"
        select USB_EHCI_ROOT_HUB_TT
-       default y
+       default n
+       ---help---
+               Enables support for the HSIC USB controller on the RK platform.
+
+config USB_EHCI_RK
+       tristate "Rockchip EHCI HOST20 support"
+       select USB_EHCI_ROOT_HUB_TT
+       default n
        ---help---
-               Enables support for the HSIC USB controller on the RK platform
+               Enables support EHCI for RK3288 and later chips.
 
 config USB_EHCI_PCI
        tristate
index 4517d22dc73d84530d37d37650f01b6deac4f4cb..a17d73217e6547906c30fa012263b63c8735b9c0 100644 (file)
@@ -1266,6 +1266,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER         ehci_rk_driver
 #endif
 
+#ifdef CONFIG_USB_EHCI_RKHSIC
+#include "ehci-rkhsic.c"
+#define PLATFORM_DRIVER         ehci_rkhsic_driver
+#endif
+
 #ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
 #include "ehci-pmcmsp.c"
 #define        PLATFORM_DRIVER         ehci_hcd_msp_driver
index db8fb507f8013511f65b36f2173fa6991c9d01f2..9b6fae73c0c192318162ddab17c83c3355a3354d 100755 (executable)
-/* ehci-msm.c - HSUSB Host Controller Driver Implementation\r
- *\r
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.\r
- *\r
- * Partly derived from ehci-fsl.c and ehci-hcd.c\r
- * Copyright (c) 2000-2004 by David Brownell\r
- * Copyright (c) 2005 MontaVista Software\r
- *\r
- * All source code in this file is licensed under the following license except\r
- * where indicated.\r
- *\r
- * This program is free software; you can redistribute it and/or modify it\r
- * under the terms of the GNU General Public License version 2 as published\r
- * by the Free Software Foundation.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r
- *\r
- * See the GNU General Public License for more details.\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, you can find it at http://www.fsf.org\r
- */\r
-\r
-# include <linux/platform_device.h>\r
-# include <linux/clk.h>\r
-# include <linux/err.h>\r
-# include <linux/device.h>\r
-# include <linux/of.h>\r
-# include <linux/of_platform.h>\r
-# include "ehci.h"\r
-#ifdef CONFIG_DWC_OTG_274\r
-# include "../dwc_otg/usbdev_rk.h"\r
-#endif\r
-#ifdef CONFIG_DWC_OTG_310\r
-# include "../dwc_otg_310/usbdev_rk.h"\r
-#endif\r
-\r
-static int rkehci_status = 1;\r
-static struct ehci_hcd *g_ehci;\r
-#define EHCI_DEVICE_FILE        "/sys/devices/platform/rk_hsusb_host/ehci_power"\r
-#define EHCI_PRINT(x...)       printk( KERN_INFO "EHCI: " x )\r
-\r
-extern struct rkehci_platform_data rkhsic_pdata;\r
-\r
-static void ehci_port_power (struct ehci_hcd *ehci, int is_on)\r
-{\r
-       unsigned port;\r
-\r
-       if (!HCS_PPC (ehci->hcs_params))\r
-               return;\r
-\r
-       ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");\r
-       for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )\r
-               (void) ehci_hub_control(ehci_to_hcd(ehci),\r
-                               is_on ? SetPortFeature : ClearPortFeature,\r
-                               USB_PORT_FEAT_POWER,\r
-                               port--, NULL, 0);\r
-       /* Flush those writes */\r
-       ehci_readl(ehci, &ehci->regs->command);\r
-       msleep(20);\r
-}\r
-\r
-static struct hc_driver rk_hc_driver = {\r
-       .description            = hcd_name,\r
-       .product_desc           = "Rockchip On-Chip EHCI Host Controller",\r
-       .hcd_priv_size          = sizeof(struct ehci_hcd),\r
-\r
-       /*\r
-        * generic hardware linkage\r
-        */\r
-       .irq                    = ehci_irq,\r
-       .flags                  = HCD_USB2 | HCD_MEMORY,\r
-\r
-       .reset                  = ehci_init,\r
-       .start                  = ehci_run,\r
-\r
-       .stop                   = ehci_stop,\r
-       .shutdown               = ehci_shutdown,\r
-\r
-       /*\r
-        * managing i/o requests and associated device resources\r
-        */\r
-       .urb_enqueue            = ehci_urb_enqueue,\r
-       .urb_dequeue            = ehci_urb_dequeue,\r
-       .endpoint_disable       = ehci_endpoint_disable,\r
-       .endpoint_reset         = ehci_endpoint_reset,\r
-       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,\r
-\r
-       /*\r
-        * scheduling support\r
-        */\r
-       .get_frame_number       = ehci_get_frame,\r
-\r
-       /*\r
-        * root hub support\r
-        */\r
-       .hub_status_data        = ehci_hub_status_data,\r
-       .hub_control            = ehci_hub_control,\r
-       .relinquish_port        = ehci_relinquish_port,\r
-       .port_handed_over       = ehci_port_handed_over,\r
-\r
-       /*\r
-        * PM support\r
-        */\r
-#ifdef CONFIG_PM\r
-       .bus_suspend            = ehci_bus_suspend,\r
-       .bus_resume             = ehci_bus_resume,\r
-#endif\r
-};\r
-\r
-static ssize_t ehci_power_show( struct device *_dev, \r
-                               struct device_attribute *attr, char *buf) \r
-{\r
-       return sprintf(buf, "%d\n", rkehci_status);\r
-}\r
-static ssize_t ehci_power_store( struct device *_dev,\r
-                                       struct device_attribute *attr, \r
-                                       const char *buf, size_t count ) \r
-{\r
-       uint32_t val = simple_strtoul(buf, NULL, 16);\r
-       struct usb_hcd *hcd = dev_get_drvdata(_dev);\r
-       struct ehci_hcd *ehci = hcd_to_ehci(hcd);\r
-       struct rkehci_platform_data *pldata = _dev->platform_data;\r
-\r
-       printk("%s: %d setting to: %d\n", __func__, rkehci_status, val);\r
-       if(val == rkehci_status)\r
-               goto out;\r
-       \r
-       rkehci_status = val;\r
-       switch(val){\r
-               case 0: //power down\r
-                       ehci_port_power(ehci, 0);\r
-                       writel_relaxed(0 ,hcd->regs +0xb0);\r
-                       dsb();\r
-                       msleep(5);\r
-                       usb_remove_hcd(hcd);\r
-                       break;\r
-               case 1: // power on\r
-                       pldata->soft_reset();\r
-                       usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);\r
-        \r
-                       ehci_port_power(ehci, 1);\r
-                       writel_relaxed(1 ,hcd->regs +0xb0);\r
-                       writel_relaxed(0x1d4d ,hcd->regs +0x90);\r
-                       writel_relaxed(0x4 ,hcd->regs +0xa0);\r
-                       dsb();\r
-                       break;\r
-               default:\r
-                       break;\r
-       }\r
-out:\r
-       return count;\r
-}\r
-static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store);\r
-\r
-static ssize_t debug_show( struct device *_dev,\r
-                               struct device_attribute *attr, char *buf)\r
-{\r
-       volatile uint32_t *addr;\r
-\r
-       EHCI_PRINT("******** EHCI Capability Registers **********\n");\r
-       addr = &g_ehci->caps->hc_capbase;\r
-       EHCI_PRINT("HCIVERSION / CAPLENGTH  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->caps->hcs_params;\r
-       EHCI_PRINT("HCSPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->caps->hcc_params;\r
-       EHCI_PRINT("HCCPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       EHCI_PRINT("********* EHCI Operational Registers *********\n");\r
-       addr = &g_ehci->regs->command;\r
-       EHCI_PRINT("USBCMD                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->regs->status;\r
-       EHCI_PRINT("USBSTS                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->regs->intr_enable;\r
-       EHCI_PRINT("USBINTR                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->regs->frame_index;\r
-       EHCI_PRINT("FRINDEX                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->regs->segment;\r
-       EHCI_PRINT("CTRLDSSEGMENT           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->regs->frame_list;\r
-       EHCI_PRINT("PERIODICLISTBASE        @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); \r
-       addr = &g_ehci->regs->async_next;\r
-       EHCI_PRINT("ASYNCLISTADDR           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = &g_ehci->regs->configured_flag;\r
-       EHCI_PRINT("CONFIGFLAG              @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       addr = g_ehci->regs->port_status;\r
-       EHCI_PRINT("PORTSC                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));\r
-       return sprintf(buf, "EHCI Registers Dump\n");\r
-}\r
-static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL);\r
-\r
-static int ehci_rk_probe(struct platform_device *pdev)\r
-{\r
-       struct usb_hcd *hcd;\r
-       struct ehci_hcd *ehci;\r
-       struct resource *res;\r
-       struct device *dev = &pdev->dev;\r
-       struct rkehci_platform_data *pldata;\r
-       int ret;\r
-       int retval = 0;\r
-       static u64 usb_dmamask = 0xffffffffUL;\r
-       struct device_node *node = pdev->dev.of_node;\r
-\r
-       dev_dbg(&pdev->dev, "ehci_rk proble\n");\r
-\r
-       dev->platform_data = &rkhsic_pdata;\r
-       pldata = dev->platform_data;\r
-       pldata->dev = dev;\r
-\r
-       if (!node) {\r
-               dev_err(dev, "device node not found\n");\r
-               return -EINVAL;\r
-       }\r
-\r
-       dev->dma_mask = &usb_dmamask;\r
-\r
-       retval = device_create_file(dev, &dev_attr_ehci_power);\r
-       retval = device_create_file(dev, &dev_attr_debug_ehci);\r
-       hcd = usb_create_hcd(&rk_hc_driver, &pdev->dev, dev_name(&pdev->dev));\r
-       if (!hcd) {\r
-               dev_err(&pdev->dev, "Unable to create HCD\n");\r
-               return  -ENOMEM;\r
-       }\r
-\r
-       pldata->hw_init();\r
-       pldata->clock_init(pldata);\r
-       pldata->clock_enable(pldata, 1);\r
-\r
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
-       if (!res) {\r
-               dev_err(&pdev->dev, "Unable to get memory resource\n");\r
-               ret = -ENODEV;\r
-               goto put_hcd;\r
-       }\r
-\r
-       hcd->rsrc_start = res->start;\r
-       hcd->rsrc_len = resource_size(res);\r
-       hcd->regs = devm_ioremap_resource(dev, res);\r
-\r
-       if (!hcd->regs) {\r
-               dev_err(&pdev->dev, "ioremap failed\n");\r
-               ret = -ENOMEM;\r
-               goto put_hcd;\r
-       }\r
-       \r
-       hcd->irq = platform_get_irq(pdev, 0);\r
-       if (hcd->irq < 0) {\r
-               dev_err(&pdev->dev, "Unable to get IRQ resource\n");\r
-               ret = hcd->irq;\r
-               goto put_hcd;\r
-       }\r
-       \r
-       ehci = hcd_to_ehci(hcd);\r
-       ehci->caps = hcd->regs;\r
-       ehci->regs = hcd->regs + 0x10;\r
-       printk("%s %p %p\n", __func__, ehci->caps, ehci->regs);\r
-    \r
-       dbg_hcs_params(ehci, "reset");\r
-       dbg_hcc_params(ehci, "reset");\r
-\r
-       ehci->hcs_params = readl(&ehci->caps->hcs_params);\r
-\r
-       ret = usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);\r
-       if (ret) {\r
-               dev_err(&pdev->dev, "Failed to add USB HCD\n");\r
-               goto unmap;\r
-       }\r
-       \r
-       g_ehci = ehci;\r
-       ehci_port_power(ehci, 1);\r
-       writel_relaxed(1 ,hcd->regs +0xb0);\r
-       writel_relaxed(0x1d4d ,hcd->regs +0x90);\r
-       writel_relaxed(0x4 ,hcd->regs +0xa0);\r
-       dsb();\r
-\r
-\r
-       printk("%s ok\n", __func__);\r
-\r
-       return 0;\r
-\r
-unmap:\r
-       iounmap(hcd->regs);\r
-put_hcd:\r
-       usb_put_hcd(hcd);\r
-\r
-       return ret;\r
-}\r
-\r
-static int ehci_rk_remove(struct platform_device *pdev)\r
-{\r
-       struct usb_hcd *hcd = platform_get_drvdata(pdev);\r
-\r
-       usb_put_hcd(hcd);\r
-\r
-       return 0;\r
-}\r
-\r
-#ifdef CONFIG_PM\r
-static int ehci_rk_pm_suspend(struct device *dev)\r
-{\r
-       struct usb_hcd *hcd = dev_get_drvdata(dev);\r
-       bool wakeup = device_may_wakeup(dev);\r
-\r
-       dev_dbg(dev, "ehci-rk PM suspend\n");\r
-\r
-       /*\r
-        * EHCI helper function has also the same check before manipulating\r
-        * port wakeup flags.  We do check here the same condition before\r
-        * calling the same helper function to avoid bringing hardware\r
-        * from Low power mode when there is no need for adjusting port\r
-        * wakeup flags.\r
-        */\r
-       if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {\r
-               pm_runtime_resume(dev);\r
-               ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),\r
-                               wakeup);\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-static int ehci_rk_pm_resume(struct device *dev)\r
-{\r
-       struct usb_hcd *hcd = dev_get_drvdata(dev);\r
-\r
-       dev_dbg(dev, "ehci-rk PM resume\n");\r
-       ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));\r
-\r
-       return 0;\r
-}\r
-#else\r
-#define ehci_rk_pm_suspend     NULL\r
-#define ehci_rk_pm_resume      NULL\r
-#endif\r
-\r
-static const struct dev_pm_ops ehci_rk_dev_pm_ops = {\r
-       .suspend         = ehci_rk_pm_suspend,\r
-       .resume          = ehci_rk_pm_resume,\r
-};\r
-\r
-static struct of_device_id rk_hsic_of_match[] = {\r
-       { .compatible = "rockchip,rk_hsic_host", },\r
-       { },\r
-};\r
-\r
-MODULE_DEVICE_TABLE(of, rk_hsic_of_match);\r
-\r
-static struct platform_driver ehci_rk_driver = {\r
-       .probe  = ehci_rk_probe,\r
-       .remove = ehci_rk_remove,\r
-       .driver = {\r
-                  .name = "rk_hsic_host",\r
-                  .of_match_table = of_match_ptr(rk_hsic_of_match),\r
-#ifdef CONFIG_PM\r
-                  .pm = &ehci_rk_dev_pm_ops,\r
-#endif\r
-       },\r
-};\r
-\r
+/*
+ * EHCI-compliant USB host controller driver for Rockchip SoCs
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2009 - 2013 NVIDIA Corporation
+ *
+ * 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.
+ *
+ */
+# include <linux/platform_device.h>
+# include <linux/clk.h>
+# include <linux/err.h>
+# include <linux/device.h>
+# include <linux/of.h>
+# include <linux/of_platform.h>
+# include "ehci.h"
+#ifdef CONFIG_DWC_OTG_274
+# include "../dwc_otg/usbdev_rk.h"
+#endif
+#ifdef CONFIG_DWC_OTG_310
+# include "../dwc_otg_310/usbdev_rk.h"
+#endif
+
+static int rkehci_status = 1;
+static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
+{
+
+}
+
+static struct hc_driver rk_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "Rockchip On-Chip EHCI Host Controller",
+       .hcd_priv_size          = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq                    = ehci_irq,
+       .flags                  = HCD_USB2 | HCD_MEMORY,
+
+       .reset                  = ehci_init,
+       .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,
+       .endpoint_reset         = ehci_endpoint_reset,
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number       = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data        = ehci_hub_status_data,
+       .hub_control            = ehci_hub_control,
+       .relinquish_port        = ehci_relinquish_port,
+       .port_handed_over       = ehci_port_handed_over,
+
+       /*
+        * PM support
+        */
+#ifdef CONFIG_PM
+       .bus_suspend            = ehci_bus_suspend,
+       .bus_resume             = ehci_bus_resume,
+#endif
+};
+static ssize_t ehci_power_show( struct device *_dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", rkehci_status);
+}
+static ssize_t ehci_power_store( struct device *_dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count )
+{
+       return count;
+}
+static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store);
+static ssize_t debug_show( struct device *_dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "EHCI Registers Dump\n");
+}
+static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL);
+static int ehci_rk_probe(struct platform_device *pdev)
+{
+       dev_dbg(&pdev->dev, "ehci_rk proble\n");
+       return 0;
+}
+static int ehci_rk_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+#ifdef CONFIG_PM
+static int ehci_rk_pm_suspend(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       bool wakeup = device_may_wakeup(dev);
+
+       dev_dbg(dev, "ehci-rk PM suspend\n");
+
+       /*
+        * EHCI helper function has also the same check before manipulating
+        * port wakeup flags.  We do check here the same condition before
+        * calling the same helper function to avoid bringing hardware
+        * from Low power mode when there is no need for adjusting port
+        * wakeup flags.
+        */
+       if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
+               pm_runtime_resume(dev);
+               ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
+                               wakeup);
+       }
+
+       return 0;
+}
+
+static int ehci_rk_pm_resume(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "ehci-rk PM resume\n");
+       ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+
+       return 0;
+}
+#else
+#define ehci_rk_pm_suspend     NULL
+#define ehci_rk_pm_resume      NULL
+#endif
+
+static const struct dev_pm_ops ehci_rk_dev_pm_ops = {
+       .suspend         = ehci_rk_pm_suspend,
+       .resume          = ehci_rk_pm_resume,
+};
+
+static struct of_device_id rk_ehci_of_match[] = {
+       { .compatible = "rockchip,rk_ehci_host", },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, rk_ehci_of_match);
+
+static struct platform_driver ehci_rk_driver = {
+       .probe  = ehci_rk_probe,
+       .remove = ehci_rk_remove,
+       .driver = {
+                  .name = "rk_ehci_host",
+                  .of_match_table = of_match_ptr(rk_ehci_of_match),
+#ifdef CONFIG_PM
+                  .pm = &ehci_rk_dev_pm_ops,
+#endif
+       },
+};
diff --git a/drivers/usb/host/ehci-rkhsic.c b/drivers/usb/host/ehci-rkhsic.c
new file mode 100755 (executable)
index 0000000..37e19e3
--- /dev/null
@@ -0,0 +1,359 @@
+/* ehci-msm.c - HSUSB Host Controller Driver Implementation
+ *
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Partly derived from ehci-fsl.c and ehci-hcd.c
+ * Copyright (c) 2000-2004 by David Brownell
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * 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.
+ *
+ * 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, you can find it at http://www.fsf.org
+ */
+
+# include <linux/platform_device.h>
+# include <linux/clk.h>
+# include <linux/err.h>
+# include <linux/device.h>
+# include <linux/of.h>
+# include <linux/of_platform.h>
+# include "ehci.h"
+#ifdef CONFIG_DWC_OTG_274
+# include "../dwc_otg/usbdev_rk.h"
+#endif
+#ifdef CONFIG_DWC_OTG_310
+# include "../dwc_otg_310/usbdev_rk.h"
+#endif
+
+static int rkehci_status = 1;
+static struct ehci_hcd *g_ehci;
+#define EHCI_DEVICE_FILE        "/sys/devices/platform/rk_hsusb_host/ehci_power"
+#define EHCI_PRINT(x...)       printk( KERN_INFO "EHCI: " x )
+
+extern struct rkehci_platform_data rkhsic_pdata;
+
+static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
+{
+       unsigned port;
+
+       if (!HCS_PPC (ehci->hcs_params))
+               return;
+
+       ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");
+       for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
+               (void) ehci_hub_control(ehci_to_hcd(ehci),
+                               is_on ? SetPortFeature : ClearPortFeature,
+                               USB_PORT_FEAT_POWER,
+                               port--, NULL, 0);
+       /* Flush those writes */
+       ehci_readl(ehci, &ehci->regs->command);
+       msleep(20);
+}
+
+static struct hc_driver rk_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "Rockchip On-Chip EHCI Host Controller",
+       .hcd_priv_size          = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq                    = ehci_irq,
+       .flags                  = HCD_USB2 | HCD_MEMORY,
+
+       .reset                  = ehci_init,
+       .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,
+       .endpoint_reset         = ehci_endpoint_reset,
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number       = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data        = ehci_hub_status_data,
+       .hub_control            = ehci_hub_control,
+       .relinquish_port        = ehci_relinquish_port,
+       .port_handed_over       = ehci_port_handed_over,
+
+       /*
+        * PM support
+        */
+#ifdef CONFIG_PM
+       .bus_suspend            = ehci_bus_suspend,
+       .bus_resume             = ehci_bus_resume,
+#endif
+};
+
+static ssize_t ehci_power_show( struct device *_dev, 
+                               struct device_attribute *attr, char *buf) 
+{
+       return sprintf(buf, "%d\n", rkehci_status);
+}
+static ssize_t ehci_power_store( struct device *_dev,
+                                       struct device_attribute *attr, 
+                                       const char *buf, size_t count ) 
+{
+       uint32_t val = simple_strtoul(buf, NULL, 16);
+       struct usb_hcd *hcd = dev_get_drvdata(_dev);
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct rkehci_platform_data *pldata = _dev->platform_data;
+
+       printk("%s: %d setting to: %d\n", __func__, rkehci_status, val);
+       if(val == rkehci_status)
+               goto out;
+       
+       rkehci_status = val;
+       switch(val){
+               case 0: //power down
+                       ehci_port_power(ehci, 0);
+                       writel_relaxed(0 ,hcd->regs +0xb0);
+                       dsb();
+                       msleep(5);
+                       usb_remove_hcd(hcd);
+                       break;
+               case 1: // power on
+                       pldata->soft_reset();
+                       usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+        
+                       ehci_port_power(ehci, 1);
+                       writel_relaxed(1 ,hcd->regs +0xb0);
+                       writel_relaxed(0x1d4d ,hcd->regs +0x90);
+                       writel_relaxed(0x4 ,hcd->regs +0xa0);
+                       dsb();
+                       break;
+               default:
+                       break;
+       }
+out:
+       return count;
+}
+static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store);
+
+static ssize_t debug_show( struct device *_dev,
+                               struct device_attribute *attr, char *buf)
+{
+       volatile uint32_t *addr;
+
+       EHCI_PRINT("******** EHCI Capability Registers **********\n");
+       addr = &g_ehci->caps->hc_capbase;
+       EHCI_PRINT("HCIVERSION / CAPLENGTH  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->caps->hcs_params;
+       EHCI_PRINT("HCSPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->caps->hcc_params;
+       EHCI_PRINT("HCCPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       EHCI_PRINT("********* EHCI Operational Registers *********\n");
+       addr = &g_ehci->regs->command;
+       EHCI_PRINT("USBCMD                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->status;
+       EHCI_PRINT("USBSTS                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->intr_enable;
+       EHCI_PRINT("USBINTR                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->frame_index;
+       EHCI_PRINT("FRINDEX                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->segment;
+       EHCI_PRINT("CTRLDSSEGMENT           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->frame_list;
+       EHCI_PRINT("PERIODICLISTBASE        @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); 
+       addr = &g_ehci->regs->async_next;
+       EHCI_PRINT("ASYNCLISTADDR           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->configured_flag;
+       EHCI_PRINT("CONFIGFLAG              @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = g_ehci->regs->port_status;
+       EHCI_PRINT("PORTSC                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       return sprintf(buf, "EHCI Registers Dump\n");
+}
+static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL);
+
+static int ehci_rkhsic_probe(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct rkehci_platform_data *pldata;
+       int ret;
+       int retval = 0;
+       static u64 usb_dmamask = 0xffffffffUL;
+       struct device_node *node = pdev->dev.of_node;
+
+       dev_dbg(&pdev->dev, "ehci_rkhsic proble\n");
+
+       dev->platform_data = &rkhsic_pdata;
+       pldata = dev->platform_data;
+       pldata->dev = dev;
+
+       if (!node) {
+               dev_err(dev, "device node not found\n");
+               return -EINVAL;
+       }
+
+       dev->dma_mask = &usb_dmamask;
+
+       retval = device_create_file(dev, &dev_attr_ehci_power);
+       retval = device_create_file(dev, &dev_attr_debug_ehci);
+       hcd = usb_create_hcd(&rk_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd) {
+               dev_err(&pdev->dev, "Unable to create HCD\n");
+               return  -ENOMEM;
+       }
+
+       pldata->hw_init();
+       pldata->clock_init(pldata);
+       pldata->clock_enable(pldata, 1);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get memory resource\n");
+               ret = -ENODEV;
+               goto put_hcd;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+       hcd->regs = devm_ioremap_resource(dev, res);
+
+       if (!hcd->regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto put_hcd;
+       }
+       
+       hcd->irq = platform_get_irq(pdev, 0);
+       if (hcd->irq < 0) {
+               dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+               ret = hcd->irq;
+               goto put_hcd;
+       }
+       
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs + 0x10;
+       printk("%s %p %p\n", __func__, ehci->caps, ehci->regs);
+    
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+       ret = usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add USB HCD\n");
+               goto unmap;
+       }
+       
+       g_ehci = ehci;
+       ehci_port_power(ehci, 1);
+       writel_relaxed(1 ,hcd->regs +0xb0);
+       writel_relaxed(0x1d4d ,hcd->regs +0x90);
+       writel_relaxed(0x4 ,hcd->regs +0xa0);
+       dsb();
+
+
+       printk("%s ok\n", __func__);
+
+       return 0;
+
+unmap:
+       iounmap(hcd->regs);
+put_hcd:
+       usb_put_hcd(hcd);
+
+       return ret;
+}
+
+static int ehci_rkhsic_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int ehci_rkhsic_pm_suspend(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       bool wakeup = device_may_wakeup(dev);
+
+       dev_dbg(dev, "ehci-rkhsic PM suspend\n");
+
+       /*
+        * EHCI helper function has also the same check before manipulating
+        * port wakeup flags.  We do check here the same condition before
+        * calling the same helper function to avoid bringing hardware
+        * from Low power mode when there is no need for adjusting port
+        * wakeup flags.
+        */
+       if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
+               pm_runtime_resume(dev);
+               ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
+                               wakeup);
+       }
+
+       return 0;
+}
+
+static int ehci_rkhsic_pm_resume(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "ehci-rkhsic PM resume\n");
+       ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+
+       return 0;
+}
+#else
+#define ehci_rkhsic_pm_suspend NULL
+#define ehci_rkhsic_pm_resume  NULL
+#endif
+
+static const struct dev_pm_ops ehci_rkhsic_dev_pm_ops = {
+       .suspend         = ehci_rkhsic_pm_suspend,
+       .resume          = ehci_rkhsic_pm_resume,
+};
+
+static struct of_device_id rk_hsic_of_match[] = {
+       { .compatible = "rockchip,rk_hsic_host", },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, rk_hsic_of_match);
+
+static struct platform_driver ehci_rkhsic_driver = {
+       .probe  = ehci_rkhsic_probe,
+       .remove = ehci_rkhsic_remove,
+       .driver = {
+                  .name = "rk_hsic_host",
+                  .of_match_table = of_match_ptr(rk_hsic_of_match),
+#ifdef CONFIG_PM
+                  .pm = &ehci_rkhsic_dev_pm_ops,
+#endif
+       },
+};
+