diff options
author | Albert Chen <R65187@freescale.com> | 2008-03-17 14:02:12 +0800 |
---|---|---|
committer | Daniel Schaeffer <daniel.schaeffer@timesys.com> | 2008-08-25 15:20:49 -0400 |
commit | b44e2360f203ef6848ef8a5c8e3519db85cdc84e (patch) | |
tree | 9df2bd7241839f925a9675e03daab8abb6674010 | |
parent | 33dfa962241282facc7a270d285816876956a671 (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/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-mx37/clock.c | 22 | ||||
-rw-r--r-- | arch/arm/mach-mx37/crm_regs.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-mx37/mx37_3stack_gpio.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-mx37/usb.c | 142 | ||||
-rw-r--r-- | arch/arm/plat-mxc/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/plat-mxc/usb_common.c | 32 | ||||
-rw-r--r-- | arch/arm/plat-mxc/utmixc.c | 61 | ||||
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.c | 3 | ||||
-rw-r--r-- | include/asm-arm/arch-mxc/mx37.h | 2 |
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) |