summaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch')
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch347
1 files changed, 347 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch b/recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch
new file mode 100644
index 0000000000..1c60690b89
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch
@@ -0,0 +1,347 @@
+From ce297d614ab56284823043e1743200388d9f466f Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Mon, 9 Mar 2009 12:29:23 +0100
+Subject: [PATCH 027/101] Add EHCI support for MX27 and MX31 based boards
+
+The Freescale MX27 and MX31 SoCs have a EHCI controller onboard.
+The controller is capable of USB on the go. This patch adds
+support for the host controller only.
+
+The USB OTG core used here is the ARC core, so the driver should
+be renamed.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@phytec.de>
+---
+ arch/arm/plat-mxc/include/mach/mxc_ehci.h | 9 +
+ drivers/usb/Kconfig | 1 +
+ drivers/usb/host/Kconfig | 7 +
+ drivers/usb/host/ehci-hcd.c | 5 +
+ drivers/usb/host/ehci-mxc.c | 256 +++++++++++++++++++++++++++++
+ 5 files changed, 278 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/plat-mxc/include/mach/mxc_ehci.h
+ create mode 100644 drivers/usb/host/ehci-mxc.c
+
+Index: linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mxc_ehci.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mxc_ehci.h 2009-12-10 11:40:43.315272374 +0100
+@@ -0,0 +1,9 @@
++#ifndef __INCLUDE_ASM_ARCH_MXC_EHCI_H
++#define __INCLUDE_ASM_ARCH_MXC_EHCI_H
++
++struct mxc_usbh_platform_data {
++ int (*init)(struct platform_device *pdev);
++ int (*exit)(struct platform_device *pdev);
++};
++#endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */
++
+Index: linux-2.6.31.6/drivers/usb/Kconfig
+===================================================================
+--- linux-2.6.31.6.orig/drivers/usb/Kconfig 2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/usb/Kconfig 2009-12-10 11:40:43.315272374 +0100
+@@ -58,6 +58,7 @@
+ default y if PPC_83xx
+ default y if SOC_AU1200
+ default y if ARCH_IXP4XX
++ default y if ARCH_MXC
+ default PCI
+
+ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
+Index: linux-2.6.31.6/drivers/usb/host/Kconfig
+===================================================================
+--- linux-2.6.31.6.orig/drivers/usb/host/Kconfig 2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/usb/host/Kconfig 2009-12-10 11:40:43.315272374 +0100
+@@ -105,6 +105,13 @@
+ ---help---
+ Variation of ARC USB block used in some Freescale chips.
+
++config USB_EHCI_MXC
++ bool "Support for Freescale on-chip EHCI USB controller"
++ depends on USB_EHCI_HCD && ARCH_MXC
++ select USB_EHCI_ROOT_HUB_TT
++ ---help---
++ Variation of ARC USB block used in some Freescale 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
+Index: linux-2.6.31.6/drivers/usb/host/ehci-hcd.c
+===================================================================
+--- linux-2.6.31.6.orig/drivers/usb/host/ehci-hcd.c 2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/usb/host/ehci-hcd.c 2009-12-10 11:40:43.315272374 +0100
+@@ -1092,6 +1092,11 @@
+ #define PLATFORM_DRIVER ehci_fsl_driver
+ #endif
+
++#ifdef CONFIG_USB_EHCI_MXC
++#include "ehci-mxc.c"
++#define PLATFORM_DRIVER ehci_mxc_driver
++#endif
++
+ #ifdef CONFIG_SOC_AU1200
+ #include "ehci-au1xxx.c"
+ #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
+Index: linux-2.6.31.6/drivers/usb/host/ehci-mxc.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/usb/host/ehci-mxc.c 2009-12-10 11:40:43.315272374 +0100
+@@ -0,0 +1,256 @@
++/*
++ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
++ *
++ * 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.
++ *
++ */
++
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <mach/mxc_ehci.h>
++
++struct ehci_mxc_priv {
++ struct clk *usbclk, *ahbclk;
++ struct usb_hcd *hcd;
++};
++
++/* called during probe() after chip reset completes */
++static int ehci_mxc_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));
++ dbg_hcs_params(ehci, "reset");
++ dbg_hcc_params(ehci, "reset");
++
++ /* cache this readonly data; minimize chip reads */
++ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++ retval = ehci_halt(ehci);
++ if (retval)
++ return retval;
++
++ /* data structure init */
++ retval = ehci_init(hcd);
++ if (retval)
++ return retval;
++
++ hcd->has_tt = 1;
++
++ ehci->sbrn = 0x20;
++
++ ehci_reset(ehci);
++
++ ehci_port_power(ehci, 0);
++ return 0;
++}
++
++static const struct hc_driver ehci_mxc_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "Freescale On-Chip EHCI Host Controller",
++ .hcd_priv_size = sizeof(struct ehci_hcd),
++
++ /*
++ * generic hardware linkage
++ */
++ .irq = ehci_irq,
++ .flags = HCD_USB2 | HCD_MEMORY,
++
++ /*
++ * basic lifecycle operations
++ */
++ .reset = ehci_mxc_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,
++ .port_handed_over = ehci_port_handed_over,
++};
++
++static int ehci_mxc_drv_probe(struct platform_device *pdev)
++{
++ struct mxc_usbh_platform_data *pdata;
++ struct usb_hcd *hcd;
++ struct resource *res;
++ int irq, ret, temp;
++ struct ehci_mxc_priv *priv;
++
++ dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
++
++ pdata = (struct mxc_usbh_platform_data *)pdev->dev.platform_data;
++
++ irq = platform_get_irq(pdev, 0);
++
++ hcd = usb_create_hcd(&ehci_mxc_hc_driver, &pdev->dev, dev_name(&pdev->dev));
++ if (!hcd)
++ return -ENOMEM;
++
++ priv = kzalloc(sizeof (*priv), GFP_KERNEL);
++ if (!priv) {
++ ret = -ENOMEM;
++ goto err_alloc;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev,
++ "Found HC with no register addr. Check setup!\n");
++ ret = -ENODEV;
++ goto err_get_resource;
++ }
++
++ hcd->rsrc_start = res->start;
++ hcd->rsrc_len = resource_size(res);
++
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++ dev_dbg(&pdev->dev, "controller already in use\n");
++ ret = -EBUSY;
++ goto err_request_mem;
++ }
++
++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++ if (!hcd->regs) {
++ dev_err(&pdev->dev, "error mapping memory\n");
++ ret = -EFAULT;
++ goto err_ioremap;
++ }
++
++ priv->usbclk = clk_get(&pdev->dev, "usb");
++ if (IS_ERR(priv->usbclk)) {
++ ret = PTR_ERR(priv->usbclk);
++ goto err_clk;
++ }
++ clk_enable(priv->usbclk);
++
++ if (!cpu_is_mx35()) {
++ priv->ahbclk = clk_get(&pdev->dev, "usb_ahb");
++ if (IS_ERR(priv->ahbclk)) {
++ ret = PTR_ERR(priv->ahbclk);
++ goto err_clk_ahb;
++ }
++ clk_enable(priv->ahbclk);
++ }
++
++ if (pdata && pdata->init) {
++ ret = pdata->init(pdev);
++ if (ret) {
++ dev_err(&pdev->dev, "platform init failed\n");
++ goto err_init;
++ }
++ }
++
++ /* Set to Host mode */
++ temp = readl(hcd->regs + 0x1a8);
++ writel(temp | 0x3, hcd->regs + 0x1a8);
++
++ priv->hcd = hcd;
++ platform_set_drvdata(pdev, priv);
++
++ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
++ if (ret)
++ goto err_add;
++
++ return 0;
++
++err_add:
++ if (pdata && pdata->exit)
++ pdata->exit(pdev);
++err_init:
++ if (priv->ahbclk) {
++ clk_disable(priv->ahbclk);
++ clk_put(priv->ahbclk);
++ }
++err_clk_ahb:
++ clk_disable(priv->usbclk);
++ clk_put(priv->usbclk);
++err_clk:
++ iounmap(hcd->regs);
++err_ioremap:
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err_request_mem:
++err_get_resource:
++ kfree(priv);
++err_alloc:
++ usb_put_hcd(hcd);
++ return ret;
++}
++
++static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
++{
++ struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
++ struct usb_hcd *hcd = priv->hcd;
++
++ usb_remove_hcd(hcd);
++ iounmap(hcd->regs);
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ usb_put_hcd(hcd);
++ platform_set_drvdata(pdev, NULL);
++
++ clk_disable(priv->usbclk);
++ clk_put(priv->usbclk);
++ if (priv->ahbclk) {
++ clk_disable(priv->ahbclk);
++ clk_put(priv->ahbclk);
++ }
++
++ kfree(priv);
++
++ return 0;
++}
++
++static void
++ehci_mxc_shutdown(struct platform_device *pdev)
++{
++ struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
++ struct usb_hcd *hcd = priv->hcd;
++
++ if (hcd->driver->shutdown)
++ hcd->driver->shutdown(hcd);
++}
++
++MODULE_ALIAS("platform:mxc-ehci");
++
++static struct platform_driver ehci_mxc_driver = {
++ .probe = ehci_mxc_drv_probe,
++ .remove = __exit_p(ehci_mxc_drv_remove),
++ .shutdown = ehci_mxc_shutdown,
++ .driver = {
++ .name = "mxc-ehci",
++ },
++};