+++ /dev/null
-From 4365ef4ae6c7c08950ac34c47f7beaece2dc48ea Mon Sep 17 00:00:00 2001
-From: Lars-Peter Clausen <lars@metafoo.de>
-Date: Sun, 1 Aug 2010 21:13:26 +0200
-Subject: [PATCH] USB: Add JZ4740 OHCI support
-
-Add OHCI glue code for JZ4740 SoCs OHCI module.
-
-Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
-Cc: Greg Kroah-Hartman <gregkh@suse.de>
-Cc: David Brownell <dbrownell@users.sourceforge.net>
-Cc: linux-usb@vger.kernel.org
-Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
-Cc: linux-mips@linux-mips.org
-Cc: linux-kernel@vger.kernel.org
-Patchwork: https://patchwork.linux-mips.org/patch/1411/
-Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
----
- drivers/usb/Kconfig | 1 +
- drivers/usb/host/ohci-hcd.c | 5 +
- drivers/usb/host/ohci-jz4740.c | 276 ++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 282 insertions(+), 0 deletions(-)
- create mode 100644 drivers/usb/host/ohci-jz4740.c
-
---- a/drivers/usb/Kconfig
-+++ b/drivers/usb/Kconfig
-@@ -46,6 +46,7 @@ config USB_ARCH_HAS_OHCI
- default y if PPC_MPC52xx
- # MIPS:
- default y if SOC_AU1X00
-+ default y if MACH_JZ4740
- # SH:
- default y if CPU_SUBTYPE_SH7720
- default y if CPU_SUBTYPE_SH7721
---- a/drivers/usb/host/ohci-hcd.c
-+++ b/drivers/usb/host/ohci-hcd.c
-@@ -1095,6 +1095,11 @@ MODULE_LICENSE ("GPL");
- #define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver
- #endif
-
-+#ifdef CONFIG_MACH_JZ4740
-+#include "ohci-jz4740.c"
-+#define PLATFORM_DRIVER ohci_hcd_jz4740_driver
-+#endif
-+
- #if !defined(PCI_DRIVER) && \
- !defined(PLATFORM_DRIVER) && \
- !defined(OMAP1_PLATFORM_DRIVER) && \
---- /dev/null
-+++ b/drivers/usb/host/ohci-jz4740.c
-@@ -0,0 +1,276 @@
-+/*
-+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
-+ *
-+ * 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.
-+ *
-+ * 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.
-+ *
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/clk.h>
-+#include <linux/regulator/consumer.h>
-+
-+struct jz4740_ohci_hcd {
-+ struct ohci_hcd ohci_hcd;
-+
-+ struct regulator *vbus;
-+ bool vbus_enabled;
-+ struct clk *clk;
-+};
-+
-+static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd)
-+{
-+ return (struct jz4740_ohci_hcd *)(hcd->hcd_priv);
-+}
-+
-+static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci)
-+{
-+ return container_of((void *)jz4740_ohci, struct usb_hcd, hcd_priv);
-+}
-+
-+static int ohci_jz4740_start(struct usb_hcd *hcd)
-+{
-+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-+ int ret;
-+
-+ ret = ohci_init(ohci);
-+ if (ret < 0)
-+ return ret;
-+
-+ ohci->num_ports = 1;
-+
-+ ret = ohci_run(ohci);
-+ if (ret < 0) {
-+ dev_err(hcd->self.controller, "Can not start %s",
-+ hcd->self.bus_name);
-+ ohci_stop(hcd);
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci,
-+ bool enabled)
-+{
-+ int ret = 0;
-+
-+ if (!jz4740_ohci->vbus)
-+ return 0;
-+
-+ if (enabled && !jz4740_ohci->vbus_enabled) {
-+ ret = regulator_enable(jz4740_ohci->vbus);
-+ if (ret)
-+ dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller,
-+ "Could not power vbus\n");
-+ } else if (!enabled && jz4740_ohci->vbus_enabled) {
-+ ret = regulator_disable(jz4740_ohci->vbus);
-+ }
-+
-+ if (ret == 0)
-+ jz4740_ohci->vbus_enabled = enabled;
-+
-+ return ret;
-+}
-+
-+static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
-+ u16 wIndex, char *buf, u16 wLength)
-+{
-+ struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
-+ int ret;
-+
-+ switch (typeReq) {
-+ case SetHubFeature:
-+ if (wValue == USB_PORT_FEAT_POWER)
-+ ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true);
-+ break;
-+ case ClearHubFeature:
-+ if (wValue == USB_PORT_FEAT_POWER)
-+ ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false);
-+ break;
-+ }
-+
-+ if (ret)
-+ return ret;
-+
-+ return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
-+}
-+
-+
-+static const struct hc_driver ohci_jz4740_hc_driver = {
-+ .description = hcd_name,
-+ .product_desc = "JZ4740 OHCI",
-+ .hcd_priv_size = sizeof(struct jz4740_ohci_hcd),
-+
-+ /*
-+ * generic hardware linkage
-+ */
-+ .irq = ohci_irq,
-+ .flags = HCD_USB11 | HCD_MEMORY,
-+
-+ /*
-+ * basic lifecycle operations
-+ */
-+ .start = ohci_jz4740_start,
-+ .stop = ohci_stop,
-+ .shutdown = ohci_shutdown,
-+
-+ /*
-+ * managing i/o requests and associated device resources
-+ */
-+ .urb_enqueue = ohci_urb_enqueue,
-+ .urb_dequeue = ohci_urb_dequeue,
-+ .endpoint_disable = ohci_endpoint_disable,
-+
-+ /*
-+ * scheduling support
-+ */
-+ .get_frame_number = ohci_get_frame,
-+
-+ /*
-+ * root hub support
-+ */
-+ .hub_status_data = ohci_hub_status_data,
-+ .hub_control = ohci_jz4740_hub_control,
-+#ifdef CONFIG_PM
-+ .bus_suspend = ohci_bus_suspend,
-+ .bus_resume = ohci_bus_resume,
-+#endif
-+ .start_port_reset = ohci_start_port_reset,
-+};
-+
-+
-+static __devinit int jz4740_ohci_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+ struct usb_hcd *hcd;
-+ struct jz4740_ohci_hcd *jz4740_ohci;
-+ struct resource *res;
-+ int irq;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+
-+ if (!res) {
-+ dev_err(&pdev->dev, "Failed to get platform resource\n");
-+ return -ENOENT;
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0) {
-+ dev_err(&pdev->dev, "Failed to get platform irq\n");
-+ return irq;
-+ }
-+
-+ hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740");
-+ if (!hcd) {
-+ dev_err(&pdev->dev, "Failed to create hcd.\n");
-+ return -ENOMEM;
-+ }
-+
-+ jz4740_ohci = hcd_to_jz4740_hcd(hcd);
-+
-+ res = request_mem_region(res->start, resource_size(res), hcd_name);
-+ if (!res) {
-+ dev_err(&pdev->dev, "Failed to request mem region.\n");
-+ ret = -EBUSY;
-+ goto err_free;
-+ }
-+
-+ hcd->rsrc_start = res->start;
-+ hcd->rsrc_len = resource_size(res);
-+ hcd->regs = ioremap(res->start, resource_size(res));
-+
-+ if (!hcd->regs) {
-+ dev_err(&pdev->dev, "Failed to ioremap registers.\n");
-+ ret = -EBUSY;
-+ goto err_release_mem;
-+ }
-+
-+ jz4740_ohci->clk = clk_get(&pdev->dev, "uhc");
-+ if (IS_ERR(jz4740_ohci->clk)) {
-+ ret = PTR_ERR(jz4740_ohci->clk);
-+ dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
-+ goto err_iounmap;
-+ }
-+
-+ jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus");
-+ if (IS_ERR(jz4740_ohci->vbus))
-+ jz4740_ohci->vbus = NULL;
-+
-+
-+ clk_set_rate(jz4740_ohci->clk, 48000000);
-+ clk_enable(jz4740_ohci->clk);
-+ if (jz4740_ohci->vbus)
-+ ohci_jz4740_set_vbus_power(jz4740_ohci, true);
-+
-+ platform_set_drvdata(pdev, hcd);
-+
-+ ohci_hcd_init(hcd_to_ohci(hcd));
-+
-+ ret = usb_add_hcd(hcd, irq, 0);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret);
-+ goto err_disable;
-+ }
-+
-+ return 0;
-+
-+err_disable:
-+ platform_set_drvdata(pdev, NULL);
-+ if (jz4740_ohci->vbus) {
-+ regulator_disable(jz4740_ohci->vbus);
-+ regulator_put(jz4740_ohci->vbus);
-+ }
-+ clk_disable(jz4740_ohci->clk);
-+
-+ clk_put(jz4740_ohci->clk);
-+err_iounmap:
-+ iounmap(hcd->regs);
-+err_release_mem:
-+ release_mem_region(res->start, resource_size(res));
-+err_free:
-+ usb_put_hcd(hcd);
-+
-+ return ret;
-+}
-+
-+static __devexit int jz4740_ohci_remove(struct platform_device *pdev)
-+{
-+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
-+ struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
-+
-+ usb_remove_hcd(hcd);
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ if (jz4740_ohci->vbus) {
-+ regulator_disable(jz4740_ohci->vbus);
-+ regulator_put(jz4740_ohci->vbus);
-+ }
-+
-+ clk_disable(jz4740_ohci->clk);
-+ clk_put(jz4740_ohci->clk);
-+
-+ iounmap(hcd->regs);
-+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-+
-+ usb_put_hcd(hcd);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver ohci_hcd_jz4740_driver = {
-+ .probe = jz4740_ohci_probe,
-+ .remove = __devexit_p(jz4740_ohci_remove),
-+ .driver = {
-+ .name = "jz4740-ohci",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+MODULE_ALIAS("platfrom:jz4740-ohci");