diff options
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.patch | 347 |
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", ++ }, ++}; |