summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Chen <R65187@freescale.com>2008-03-17 14:02:12 +0800
committerDaniel Schaeffer <daniel.schaeffer@timesys.com>2008-08-25 15:20:49 -0400
commitb44e2360f203ef6848ef8a5c8e3519db85cdc84e (patch)
tree9df2bd7241839f925a9675e03daab8abb6674010
parent33dfa962241282facc7a270d285816876956a671 (diff)
ENGR00066977 : add USB controller driver, only device mode
Mx37: add USB controller driver for device mode Signed-off-by: Albert Chen <r65187@freescale.com>
-rw-r--r--arch/arm/mach-mx37/Makefile2
-rw-r--r--arch/arm/mach-mx37/clock.c22
-rw-r--r--arch/arm/mach-mx37/crm_regs.h1
-rw-r--r--arch/arm/mach-mx37/mx37_3stack_gpio.c50
-rw-r--r--arch/arm/mach-mx37/usb.c142
-rw-r--r--arch/arm/plat-mxc/Makefile2
-rw-r--r--arch/arm/plat-mxc/usb_common.c32
-rw-r--r--arch/arm/plat-mxc/utmixc.c61
-rw-r--r--drivers/usb/gadget/arcotg_udc.c3
-rw-r--r--include/asm-arm/arch-mxc/mx37.h2
10 files changed, 258 insertions, 59 deletions
diff --git a/arch/arm/mach-mx37/Makefile b/arch/arm/mach-mx37/Makefile
index 6429f03998be..7e476ef01fd4 100644
--- a/arch/arm/mach-mx37/Makefile
+++ b/arch/arm/mach-mx37/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := system.o iomux.o cpu.o mm.o clock.o devices.o serial.o dma.o
+obj-y := system.o iomux.o cpu.o mm.o clock.o devices.o serial.o dma.o usb.o
obj-$(CONFIG_MACH_MX37_3DS) += mx37_3stack.o mx37_3stack_gpio.o
obj-$(CONFIG_SPI_MXC) += mx37_3stack_cpld.o
diff --git a/arch/arm/mach-mx37/clock.c b/arch/arm/mach-mx37/clock.c
index d17291ca245d..6097d6148759 100644
--- a/arch/arm/mach-mx37/clock.c
+++ b/arch/arm/mach-mx37/clock.c
@@ -1250,8 +1250,9 @@ static struct clk usboh2_clk[] = {
.secondary = &usboh2_clk[1],
},
{
- .name = "usboh2_ipg_clk",
- .parent = &ipg_clk,
+ .name = "usb_ahb_clk",
+ .parent = &ahb_clk,
+ .secondary = &ipg_clk,
.enable = _clk_enable,
.enable_reg = MXC_CCM_CCGR2,
.enable_shift = MXC_CCM_CCGR2_CG11_OFFSET,
@@ -1725,6 +1726,21 @@ static struct clk pgc_clk = {
.recalc = _clk_pgc_recalc,
};
+/*usb OTG clock */
+/*Notes: in mx37, usb clock get from UTMI PHY, always 60MHz*/
+
+static struct clk usb_clk = {
+ .name = "usb_clk",
+ .rate = 60000000,
+};
+static struct clk usb_utmi_clk = {
+ .name = "usb_utmi_clk",
+ .enable = _clk_enable,
+ .enable_reg = MXC_CCM_CSCMR1,
+ .enable_shift = MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET,
+ .disable = _clk_disable,
+};
+
static struct clk rtc_clk = {
.name = "rtc_clk",
.parent = &ckil_clk,
@@ -1797,6 +1813,8 @@ static struct clk *mxc_clks[] = {
&usboh2_clk[0],
&usboh2_clk[1],
&usb_phy_clk,
+ &usb_utmi_clk,
+ &usb_clk,
&esdhc1_clk[0],
&esdhc1_clk[1],
&esdhc2_clk[0],
diff --git a/arch/arm/mach-mx37/crm_regs.h b/arch/arm/mach-mx37/crm_regs.h
index 46cd75e4eed9..5213146581c8 100644
--- a/arch/arm/mach-mx37/crm_regs.h
+++ b/arch/arm/mach-mx37/crm_regs.h
@@ -207,6 +207,7 @@
#define MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_OFFSET (28)
#define MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_MASK (0x3 << 28)
#define MXC_CCM_CSCMR1_DI_CLK_SEL (0x1 << 27)
+#define MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET (26)
#define MXC_CCM_CSCMR1_USB_PHY_CLK_SEL (0x1 << 26)
#define MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET (24)
#define MXC_CCM_CSCMR1_UART_CLK_SEL_MASK (0x3 << 24)
diff --git a/arch/arm/mach-mx37/mx37_3stack_gpio.c b/arch/arm/mach-mx37/mx37_3stack_gpio.c
index 59da102ede8e..0e7c8a0c3ba0 100644
--- a/arch/arm/mach-mx37/mx37_3stack_gpio.c
+++ b/arch/arm/mach-mx37/mx37_3stack_gpio.c
@@ -374,40 +374,6 @@ void gpio_ata_inactive(void)
EXPORT_SYMBOL(gpio_ata_inactive);
/*
- * USB Host 1
- * pins conflict with SPI1, ATA, UART3
- */
-int gpio_usbh1_active(void)
-{
- /*TODO*/ return 0;
-}
-
-EXPORT_SYMBOL(gpio_usbh1_active);
-
-void gpio_usbh1_inactive(void)
-{
- /*TODO*/}
-
-EXPORT_SYMBOL(gpio_usbh1_inactive);
-
-/*
- * USB Host 2
- * pins conflict with UART5, PCMCIA
- */
-int gpio_usbh2_active(void)
-{
- /*TODO*/ return 0;
-}
-
-EXPORT_SYMBOL(gpio_usbh2_active);
-
-void gpio_usbh2_inactive(void)
-{
- /*TODO*/}
-
-EXPORT_SYMBOL(gpio_usbh2_inactive);
-
-/*
* USB OTG HS port
*/
int gpio_usbotg_hs_active(void)
@@ -423,22 +389,6 @@ void gpio_usbotg_hs_inactive(void)
EXPORT_SYMBOL(gpio_usbotg_hs_inactive);
-/*
- * USB OTG FS port
- */
-int gpio_usbotg_fs_active(void)
-{
- /*TODO*/ return 0;
-}
-
-EXPORT_SYMBOL(gpio_usbotg_fs_active);
-
-void gpio_usbotg_fs_inactive(void)
-{
- /*TODO*/}
-
-EXPORT_SYMBOL(gpio_usbotg_fs_inactive);
-
/*!
* Setup GPIO for PCMCIA interface
*
diff --git a/arch/arm/mach-mx37/usb.c b/arch/arm/mach-mx37/usb.c
new file mode 100644
index 000000000000..907c5764d2f2
--- /dev/null
+++ b/arch/arm/mach-mx37/usb.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup USB_MX37 ARC OTG USB Driver for i.MX37
+ * @ingroup USB
+ */
+
+/*!
+ * @file mach-mx37/usb.c
+ *
+ * @brief platform related part of usb driver.
+ * @ingroup USB_MX37
+ */
+
+/*!
+ *Include files
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/clk.h>
+#include <linux/usb/fsl_xcvr.h>
+#include <linux/usb/otg.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/arc_otg.h>
+
+extern int usbotg_init(struct platform_device *pdev);
+extern void usbotg_uninit(struct fsl_usb2_platform_data *pdata);
+extern int gpio_usbotg_hs_active(void);
+extern void gpio_usbotg_hs_inactive(void);
+
+#if defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC)
+static struct resource otg_resources[] = {
+ {
+ .start = (u32) (OTG_BASE_ADDR),
+ .end = (u32) (OTG_BASE_ADDR + 0x1ff),
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_USB_OTG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* Notes: configure USB clock*/
+static int usbotg_init_ext(struct platform_device *pdev)
+{
+ struct clk *usb_clk;
+
+ usb_clk = clk_get(NULL, "usboh2_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ usb_clk = clk_get(NULL, "usb_phy_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ /*derive clock from oscillator */
+ usb_clk = clk_get(NULL, "usb_utmi_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+
+ return usbotg_init(pdev);
+}
+#endif
+
+#if defined(CONFIG_USB_GADGET_ARC)
+/*!
+ * OTG Gadget device
+ */
+static void udc_release(struct device *dev)
+{
+ /* normally not freed */
+}
+
+static u64 udc_dmamask = ~(u32) 0;
+
+static struct fsl_usb2_platform_data mxc_utmi_peripheral_config = {
+ .name = "OTG",
+ .platform_init = usbotg_init_ext,
+ .platform_uninit = usbotg_uninit,
+ .usbmode = (u32) &UOG_USBMODE,
+ .does_otg = 0,
+ .operating_mode = FSL_USB2_DR_DEVICE,
+ .power_budget = 150, /* 150 mA max power */
+ .gpio_usb_active = gpio_usbotg_hs_active,
+ .gpio_usb_inactive = gpio_usbotg_hs_inactive,
+ .transceiver = "utmi",
+};
+static struct platform_device otg_udc_device = {
+ .name = "arc_udc",
+ .id = -1,
+ .dev = {
+ .release = udc_release,
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &mxc_utmi_peripheral_config,
+ },
+ .resource = otg_resources,
+ .num_resources = ARRAY_SIZE(otg_resources),
+};
+#endif
+/* *INDENT-ON* */
+
+static int __init mx37_usb_init(void)
+{
+ pr_debug("%s: \n", __func__);
+
+#if defined(CONFIG_USB_GADGET_ARC)
+ if (platform_device_register(&otg_udc_device)) {
+ printk(KERN_ERR "can't register OTG Gadget\n");
+ } else {
+ pr_debug("usb: OTG Gadget registered\n");
+ }
+#endif
+
+ return 0;
+}
+
+module_init(mx37_usb_init);
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 935fe2840ae2..f66e8061bad0 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -19,7 +19,7 @@ obj-$(CONFIG_ARCH_MX21) += dma_mx2.o
obj-$(CONFIG_ARCH_MX27) += dma_mx2.o usb_common.o
obj-$(CONFIG_ARCH_MX3) += dptc.o usb_common.o
obj-$(CONFIG_ARCH_MXC91321) += dptc.o
-
+obj-$(CONFIG_ARCH_MX37) += usb_common.o utmixc.o
obj-$(CONFIG_MXC_DSP_BRINGUP) += dsp_bringup.o
# LEDs support
diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c
index 7abbc8694d52..5f3a61fbc506 100644
--- a/arch/arm/plat-mxc/usb_common.c
+++ b/arch/arm/plat-mxc/usb_common.c
@@ -50,6 +50,8 @@ struct fsl_xcvr_ops *g_xc_ops[MXC_NUMBER_USB_TRANSCEIVER] = { NULL };
static struct clk *usb_clk;
static struct clk *usb_ahb_clk;
+extern int gpio_usbotg_hs_active(void);
+extern int gpio_usbotg_hs_inactive(void);
/*
* make sure USB_CLK is running at 60 MHz +/- 1000 Hz
*/
@@ -511,9 +513,6 @@ static void otg_set_ulpi_xcvr(void)
clk_disable(usb_clk);
}
-extern int gpio_usbotg_hs_active(void);
-extern int gpio_usbotg_hs_inactive(void);
-
int fsl_usb_xcvr_suspend(struct fsl_xcvr_ops *xcvr_ops)
{
if (!machine_is_mx31_3ds())
@@ -540,6 +539,31 @@ int fsl_usb_xcvr_suspend(struct fsl_xcvr_ops *xcvr_ops)
EXPORT_SYMBOL(fsl_usb_xcvr_suspend);
+static void otg_set_utmi_xcvr(void)
+{
+ u32 tmp;
+
+ USBCTRL &= ~UCTRL_OSIC_MASK;
+ USBCTRL |= UCTRL_OUIE | /* ULPI intr enable */
+ UCTRL_OWIE | /* OTG wakeup intr enable */
+ UCTRL_OPM; /* power mask */
+
+ /* set UTMI xcvr */
+ tmp = UOG_PORTSC1 & ~PORTSC_PTS_MASK;
+ tmp |= PORTSC_PTS_UTMI;
+ UOG_PORTSC1 = tmp;
+
+ /* need to reset the controller here so that the ID pin
+ * is correctly detected.
+ */
+ UOG_USBCMD |= UCMD_RESET;
+
+ /* allow controller to reset, and leave time for
+ * the ULPI transceiver to reset too.
+ */
+ msleep(100);
+}
+
static int otg_used = 0;
int usbotg_init(struct platform_device *pdev)
@@ -589,6 +613,8 @@ int usbotg_init(struct platform_device *pdev)
otg_set_serial_xcvr();
} else if (xops->xcvr_type == PORTSC_PTS_ULPI) {
otg_set_ulpi_xcvr();
+ } else if (xops->xcvr_type == PORTSC_PTS_UTMI) {
+ otg_set_utmi_xcvr();
}
} else {
fsl_usb_mem_map(pdev);
diff --git a/arch/arm/plat-mxc/utmixc.c b/arch/arm/plat-mxc/utmixc.c
new file mode 100644
index 000000000000..58024c33340f
--- /dev/null
+++ b/arch/arm/plat-mxc/utmixc.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/usb/fsl_xcvr.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/arc_otg.h>
+
+static void usb_utmi_init(struct fsl_xcvr_ops *this)
+{
+}
+
+static void usb_utmi_uninit(struct fsl_xcvr_ops *this)
+{
+}
+
+static struct fsl_xcvr_ops utmi_ops = {
+ .name = "utmi",
+ .xcvr_type = PORTSC_PTS_UTMI,
+ .init = usb_utmi_init,
+ .uninit = usb_utmi_uninit,
+};
+
+extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops);
+
+static int __init utmixc_init(void)
+{
+ fsl_usb_xcvr_register(&utmi_ops);
+ return 0;
+}
+
+extern void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops);
+
+static void __exit utmixc_exit(void)
+{
+ fsl_usb_xcvr_unregister(&utmi_ops);
+}
+
+module_init(utmixc_init);
+module_exit(utmixc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("utmi xcvr driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 47bad5979edd..1fe7a6237504 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -1978,7 +1978,8 @@ static void dtd_complete_irq(struct arcotg_udc *udc)
usb_slave_regs->endptcomplete = bit_pos;
/* Clear the buffer if the ACK was missing from the IN ep */
- if (usb_slave_regs->endptstatus & 0x10000)
+ if ((usb_slave_regs->endptstatus & 0x10000)
+ && !(usb_slave_regs->endptstatus & 1))
usb_slave_regs->endptflush |= 0x10000;
bit_pos = le32_to_cpu(bit_pos);
diff --git a/include/asm-arm/arch-mxc/mx37.h b/include/asm-arm/arch-mxc/mx37.h
index 28b7c938a061..33f5a4606f44 100644
--- a/include/asm-arm/arch-mxc/mx37.h
+++ b/include/asm-arm/arch-mxc/mx37.h
@@ -128,7 +128,7 @@
#define ROMCP_BASE_ADDR (AIPS1_BASE_ADDR + 0x000C0000)
#define RTIC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000C4000)
#define VPU_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D0000)
-#define USBOH2_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D4000)
+#define OTG_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D4000)
#define ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D8000)
#define MSHC1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E0000)
#define FEC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E8000)