-/* 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
+ },
+};
--- /dev/null
+/* 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
+ },
+};
+