summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2011-07-04 15:58:39 +0800
committerJason Liu <r64343@freescale.com>2012-01-09 20:18:33 +0800
commit62c4eaf233b829d68d8a9bae3291a1898ab8cc38 (patch)
treefe830646ae300f02fbc6db9a63af532168ed5faa /arch
parent93eae4ad58ea51c2fc3c660a2bedf245c0855800 (diff)
ENGR00152493-1 mx6q: add usb function
Changes at MSL - Add usb code for mx6q - Usb host functions (keyboard and u-disk) are verified - USB host low power mode and wakeup are supported - defconfig for otg port is for host port - Using upstream platform device register method - Delete some useless code, and fix the warning during building Signed-off-by: Peter Chen <peter.chen@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/configs/imx6_defconfig47
-rw-r--r--arch/arm/mach-mx6/Kconfig4
-rw-r--r--arch/arm/mach-mx6/Makefile2
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabreauto.c39
-rw-r--r--arch/arm/mach-mx6/devices-imx6q.h24
-rw-r--r--arch/arm/mach-mx6/usb.h58
-rw-r--r--arch/arm/mach-mx6/usb_dr.c442
-rw-r--r--arch/arm/mach-mx6/usb_h1.c267
-rwxr-xr-xarch/arm/plat-mxc/Makefile2
-rwxr-xr-xarch/arm/plat-mxc/devices/Kconfig6
-rwxr-xr-xarch/arm/plat-mxc/devices/Makefile2
-rw-r--r--arch/arm/plat-mxc/devices/platform-fsl-usb2-otg.c45
-rw-r--r--arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c7
-rw-r--r--arch/arm/plat-mxc/devices/platform-fsl-usb2-wakeup.c46
-rw-r--r--arch/arm/plat-mxc/devices/platform-mxc-ehci.c30
-rwxr-xr-xarch/arm/plat-mxc/include/mach/arc_otg.h163
-rwxr-xr-xarch/arm/plat-mxc/include/mach/devices-common.h21
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx6q.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/mx6.h24
-rw-r--r--arch/arm/plat-mxc/include/mach/regs-usbphy-mx6.h (renamed from arch/arm/mach-mx6/regs-usbphy.h)173
-rwxr-xr-xarch/arm/plat-mxc/usb_common.c180
-rwxr-xr-xarch/arm/plat-mxc/usb_wakeup.c73
22 files changed, 1346 insertions, 311 deletions
diff --git a/arch/arm/configs/imx6_defconfig b/arch/arm/configs/imx6_defconfig
index 10cc366d6d5f..335f3fd5f281 100644
--- a/arch/arm/configs/imx6_defconfig
+++ b/arch/arm/configs/imx6_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux/arm 2.6.38 Kernel Configuration
-# Tue Jun 28 11:08:47 2011
+# Mon Jul 4 11:22:32 2011
#
CONFIG_ARM=y
CONFIG_HAVE_PWM=y
@@ -252,9 +252,12 @@ CONFIG_ARCH_MXC=y
# CONFIG_PLAT_SPEAR is not set
CONFIG_GPIO_PCA953X=y
CONFIG_IMX_HAVE_PLATFORM_FEC=y
+CONFIG_IMX_HAVE_PLATFORM_IMX_I2C=y
CONFIG_IMX_HAVE_PLATFORM_IMX_UART=y
CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX=y
CONFIG_IMX_HAVE_PLATFORM_SPI_IMX=y
+CONFIG_IMX_HAVE_PLATFORM_VIV_GPU=y
+CONFIG_IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL=y
#
# Freescale MXC Implementations
@@ -1100,7 +1103,7 @@ CONFIG_GPIOLIB=y
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
-# CONFIG_THERMAL is not set
+CONFIG_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
@@ -1222,10 +1225,10 @@ CONFIG_USB=y
# Miscellaneous USB options
#
# CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_SUSPEND=y
-CONFIG_USB_OTG=y
+# CONFIG_USB_OTG is not set
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_MON is not set
@@ -1317,35 +1320,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_TEST is not set
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_YUREX is not set
-CONFIG_USB_GADGET=y
-# CONFIG_USB_GADGET_DEBUG_FILES is not set
-CONFIG_USB_GADGET_VBUS_DRAW=2
-CONFIG_USB_GADGET_SELECTED=y
-# CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_R8A66597 is not set
-# CONFIG_USB_GADGET_PXA_U2O is not set
-# CONFIG_USB_GADGET_M66592 is not set
-CONFIG_USB_GADGET_ARC=y
-CONFIG_USB_ARC=y
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
-CONFIG_USB_ETH=m
-CONFIG_USB_ETH_RNDIS=y
-# CONFIG_USB_ETH_EEM is not set
-# CONFIG_USB_G_NCM is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FUNCTIONFS is not set
-CONFIG_USB_FILE_STORAGE=m
-# CONFIG_FSL_UTP is not set
-# CONFIG_USB_FILE_STORAGE_TEST is not set
-# CONFIG_USB_MASS_STORAGE is not set
-CONFIG_USB_G_SERIAL=m
-# CONFIG_USB_G_PRINTER is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
-# CONFIG_USB_G_MULTI is not set
-# CONFIG_USB_G_HID is not set
-# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_GADGET is not set
#
# OTG and related infrastructure
@@ -1354,7 +1329,6 @@ CONFIG_USB_OTG_UTILS=y
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_USB_ULPI is not set
# CONFIG_NOP_USB_XCEIV is not set
-CONFIG_MXC_OTG=y
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_UNSAFE_RESUME=y
@@ -1529,6 +1503,11 @@ CONFIG_CLKDEV_LOOKUP=y
#
#
+# ANATOP_THERMAL
+#
+CONFIG_ANATOP_THERMAL=y
+
+#
# File systems
#
CONFIG_EXT2_FS=y
diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig
index 0d9b07bc65cb..a1cd8dfca158 100644
--- a/arch/arm/mach-mx6/Kconfig
+++ b/arch/arm/mach-mx6/Kconfig
@@ -27,6 +27,10 @@ config MACH_MX6Q_SABREAUTO
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_VIV_GPU
select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_FSL_OTG
+ select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP
help
Include support for i.MX 6Quad SABRE Automotive Infotainment platform. This includes specific
configurations for the board and its peripherals.
diff --git a/arch/arm/mach-mx6/Makefile b/arch/arm/mach-mx6/Makefile
index e6274bd41c3c..99b5623f3fad 100644
--- a/arch/arm/mach-mx6/Makefile
+++ b/arch/arm/mach-mx6/Makefile
@@ -3,7 +3,7 @@
#
# Object file lists.
-obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o
+obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_dr.o usb_h1.o
obj-$(CONFIG_ARCH_MX6) += clock.o
obj-$(CONFIG_MACH_MX6Q_SABREAUTO) += board-mx6q_sabreauto.o
diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
index b90fb342219b..abdc28dd6269 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
@@ -60,12 +60,15 @@
#include <linux/gpio.h>
#include <linux/etherdevice.h>
+#include "usb.h"
#include "devices-imx6q.h"
+#include "regs-anadig.h"
#define MX6Q_SABREAUTO_ECSPI1_CS0 IMX_GPIO_NR(2, 30)
#define MX6Q_SABREAUTO_ECSPI1_CS1 IMX_GPIO_NR(3, 19)
#define MX6Q_SABREAUTO_SD3_CD IMX_GPIO_NR(6, 11)
#define MX6Q_SABREAUTO_SD3_WP IMX_GPIO_NR(6, 14)
+#define MX6Q_SABREAUTO_USB_OTG_PWR IMX_GPIO_NR(3, 22)
#define MX6Q_SABREAUTO_MAX7310_1_BASE_ADDR IMX_GPIO_NR(8, 0)
#define MX6Q_SABREAUTO_MAX7310_2_BASE_ADDR IMX_GPIO_NR(8, 8)
#define MX6Q_SABREAUTO_CAP_TCH_INT IMX_GPIO_NR(3, 31)
@@ -150,6 +153,7 @@ static iomux_v3_cfg_t mx6q_sabreauto_pads[] = {
/* I2C3 */
MX6Q_PAD_GPIO_5__I2C3_SCL,
MX6Q_PAD_GPIO_16__I2C3_SDA,
+ MX6Q_PAD_GPIO_1__USBOTG_ID,
};
static const struct esdhc_platform_data mx6q_sabreauto_sd3_data __initconst = {
.cd_gpio = MX6Q_SABREAUTO_SD3_CD,
@@ -270,6 +274,40 @@ static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {
},
};
+static void imx6q_sabreauto_usbotg_vbus(bool on)
+{
+ if (on)
+ gpio_set_value(MX6Q_SABREAUTO_USB_OTG_PWR, 1);
+ else
+ gpio_set_value(MX6Q_SABREAUTO_USB_OTG_PWR, 0);
+}
+
+static void __init imx6q_sabreauto_init_usb(void)
+{
+ int ret = 0;
+ void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR);
+
+ imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR);
+ /* disable external charger detect, or it will affect signal quality at dp */
+ __raw_writel(BM_ANADIG_USB1_CHRG_DETECT_EN_B \
+ | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B, \
+ anatop_base_addr + HW_ANADIG_USB1_CHRG_DETECT);
+ __raw_writel(BM_ANADIG_USB2_CHRG_DETECT_EN_B \
+ | BM_ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, \
+ anatop_base_addr + HW_ANADIG_USB2_CHRG_DETECT);
+
+ ret = gpio_request(MX6Q_SABREAUTO_USB_OTG_PWR, "usb-pwr");
+ if (ret) {
+ printk(KERN_ERR"failed to get GPIO MX6Q_SABREAUTO_USB_OTG_PWR: %d\n", ret);
+ return;
+ }
+ gpio_direction_output(MX6Q_SABREAUTO_USB_OTG_PWR, 0);
+ mxc_iomux_set_gpr_register(1, 13, 1, 1);
+
+ mx6_set_otghost_vbus_func(imx6q_sabreauto_usbotg_vbus);
+ mx6_usb_dr_init();
+ mx6_usb_h1_init();
+}
static struct viv_gpu_platform_data imx6q_gc2000_pdata __initdata = {
.reserved_mem_size = SZ_128M,
};
@@ -293,6 +331,7 @@ static void __init mx6_board_init(void)
imx6q_add_sdhci_usdhc_imx(3, &mx6q_sabreauto_sd4_data);
imx_add_viv_gpu("gc2000", &imx6_gc2000_data, &imx6q_gc2000_pdata);
+ imx6q_sabreauto_init_usb();
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h
index e46f6566ff3b..ed8298ba9db7 100644
--- a/arch/arm/mach-mx6/devices-imx6q.h
+++ b/arch/arm/mach-mx6/devices-imx6q.h
@@ -45,6 +45,30 @@ extern const struct imx_imx_i2c_data imx6q_imx_i2c_data[] __initconst;
#define imx6q_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx6q_imx_i2c_data[id], pdata)
+extern const struct imx_fsl_usb2_udc_data imx6q_fsl_usb2_udc_data __initconst;
+#define imx6q_add_fsl_usb2_udc(pdata) \
+ imx_add_fsl_usb2_udc(&imx6q_fsl_usb2_udc_data, pdata)
+
+extern const struct imx_mxc_ehci_data imx6q_mxc_ehci_otg_data __initconst;
+#define imx6q_add_fsl_ehci_otg(pdata) \
+ imx_add_fsl_ehci(&imx6q_mxc_ehci_otg_data, pdata)
+
+extern const struct imx_mxc_ehci_data imx6q_mxc_ehci_hs_data[] __initconst;
+#define imx6q_add_fsl_ehci_hs(id, pdata) \
+ imx_add_fsl_ehci(&imx6q_mxc_ehci_hs_data[id - 1], pdata)
+
+extern const struct imx_fsl_usb2_otg_data imx6q_fsl_usb2_otg_data __initconst;
+#define imx6q_add_fsl_usb2_otg(pdata) \
+ imx_add_fsl_usb2_otg(&imx6q_fsl_usb2_otg_data, pdata)
+
+extern const struct imx_fsl_usb2_wakeup_data imx6q_fsl_otg_wakeup_data __initconst;
+#define imx6q_add_fsl_usb2_otg_wakeup(pdata) \
+ imx_add_fsl_usb2_wakeup(&imx6q_fsl_otg_wakeup_data, pdata)
+
+extern const struct imx_fsl_usb2_wakeup_data imx6q_fsl_hs_wakeup_data[] __initconst;
+#define imx6q_add_fsl_usb2_hs_wakeup(id, pdata) \
+ imx_add_fsl_usb2_wakeup(&imx6q_fsl_hs_wakeup_data[id - 1], pdata)
+
extern const struct imx_viv_gpu_data imx6_gc2000_data __initconst;
extern const struct imx_viv_gpu_data imx6_gc320_data __initconst;
extern const struct imx_viv_gpu_data imx6_gc355_data __initconst;
diff --git a/arch/arm/mach-mx6/usb.h b/arch/arm/mach-mx6/usb.h
new file mode 100644
index 000000000000..88f14d028380
--- /dev/null
+++ b/arch/arm/mach-mx6/usb.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <mach/common.h>
+
+extern int usbotg_init(struct platform_device *pdev);
+extern void usbotg_uninit(struct fsl_usb2_platform_data *pdata);
+extern struct platform_device *host_pdev_register(struct resource *res,
+ int n_res, struct fsl_usb2_platform_data *config);
+
+extern int fsl_usb_host_init(struct platform_device *pdev);
+extern void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata);
+extern int gpio_usbotg_utmi_active(void);
+extern void gpio_usbotg_utmi_inactive(void);
+
+extern void __init mx6_usb_dr_init(void);
+extern void __init mx6_usb_h1_init(void);
+
+typedef void (*driver_vbus_func)(bool);
+extern void mx6_set_host1_vbus_func(driver_vbus_func);
+extern void mx6_set_otghost_vbus_func(driver_vbus_func);
+extern struct platform_device anatop_thermal_device;
+extern struct platform_device mxc_usbdr_otg_device;
+extern struct platform_device mxc_usbdr_udc_device;
+extern struct platform_device mxc_usbdr_host_device;
+extern struct platform_device mxc_usbdr_wakeup_device;
+extern struct platform_device mxc_usbh1_device;
+extern struct platform_device mxc_usbh1_wakeup_device;
+
+/*
+ * Used to set pdata->operating_mode before registering the platform_device.
+ * If OTG is configured, the controller operates in OTG mode,
+ * otherwise it's either host or device.
+ */
+#ifdef CONFIG_USB_OTG
+#define DR_UDC_MODE FSL_USB2_DR_OTG
+#define DR_HOST_MODE FSL_USB2_DR_OTG
+#else
+#define DR_UDC_MODE FSL_USB2_DR_DEVICE
+#define DR_HOST_MODE FSL_USB2_DR_HOST
+#endif
+
+extern void __iomem *imx_otg_base;
diff --git a/arch/arm/mach-mx6/usb_dr.c b/arch/arm/mach-mx6/usb_dr.c
new file mode 100644
index 000000000000..c2441c7ad8e6
--- /dev/null
+++ b/arch/arm/mach-mx6/usb_dr.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <mach/arc_otg.h>
+#include <mach/hardware.h>
+#include "devices-imx6q.h"
+#include "usb.h"
+static int usbotg_init_ext(struct platform_device *pdev);
+static void usbotg_uninit_ext(struct platform_device *pdev);
+static void usbotg_clock_gate(bool on);
+
+static struct clk *usb_phy1_clk;
+static struct clk *usb_oh3_clk;
+static void usbotg_wakeup_event_clear(void);
+extern int clk_get_usecount(struct clk *clk);
+
+/* Beginning of Common operation for DR port */
+
+/*
+ * platform data structs
+ * - Which one to use is determined by CONFIG options in usb.h
+ * - operating_mode plugged at run time
+ */
+static struct fsl_usb2_platform_data dr_utmi_config = {
+ .name = "DR",
+ .init = usbotg_init_ext,
+ .exit = usbotg_uninit_ext,
+ .phy_mode = FSL_USB2_PHY_UTMI_WIDE,
+ .power_budget = 500, /* 500 mA max power */
+ .usb_clock_for_pm = usbotg_clock_gate,
+ .transceiver = "utmi",
+ .phy_regs = USB_PHY0_BASE_ADDR,
+};
+
+/* Platform data for wakeup operation */
+static struct fsl_usb2_wakeup_platform_data dr_wakeup_config = {
+ .name = "DR wakeup",
+ .usb_clock_for_pm = usbotg_clock_gate,
+ .usb_wakeup_exhandle = usbotg_wakeup_event_clear,
+};
+
+static void usbotg_internal_phy_clock_gate(bool on)
+{
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR);
+ if (on) {
+ __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_CLR);
+ } else {
+ __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_SET);
+ }
+}
+
+static int usb_phy_enable(struct fsl_usb2_platform_data *pdata)
+{
+ u32 tmp;
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR);
+ void __iomem *phy_ctrl;
+
+ /* Stop then Reset */
+ UOG_USBCMD &= ~UCMD_RUN_STOP;
+ while (UOG_USBCMD & UCMD_RUN_STOP)
+ ;
+
+ UOG_USBCMD |= UCMD_RESET;
+ while ((UOG_USBCMD) & (UCMD_RESET))
+ ;
+ /* Reset USBPHY module */
+ phy_ctrl = phy_reg + HW_USBPHY_CTRL;
+ tmp = __raw_readl(phy_ctrl);
+ tmp |= BM_USBPHY_CTRL_SFTRST;
+ __raw_writel(tmp, phy_ctrl);
+ udelay(10);
+
+ /* Remove CLKGATE and SFTRST */
+ tmp = __raw_readl(phy_ctrl);
+ tmp &= ~(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST);
+ __raw_writel(tmp, phy_ctrl);
+ udelay(10);
+
+ /* Power up the PHY */
+ __raw_writel(0, phy_reg + HW_USBPHY_PWD);
+ if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
+ (pdata->operating_mode == FSL_USB2_DR_OTG)) {
+ /* enable FS/LS device */
+ __raw_writel(BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3
+ , phy_reg + HW_USBPHY_CTRL_SET);
+ }
+
+
+ return 0;
+}
+/* Notes: configure USB clock*/
+static int usbotg_init_ext(struct platform_device *pdev)
+{
+ struct clk *usb_clk;
+ u32 ret;
+
+ /* at mx6q: this clock is AHB clock for usb core */
+ usb_clk = clk_get(NULL, "usboh3_clk");
+ clk_enable(usb_clk);
+ usb_oh3_clk = usb_clk;
+
+ usb_clk = clk_get(NULL, "usb_phy1_clk");
+ clk_enable(usb_clk);
+ usb_phy1_clk = usb_clk;
+
+ ret = usbotg_init(pdev);
+ if (ret) {
+ printk(KERN_ERR "otg init fails......\n");
+ return ret;
+ }
+ usbotg_internal_phy_clock_gate(true);
+ usb_phy_enable(pdev->dev.platform_data);
+ return ret;
+}
+
+static void usbotg_uninit_ext(struct platform_device *pdev)
+{
+ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+ clk_disable(usb_phy1_clk);
+ clk_put(usb_phy1_clk);
+
+ clk_disable(usb_oh3_clk);
+ clk_put(usb_oh3_clk);
+
+ usbotg_uninit(pdata);
+}
+
+static void usbotg_clock_gate(bool on)
+{
+ pr_debug("%s: on is %d\n", __func__, on);
+ if (on) {
+ clk_enable(usb_oh3_clk);
+ clk_enable(usb_phy1_clk);
+ } else {
+ clk_disable(usb_phy1_clk);
+ clk_disable(usb_oh3_clk);
+ }
+ pr_debug("usb_oh3_clk:%d, usb_phy_clk1_ref_count:%d\n", clk_get_usecount(usb_oh3_clk), clk_get_usecount(usb_phy1_clk));
+}
+
+void mx6_set_otghost_vbus_func(driver_vbus_func driver_vbus)
+{
+ dr_utmi_config.platform_driver_vbus = driver_vbus;
+}
+/* Below two macros are used at otg mode to indicate usb mode*/
+#define ENABLED_BY_HOST (0x1 << 0)
+#define ENABLED_BY_DEVICE (0x1 << 1)
+static u32 low_power_enable_src; /* only useful at otg mode */
+static void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR);
+ u32 tmp;
+ pr_debug("DR: %s begins, enable is %d\n", __func__, enable);
+
+ if (enable) {
+ UOG_PORTSC1 |= PORTSC_PHCD;
+ tmp = (BM_USBPHY_PWD_TXPWDFS
+ | BM_USBPHY_PWD_TXPWDIBIAS
+ | BM_USBPHY_PWD_TXPWDV2I
+ | BM_USBPHY_PWD_RXPWDENV
+ | BM_USBPHY_PWD_RXPWD1PT1
+ | BM_USBPHY_PWD_RXPWDDIFF
+ | BM_USBPHY_PWD_RXPWDRX);
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET);
+ usbotg_internal_phy_clock_gate(false);
+
+ } else {
+ if (UOG_PORTSC1 & PORTSC_PHCD) {
+ UOG_PORTSC1 &= ~PORTSC_PHCD;
+ mdelay(1);
+ }
+ usbotg_internal_phy_clock_gate(true);
+ tmp = (BM_USBPHY_PWD_TXPWDFS
+ | BM_USBPHY_PWD_TXPWDIBIAS
+ | BM_USBPHY_PWD_TXPWDV2I
+ | BM_USBPHY_PWD_RXPWDENV
+ | BM_USBPHY_PWD_RXPWD1PT1
+ | BM_USBPHY_PWD_RXPWDDIFF
+ | BM_USBPHY_PWD_RXPWDRX);
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR);
+
+ }
+ pr_debug("DR: %s ends, enable is %d\n", __func__, enable);
+}
+
+static void __phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable, int source)
+{
+ if (enable) {
+ low_power_enable_src |= source;
+#ifdef CONFIG_USB_OTG
+ if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
+ pr_debug("phy lowpower enabled\n");
+ enter_phy_lowpower_suspend(pdata, enable);
+ }
+#else
+ enter_phy_lowpower_suspend(pdata, enable);
+#endif
+ } else {
+ pr_debug("phy lowpower disable\n");
+ enter_phy_lowpower_suspend(pdata, enable);
+ low_power_enable_src &= ~source;
+ }
+}
+
+static void otg_wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR);
+
+ pr_debug("%s, enable is %d\n", __func__, enable);
+ if (enable) {
+ __raw_writel(BM_USBPHY_CTRL_ENIDCHG_WKUP | BM_USBPHY_CTRL_ENVBUSCHG_WKUP
+ | BM_USBPHY_CTRL_ENDPDMCHG_WKUP
+ | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS
+ | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD
+ | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE
+ | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE
+ | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_SET);
+ USB_OTG_CTRL |= UCTRL_OWIE;
+ } else {
+ USB_OTG_CTRL &= ~UCTRL_OWIE;
+ /* The interrupt must be disabled for at least 3 clock
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+
+static u32 wakeup_irq_enable_src; /* only useful at otg mode */
+static void __wakeup_irq_enable(struct fsl_usb2_platform_data *pdata, bool on, int source)
+ {
+ /* otg host and device share the OWIE bit, only when host and device
+ * all enable the wakeup irq, we can enable the OWIE bit
+ */
+ if (on) {
+#ifdef CONFIG_USB_OTG
+ wakeup_irq_enable_src |= source;
+ if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
+ otg_wake_up_enable(pdata, on);
+ }
+#else
+ otg_wake_up_enable(pdata, on);
+#endif
+ } else {
+ otg_wake_up_enable(pdata, on);
+ wakeup_irq_enable_src &= ~source;
+ /* The interrupt must be disabled for at least 3 clock
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+
+/* The wakeup operation for DR port, it will clear the wakeup irq status
+ * and re-enable the wakeup
+ */
+static void usbotg_wakeup_event_clear(void)
+{
+ int wakeup_req = USB_OTG_CTRL & UCTRL_OWIR;
+
+ if (wakeup_req != 0) {
+ printk(KERN_INFO "Unknown wakeup.(OTGSC 0x%x)\n", UOG_OTGSC);
+ /* Disable OWIE to clear OWIR, wait 3 clock
+ * cycles of standly clock(32KHz)
+ */
+ USB_OTG_CTRL &= ~UCTRL_OWIE;
+ udelay(100);
+ USB_OTG_CTRL |= UCTRL_OWIE;
+ }
+}
+
+/* End of Common operation for DR port */
+
+#ifdef CONFIG_USB_EHCI_ARC_OTG
+/* Beginning of host related operation for DR port */
+static void _host_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __phy_lowpower_suspend(pdata, enable, ENABLED_BY_HOST);
+}
+
+static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __wakeup_irq_enable(pdata, enable, ENABLED_BY_HOST);
+ if (enable) {
+ pr_debug("host wakeup enable\n");
+ USB_OTG_CTRL |= UCTRL_WKUP_ID_EN;
+ } else {
+ pr_debug("host wakeup disable\n");
+ USB_OTG_CTRL &= ~UCTRL_WKUP_ID_EN;
+ /* The interrupt must be disabled for at least 3 clock
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+ pr_debug("the otgsc is 0x%x, usbsts is 0x%x, portsc is 0x%x, otgctrl: 0x%x\n", UOG_OTGSC, UOG_USBSTS, UOG_PORTSC1, USB_OTG_CTRL);
+}
+
+static enum usb_wakeup_event _is_host_wakeup(struct fsl_usb2_platform_data *pdata)
+{
+ u32 wakeup_req = USB_OTG_CTRL & UCTRL_OWIR;
+ u32 otgsc = UOG_OTGSC;
+
+ if (wakeup_req) {
+ pr_debug("the otgsc is 0x%x, usbsts is 0x%x, portsc is 0x%x, wakeup_irq is 0x%x\n", UOG_OTGSC, UOG_USBSTS, UOG_PORTSC1, wakeup_req);
+ }
+ /* if ID change sts, it is a host wakeup event */
+ if (wakeup_req && (otgsc & OTGSC_IS_USB_ID)) {
+ pr_debug("otg host ID wakeup\n");
+ /* if host ID wakeup, we must clear the b session change sts */
+ otgsc &= (~OTGSC_IS_USB_ID);
+ return WAKEUP_EVENT_ID;
+ }
+ if (wakeup_req && (!(otgsc & OTGSC_STS_USB_ID))) {
+ pr_debug("otg host Remote wakeup\n");
+ return WAKEUP_EVENT_DPDM;
+ }
+ return WAKEUP_EVENT_INVALID;
+}
+
+static void host_wakeup_handler(struct fsl_usb2_platform_data *pdata)
+{
+ _host_phy_lowpower_suspend(pdata, false);
+ _host_wakeup_enable(pdata, false);
+ pdata->wakeup_event = 1;
+}
+/* End of host related operation for DR port */
+#endif /* CONFIG_USB_EHCI_ARC_OTG */
+
+
+#ifdef CONFIG_USB_GADGET_ARC
+/* Beginning of device related operation for DR port */
+static void _device_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __phy_lowpower_suspend(pdata, enable, ENABLED_BY_DEVICE);
+}
+
+static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __wakeup_irq_enable(pdata, enable, ENABLED_BY_DEVICE);
+ /* if udc is not used by any gadget, we can not enable the vbus wakeup */
+ if (!pdata->port_enables) {
+ USB_OTG_CTRL &= ~UCTRL_WKUP_VBUS_EN;
+ return;
+ }
+ if (enable) {
+ pr_debug("device wakeup enable\n");
+ USB_OTG_CTRL |= UCTRL_WKUP_VBUS_EN;
+ } else {
+ pr_debug("device wakeup disable\n");
+ USB_OTG_CTRL &= ~UCTRL_WKUP_VBUS_EN;
+ }
+}
+
+static enum usb_wakeup_event _is_device_wakeup(struct fsl_usb2_platform_data *pdata)
+{
+ int wakeup_req = USB_OTG_CTRL & UCTRL_OWIR;
+ pr_debug("%s\n", __func__);
+
+ /* if ID=1, it is a device wakeup event */
+ if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && (UOG_PORTSC1 & PORTSC_PORT_FORCE_RESUME)) {
+ printk(KERN_INFO "otg udc wakeup, host sends resume signal\n");
+ return true;
+ }
+ if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && (UOG_USBSTS & USBSTS_URI)) {
+ printk(KERN_INFO "otg udc wakeup, host sends reset signal\n");
+ return true;
+ }
+ if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && (UOG_OTGSC & OTGSC_STS_A_VBUS_VALID) \
+ && (UOG_OTGSC & OTGSC_IS_B_SESSION_VALID)) {
+ printk(KERN_INFO "otg udc vbus rising wakeup\n");
+ return true;
+ }
+ if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && !(UOG_OTGSC & OTGSC_STS_A_VBUS_VALID)) {
+ printk(KERN_INFO "otg udc vbus falling wakeup\n");
+ return true;
+ }
+
+ return WAKEUP_EVENT_INVALID;
+}
+
+static void device_wakeup_handler(struct fsl_usb2_platform_data *pdata)
+{
+ _device_phy_lowpower_suspend(pdata, false);
+ _device_wakeup_enable(pdata, false);
+}
+
+/* end of device related operation for DR port */
+#endif /* CONFIG_USB_GADGET_ARC */
+
+void __init mx6_usb_dr_init(void)
+{
+ struct platform_device *pdev;
+#ifdef CONFIG_USB_OTG
+ /* wake_up_enable is useless, just for usb_register_remote_wakeup execution*/
+ dr_utmi_config.wake_up_enable = _device_wakeup_enable;
+ dr_utmi_config.operating_mode = FSL_USB2_DR_OTG;
+ dr_utmi_config.wakeup_pdata = &dr_wakeup_config;
+ pdev = imx6q_add_fsl_usb2_otg(&dr_utmi_config);
+ dr_wakeup_config.usb_pdata[0] = pdev->dev.platform_data;
+#endif
+#ifdef CONFIG_USB_EHCI_ARC_OTG
+ dr_utmi_config.operating_mode = DR_HOST_MODE;
+ dr_utmi_config.wake_up_enable = _host_wakeup_enable;
+ dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend;
+ dr_utmi_config.is_wakeup_event = _is_host_wakeup;
+ dr_utmi_config.wakeup_pdata = &dr_wakeup_config;
+ dr_utmi_config.wakeup_handler = host_wakeup_handler;
+ pdev = imx6q_add_fsl_ehci_otg(&dr_utmi_config);
+ dr_wakeup_config.usb_pdata[1] = pdev->dev.platform_data;
+#endif
+#ifdef CONFIG_USB_GADGET_ARC
+ dr_utmi_config.operating_mode = DR_UDC_MODE;
+ dr_utmi_config.wake_up_enable = _device_wakeup_enable;
+ dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend;
+ dr_utmi_config.is_wakeup_event = _is_device_wakeup;
+ dr_utmi_config.wakeup_pdata = &dr_wakeup_config;
+ dr_utmi_config.wakeup_handler = device_wakeup_handler;
+ pdev = imx6q_add_fsl_usb2_udc(&dr_utmi_config);
+ dr_wakeup_config.usb_pdata[2] = pdev->dev.platform_data;
+#endif
+ /* register wakeup device */
+ imx6q_add_fsl_usb2_otg_wakeup(&dr_wakeup_config);
+}
diff --git a/arch/arm/mach-mx6/usb_h1.c b/arch/arm/mach-mx6/usb_h1.c
new file mode 100644
index 000000000000..2261235fe879
--- /dev/null
+++ b/arch/arm/mach-mx6/usb_h1.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <mach/arc_otg.h>
+#include <mach/hardware.h>
+#include "devices-imx6q.h"
+#include "usb.h"
+
+static struct clk *usb_phy2_clk;
+static struct clk *usb_oh3_clk;
+extern int clk_get_usecount(struct clk *clk);
+static struct fsl_usb2_platform_data usbh1_config;
+
+static void usbh1_internal_phy_clock_gate(bool on)
+{
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
+ if (on) {
+ __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_CLR);
+ } else {
+ __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_SET);
+ }
+}
+
+static int usb_phy_enable(struct fsl_usb2_platform_data *pdata)
+{
+ u32 tmp;
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
+ void __iomem *phy_ctrl;
+
+ /* Stop then Reset */
+ UH1_USBCMD &= ~UCMD_RUN_STOP;
+ while (UH1_USBCMD & UCMD_RUN_STOP)
+ ;
+
+ UH1_USBCMD |= UCMD_RESET;
+ while ((UH1_USBCMD) & (UCMD_RESET))
+ ;
+ /* Reset USBPHY module */
+ phy_ctrl = phy_reg + HW_USBPHY_CTRL;
+ tmp = __raw_readl(phy_ctrl);
+ tmp |= BM_USBPHY_CTRL_SFTRST;
+ __raw_writel(tmp, phy_ctrl);
+ udelay(10);
+
+ /* Remove CLKGATE and SFTRST */
+ tmp = __raw_readl(phy_ctrl);
+ tmp &= ~(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST);
+ __raw_writel(tmp, phy_ctrl);
+ udelay(10);
+
+ /* Power up the PHY */
+ __raw_writel(0, phy_reg + HW_USBPHY_PWD);
+ /* enable FS/LS device */
+ tmp = __raw_readl(phy_reg + HW_USBPHY_CTRL);
+ tmp |= (BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3);
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL);
+
+ return 0;
+}
+static int fsl_usb_host_init_ext(struct platform_device *pdev)
+{
+ int ret;
+ struct clk *usb_clk;
+ usb_clk = clk_get(NULL, "usboh3_clk");
+ clk_enable(usb_clk);
+ usb_oh3_clk = usb_clk;
+
+ usb_clk = clk_get(NULL, "usb_phy2_clk");
+ clk_enable(usb_clk);
+ usb_phy2_clk = usb_clk;
+
+ ret = fsl_usb_host_init(pdev);
+ if (ret) {
+ printk(KERN_ERR "host1 init fails......\n");
+ return ret;
+ }
+ usbh1_internal_phy_clock_gate(true);
+ usb_phy_enable(pdev->dev.platform_data);
+
+ return 0;
+}
+
+static void fsl_usb_host_uninit_ext(struct platform_device *pdev)
+{
+ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+ fsl_usb_host_uninit(pdata);
+
+ clk_disable(usb_oh3_clk);
+ clk_put(usb_oh3_clk);
+
+ clk_disable(usb_phy2_clk);
+ clk_put(usb_phy2_clk);
+
+}
+
+static void usbh1_clock_gate(bool on)
+{
+ pr_debug("%s: on is %d\n", __func__, on);
+ if (on) {
+ clk_enable(usb_oh3_clk);
+ clk_enable(usb_phy2_clk);
+ } else {
+ clk_disable(usb_phy2_clk);
+ clk_disable(usb_oh3_clk);
+ }
+}
+
+void mx6_set_host1_vbus_func(driver_vbus_func driver_vbus)
+{
+ usbh1_config.platform_driver_vbus = driver_vbus;
+}
+
+static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
+
+ pr_debug("host1, %s, enable is %d\n", __func__, enable);
+ if (enable) {
+ __raw_writel(BM_USBPHY_CTRL_ENIDCHG_WKUP | BM_USBPHY_CTRL_ENVBUSCHG_WKUP
+ | BM_USBPHY_CTRL_ENDPDMCHG_WKUP
+ | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS
+ | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD
+ | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE
+ | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE
+ | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_SET);
+ USB_H1_CTRL |= (UCTRL_OWIE | UCTRL_WKUP_ID_EN);
+ } else {
+ USB_H1_CTRL &= ~(UCTRL_OWIE | UCTRL_WKUP_ID_EN);
+ /* The interrupt must be disabled for at least 3
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+
+static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ u32 tmp;
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
+ pr_debug("host1, %s, enable is %d\n", __func__, enable);
+ if (enable) {
+ UH1_PORTSC1 |= PORTSC_PHCD;
+
+ pr_debug("%s, Poweroff UTMI \n", __func__);
+
+ tmp = (BM_USBPHY_PWD_TXPWDFS
+ | BM_USBPHY_PWD_TXPWDIBIAS
+ | BM_USBPHY_PWD_TXPWDV2I
+ | BM_USBPHY_PWD_RXPWDENV
+ | BM_USBPHY_PWD_RXPWD1PT1
+ | BM_USBPHY_PWD_RXPWDDIFF
+ | BM_USBPHY_PWD_RXPWDRX);
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET);
+
+ usbh1_internal_phy_clock_gate(false);
+ } else {
+ if (UH1_PORTSC1 & PORTSC_PHCD) {
+ UH1_PORTSC1 &= ~PORTSC_PHCD;
+ mdelay(1);
+ }
+ usbh1_internal_phy_clock_gate(true);
+ tmp = (BM_USBPHY_PWD_TXPWDFS
+ | BM_USBPHY_PWD_TXPWDIBIAS
+ | BM_USBPHY_PWD_TXPWDV2I
+ | BM_USBPHY_PWD_RXPWDENV
+ | BM_USBPHY_PWD_RXPWD1PT1
+ | BM_USBPHY_PWD_RXPWDDIFF
+ | BM_USBPHY_PWD_RXPWDRX);
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR);
+
+ }
+}
+
+static enum usb_wakeup_event _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata)
+{
+ u32 wakeup_req = USB_H1_CTRL & UCTRL_OWIR;
+ u32 otgsc = UOG_OTGSC;
+
+ if (wakeup_req) {
+ pr_debug("the otgsc is 0x%x, usbsts is 0x%x, portsc is 0x%x, wakeup_irq is 0x%x\n", UOG_OTGSC, UOG_USBSTS, UOG_PORTSC1, wakeup_req);
+ }
+ /* if ID change sts, it is a host wakeup event */
+ if (wakeup_req && (otgsc & OTGSC_IS_USB_ID)) {
+ pr_debug("otg host ID wakeup\n");
+ /* if host ID wakeup, we must clear the b session change sts */
+ otgsc &= (~OTGSC_IS_USB_ID);
+ return WAKEUP_EVENT_ID;
+ }
+ if (wakeup_req && (!(otgsc & OTGSC_STS_USB_ID))) {
+ pr_debug("otg host Remote wakeup\n");
+ return WAKEUP_EVENT_DPDM;
+ }
+ return WAKEUP_EVENT_INVALID;
+}
+
+static void h1_wakeup_handler(struct fsl_usb2_platform_data *pdata)
+{
+ _wake_up_enable(pdata, false);
+ _phy_lowpower_suspend(pdata, false);
+ pdata->wakeup_event = 1;
+}
+
+static void usbh1_wakeup_event_clear(void)
+{
+ void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
+ u32 wakeup_irq_bits;
+
+ wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+ if (__raw_readl(phy_reg + HW_USBPHY_CTRL) && wakeup_irq_bits) {
+ /* clear the wakeup interrupt status */
+ __raw_writel(wakeup_irq_bits, phy_reg + HW_USBPHY_CTRL_CLR);
+ }
+}
+
+static struct fsl_usb2_platform_data usbh1_config = {
+ .name = "Host 1",
+ .init = fsl_usb_host_init_ext,
+ .exit = fsl_usb_host_uninit_ext,
+ .operating_mode = FSL_USB2_MPH_HOST,
+ .phy_mode = FSL_USB2_PHY_UTMI_WIDE,
+ .power_budget = 500, /* 500 mA max power */
+ .wake_up_enable = _wake_up_enable,
+ .usb_clock_for_pm = usbh1_clock_gate,
+ .phy_lowpower_suspend = _phy_lowpower_suspend,
+ .is_wakeup_event = _is_usbh1_wakeup,
+ .wakeup_handler = h1_wakeup_handler,
+ .transceiver = "utmi",
+ .phy_regs = USB_PHY1_BASE_ADDR,
+};
+static struct fsl_usb2_wakeup_platform_data usbh1_wakeup_config = {
+ .name = "USBH1 wakeup",
+ .usb_clock_for_pm = usbh1_clock_gate,
+ .usb_pdata = {&usbh1_config, NULL, NULL},
+ .usb_wakeup_exhandle = usbh1_wakeup_event_clear,
+};
+
+void __init mx6_usb_h1_init(void)
+{
+ imx6q_add_fsl_ehci_hs(1, &usbh1_config);
+ usbh1_config.wakeup_pdata = &usbh1_wakeup_config;
+ imx6q_add_fsl_usb2_hs_wakeup(1, &usbh1_wakeup_config);
+}
+
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 3500b766e1a4..8b864bba2774 100755
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -33,5 +33,5 @@ obj-$(CONFIG_MXC_DVFS_PER) += dvfs_per.o
# USB support
obj-$(CONFIG_ISP1504_MXC) += isp1504xc.o
-obj-$(CONFIG_UTMI_MXC) += utmixc.o
+obj-$(CONFIG_USB) += utmixc.o
obj-$(CONFIG_USB) += serialxc.o
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index cbd21149f636..b6eda42e8e75 100755
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -136,3 +136,9 @@ config IMX_HAVE_PLATFORM_VIV_GPU
config IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL
bool
+
+config IMX_HAVE_PLATFORM_FSL_OTG
+ bool
+
+config IMX_HAVE_PLATFORM_FSL_USB_WAKEUP
+ bool
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index da3657d13a5e..c4203cfd6853 100755
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -47,3 +47,5 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SPDIF) += platform-imx-spdif-dai.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SPDIF) += platform-imx-spdif-audio.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_VIV_GPU) += platform-viv_gpu.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL) += platform-imx-anatop-thermal.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_OTG) += platform-fsl-usb2-otg.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_USB_WAKEUP) += platform-fsl-usb2-wakeup.o
diff --git a/arch/arm/plat-mxc/devices/platform-fsl-usb2-otg.c b/arch/arm/plat-mxc/devices/platform-fsl-usb2-otg.c
new file mode 100644
index 000000000000..f32593c27ccd
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-fsl-usb2-otg.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Based on Uwe Kleine-Koenig's platform-fsl-usb2-udc.c
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_fsl_usb2_otg_data_entry_single(soc) \
+ { \
+ .iobase = soc ## _USB_OTG_BASE_ADDR, \
+ .irq = soc ## _INT_USB_OTG, \
+ }
+
+
+#ifdef CONFIG_SOC_IMX6Q
+const struct imx_fsl_usb2_otg_data imx6q_fsl_usb2_otg_data __initconst =
+ imx_fsl_usb2_otg_data_entry_single(MX6Q);
+#endif /* ifdef CONFIG_SOC_IMX6Q */
+
+struct platform_device *__init imx_add_fsl_usb2_otg(
+ const struct imx_fsl_usb2_otg_data *data,
+ const struct fsl_usb2_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + SZ_512 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+ return imx_add_platform_device_dmamask("fsl-usb2-otg", -1,
+ res, ARRAY_SIZE(res),
+ pdata, sizeof(*pdata), DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c b/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c
index 59c33f6e401c..87161a564cd0 100644
--- a/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c
+++ b/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
* Copyright (C) 2010 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
*
@@ -35,6 +37,11 @@ const struct imx_fsl_usb2_udc_data imx35_fsl_usb2_udc_data __initconst =
imx_fsl_usb2_udc_data_entry_single(MX35);
#endif /* ifdef CONFIG_SOC_IMX35 */
+#ifdef CONFIG_SOC_IMX6Q
+const struct imx_fsl_usb2_udc_data imx6q_fsl_usb2_udc_data __initconst =
+ imx_fsl_usb2_udc_data_entry_single(MX6Q);
+#endif /* ifdef CONFIG_SOC_IMX6Q */
+
struct platform_device *__init imx_add_fsl_usb2_udc(
const struct imx_fsl_usb2_udc_data *data,
const struct fsl_usb2_platform_data *pdata)
diff --git a/arch/arm/plat-mxc/devices/platform-fsl-usb2-wakeup.c b/arch/arm/plat-mxc/devices/platform-fsl-usb2-wakeup.c
new file mode 100644
index 000000000000..d774e78c2b07
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-fsl-usb2-wakeup.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#define imx_fsl_usb2_wakeup_data_entry_single(soc, _id, hs) \
+ { \
+ .id = _id, \
+ .irq_phy = soc ## _INT_USB_PHY ## _id, \
+ .irq_core = soc ## _INT_USB_ ## hs, \
+ }
+
+#ifdef CONFIG_SOC_IMX6Q
+const struct imx_fsl_usb2_wakeup_data imx6q_fsl_otg_wakeup_data __initconst =
+ imx_fsl_usb2_wakeup_data_entry_single(MX6Q, 0, OTG);
+const struct imx_fsl_usb2_wakeup_data imx6q_fsl_hs_wakeup_data[] __initconst = {
+ imx_fsl_usb2_wakeup_data_entry_single(MX6Q, 1, HS1),
+};
+#endif /* ifdef CONFIG_SOC_IMX6Q */
+
+struct platform_device *__init imx_add_fsl_usb2_wakeup(
+ const struct imx_fsl_usb2_wakeup_data *data,
+ const struct fsl_usb2_wakeup_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->irq_phy,
+ .end = data->irq_phy,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .start = data->irq_core,
+ .end = data->irq_core,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+ return imx_add_platform_device_dmamask("usb-wakeup", data->id,
+ res, ARRAY_SIZE(res),
+ pdata, sizeof(*pdata), DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-mxc-ehci.c b/arch/arm/plat-mxc/devices/platform-mxc-ehci.c
index cc488f4b6204..deac2411c911 100644
--- a/arch/arm/plat-mxc/devices/platform-mxc-ehci.c
+++ b/arch/arm/plat-mxc/devices/platform-mxc-ehci.c
@@ -8,7 +8,6 @@
*/
#include <mach/hardware.h>
#include <mach/devices-common.h>
-
#define imx_mxc_ehci_data_entry_single(soc, _id, hs) \
{ \
.id = _id, \
@@ -48,6 +47,14 @@ const struct imx_mxc_ehci_data imx35_mxc_ehci_hs_data __initconst =
imx_mxc_ehci_data_entry_single(MX35, 1, HS);
#endif /* ifdef CONFIG_SOC_IMX35 */
+#ifdef CONFIG_SOC_IMX6Q
+const struct imx_mxc_ehci_data imx6q_mxc_ehci_otg_data __initconst =
+ imx_mxc_ehci_data_entry_single(MX6Q, 0, OTG);
+const struct imx_mxc_ehci_data imx6q_mxc_ehci_hs_data[] __initconst = {
+ imx_mxc_ehci_data_entry_single(MX6Q, 1, HS1),
+};
+#endif /* ifdef CONFIG_SOC_IMX6Q */
+
struct platform_device *__init imx_add_mxc_ehci(
const struct imx_mxc_ehci_data *data,
const struct mxc_usbh_platform_data *pdata)
@@ -67,3 +74,24 @@ struct platform_device *__init imx_add_mxc_ehci(
res, ARRAY_SIZE(res),
pdata, sizeof(*pdata), DMA_BIT_MASK(32));
}
+
+/* FSL internal non-upstream code */
+struct platform_device *__init imx_add_fsl_ehci(
+ const struct imx_mxc_ehci_data *data,
+ const struct fsl_usb2_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + SZ_512 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+ return imx_add_platform_device_dmamask("fsl-ehci", data->id,
+ res, ARRAY_SIZE(res),
+ pdata, sizeof(*pdata), DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/include/mach/arc_otg.h b/arch/arm/plat-mxc/include/mach/arc_otg.h
index 465a8fe479a1..16cfae398da2 100755
--- a/arch/arm/plat-mxc/include/mach/arc_otg.h
+++ b/arch/arm/plat-mxc/include/mach/arc_otg.h
@@ -30,14 +30,16 @@ extern void __iomem *imx_otg_base;
#define USB_OTGREGS_BASE (OTG_BASE_ADDR + 0x000)
#define USB_H1REGS_BASE (OTG_BASE_ADDR + 0x200)
#define USB_H2REGS_BASE (OTG_BASE_ADDR + 0x400)
-#ifdef CONFIG_ARCH_MX5
+#if defined CONFIG_ARCH_MX5
+#define USB_H3REGS_BASE (OTG_BASE_ADDR + 0x600)
+#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x800)
+#elif CONFIG_ARCH_MX6
#define USB_H3REGS_BASE (OTG_BASE_ADDR + 0x600)
#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x800)
#else
#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x600)
#endif
-
#define USBOTG_REG32(offset) (*((volatile u32 __force *)(USB_OTGREGS_BASE + (offset))))
#define USBOTG_REG16(offset) (*((volatile u16 __force *)(USB_OTGREGS_BASE + (offset))))
@@ -163,6 +165,21 @@ extern void __iomem *imx_otg_base;
#define USBH1_PHY_CTRL1 USBOTHER_REG(0x20) /* USB Cotrol Register 1*/
#define USB_CLKONOFF_CTRL USBOTHER_REG(0x24) /* USB Clock on/off Control Register */
+/* mx6x other regs */
+#define USB_OTG_CTRL USBOTHER_REG(0x00) /* USB OTG Control register */
+#define USB_H1_CTRL USBOTHER_REG(0x04) /* USB H1 Control register */
+#define USB_H2_CTRL USBOTHER_REG(0x08) /* USB H2 Control register */
+#define USB_H3_CTRL USBOTHER_REG(0x0c) /* USB H3 Control register */
+#define USB_UH2_HSIC_CTRL USBOTHER_REG(0x10) /* USB Host2 HSIC Control Register */
+#define USB_UH3_HSIC_CTRL USBOTHER_REG(0x14) /* USB Host3 HSIC Control Register */
+#define USB_OTG_PHY_CTRL_0 USBOTHER_REG(0x18) /* OTG UTMI PHY Control 0 Register */
+#define USB_H1_PHY_CTRL_0 USBOTHER_REG(0x1c) /* OTG UTMI PHY Control 1 Register */
+#define USB_UH2_HSIC_DLL_CFG1 USBOTHER_REG(0x20) /* USB Host2 HSIC DLL Configuration Register 1 */
+#define USB_UH2_HSIC_DLL_CFG2 USBOTHER_REG(0x24) /* USB Host2 HSIC DLL Configuration Register 2 */
+#define USB_UH2_HSIC_DLL_CFG3 USBOTHER_REG(0x28) /* USB Host2 HSIC DLL Configuration Register 3 */
+#define USB_UH3_HSIC_DLL_CFG1 USBOTHER_REG(0x30) /* USB Host3 HSIC DLL Configuration Register 1 */
+#define USB_UH3_HSIC_DLL_CFG2 USBOTHER_REG(0x34) /* USB Host3 HSIC DLL Configuration Register 2 */
+#define USB_UH3_HSIC_DLL_CFG3 USBOTHER_REG(0x38) /* USB Host3 HSIC DLL Configuration Register 3 */
/*
* register bits
*/
@@ -233,6 +250,12 @@ extern void __iomem *imx_otg_base;
/* UOG_USBSTS bits */
#define USBSTS_PCI (1 << 2) /* Port Change Detect */
#define USBSTS_URI (1 << 6) /* USB Reset Received */
+
+/* USBCMD */
+#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
+#define UCMD_RESET (1 << 1) /* controller reset */
+#define UCMD_ITC_NO_THRESHOLD (~(0xff << 16)) /* Interrupt Threshold Control */
+
#if 1 /* FIXME these here for compatibility between my names and Leo's */
/* OTG interrupt enable bit masks */
#define OTGSC_INTERRUPT_ENABLE_BITS_MASK OTGSC_IE_MASK
@@ -250,137 +273,13 @@ extern void __iomem *imx_otg_base;
#define USBMODE_CM_DEVICE (2 << 0) /* device */
#define USBMODE_CM_reserved (1 << 0) /* reserved */
-/* USBCTRL */
-#define UCTRL_OWIR (1 << 31) /* OTG wakeup intr request received */
-#define UCTRL_OSIC_MASK (3 << 29) /* OTG Serial Interface Config: */
-#define UCTRL_OSIC_DU6 (0 << 29) /* Differential/unidirectional 6 wire */
-#define UCTRL_OSIC_DB4 (1 << 29) /* Differential/bidirectional 4 wire */
-#define UCTRL_OSIC_SU6 (2 << 29) /* single-ended/unidirectional 6 wire */
-#define UCTRL_OSIC_SB3 (3 << 29) /* single-ended/bidirectional 3 wire */
-
-#define UCTRL_OUIE (1 << 28) /* OTG ULPI intr enable */
-#define UCTRL_OWIE (1 << 27) /* OTG wakeup intr enable */
-#define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */
-#define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */
-#define UCTRL_OPM (1 << 24) /* OTG power mask */
-#define UCTRL_O_PWR_POL (1 << 24) /* OTG power pin polarity */
-#ifdef CONFIG_ARCH_MX5
-#define UCTRL_H2WIR (1 << 17) /* HOST2 wakeup intr request received */
-#else
-#define UCTRL_H2WIR (1 << 23) /* HOST2 wakeup intr request received */
-#endif
-#define UCTRL_H2SIC_MASK (3 << 21) /* HOST2 Serial Interface Config: */
-#define UCTRL_H2SIC_DU6 (0 << 21) /* Differential/unidirectional 6 wire */
-#define UCTRL_H2SIC_DB4 (1 << 21) /* Differential/bidirectional 4 wire */
-#define UCTRL_H2SIC_SU6 (2 << 21) /* single-ended/unidirectional 6 wire */
-#define UCTRL_H2SIC_SB3 (3 << 21) /* single-ended/bidirectional 3 wire */
-
-#ifdef CONFIG_ARCH_MX5
-#define UCTRL_H2UIE (1 << 8) /* HOST2 ULPI intr enable */
-#define UCTRL_H2WIE (1 << 7) /* HOST2 wakeup intr enable */
-#define UCTRL_H2PP 0 /* Power Polarity for uh2 */
-#define UCTRL_H2PM (1 << 4) /* HOST2 power mask */
+#define HCSPARAMS_PPC (0x1<<4) /* Port Power Control */
+extern enum fsl_usb2_modes get_usb_mode(struct fsl_usb2_platform_data *pdata);
+#ifdef CONFIG_ARCH_MX6
+#include "regs-usbphy-mx6.h"
#else
-#define UCTRL_H2UIE (1 << 20) /* HOST2 ULPI intr enable */
-#define UCTRL_H2WIE (1 << 19) /* HOST2 wakeup intr enable */
-#define UCTRL_H2PP (1 << 18) /* Power Polarity for uh2 */
-#define UCTRL_H2PM (1 << 16) /* HOST2 power mask */
+#include "regs-usbphy-others.h"
#endif
-#define UCTRL_H2OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */
-#define UCTRL_H2OIDWK_EN (1 << 5) /* OTG ID Wakeup Enable */
-#define UCTRL_H1WIR (1 << 15) /* HOST1 wakeup intr request received */
-#define UCTRL_H1SIC_MASK (3 << 13) /* HOST1 Serial Interface Config: */
-#define UCTRL_H1SIC_DU6 (0 << 13) /* Differential/unidirectional 6 wire */
-#define UCTRL_H1SIC_DB4 (1 << 13) /* Differential/bidirectional 4 wire */
-#define UCTRL_H1SIC_SU6 (2 << 13) /* single-ended/unidirectional 6 wire */
-#define UCTRL_H1SIC_SB3 (3 << 13) /* single-ended/bidirectional 3 wire */
-#define UCTRL_OLOCKD (1 << 13) /* otg lock disable */
-#define UCTRL_H2LOCKD (1 << 12) /* HOST2 lock disable */
-#define UCTRL_H1UIE (1 << 12) /* Host1 ULPI interrupt enable */
+#endif /* __ASM_ARCH_MXC_ARC_OTG_H__ */
-#if defined(CONFIG_ARCH_MX37)
-/* VBUS wakeup enable, UTMI only */
-#define UCTRL_VBUS_WKUP_EN (1 << 12)
-#elif defined(CONFIG_ARCH_MX25) || defined(CONFIG_ARCH_MX35)
-#define UCTRL_VBUS_WKUP_EN (1 << 15)
-#endif
-
-#define UCTRL_PP (1 << 11) /* power polarity bit */
-#define UCTRL_H1WIE (1 << 11) /* HOST1 wakeup intr enable */
-#define UCTRL_H1BPVAL_RXDP (1 << 10) /* HOST1 RxDp status in bypass mode */
-#define UCTRL_XCSO (1 << 10) /* Xcvr Clock Select for OTG port */
-#define UCTRL_H1BPVAL_RXDM (1 << 9) /* HOST1 RxDm status in bypass mode */
-#define UCTRL_XCSH2 (1 << 9) /* Xcvr Clock Select for Host port */
-#define UCTRL_H1PM (1 << 8) /* HOST1 power mask */
-#define UCTRL_IP_PULIDP (1 << 8) /* Ipp_Puimpel_Pullup_Dp */
-
-#define UCTRL_IP_PUE_UP (1 << 7) /* ipp_pue_pullup_dp */
-#define UCTRL_IP_PUE_DOWN (1 << 6) /* ipp_pue_pulldwn_dpdm */
-#define UCTRL_H2DT (1 << 5) /* HOST2 TLL disabled */
-#define UCTRL_H1DT (1 << 4) /* HOST1 TLL disabled */
-#define UCTRL_USBTE (1 << 4) /* USBT Transceiver enable */
-#define UCTRL_OCPOL (1 << 3) /* OverCurrent Polarity */
-#define UCTRL_OCE (1 << 2) /* OverCurrent Enable */
-#define UCTRL_H2OCPOL (1 << 2) /* OverCurrent Polarity of Host2 */
-#define UCTRL_H2OCS (1 << 1) /* Host OverCurrent State */
-#define UCTRL_BPE (1 << 0) /* bypass mode enable */
-#define UCTRL_OTD (1 << 0) /* OTG TLL Disable */
-#define UCTRL_OOCS (1 << 0) /* OTG OverCurrent State */
-
-/* USBCMD */
-#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
-#define UCMD_RESET (1 << 1) /* controller reset */
-#define UCMD_ITC_NO_THRESHOLD (~(0xff << 16)) /* Interrupt Threshold Control */
-
-/* OTG_MIRROR */
-#define OTGM_SESEND (1 << 4) /* B device session end */
-#define OTGM_VBUSVAL (1 << 3) /* Vbus valid */
-#define OTGM_BSESVLD (1 << 2) /* B session Valid */
-#define OTGM_ASESVLD (1 << 1) /* A session Valid */
-#define OTGM_IDIDG (1 << 0) /* OTG ID pin status */
- /* 1=high: Operate as B-device */
- /* 0=low : Operate as A-device */
-
-/* USB_PHY_CTRL_FUNC */
-/* PHY control0 Register Bit Masks */
-#define USB_UTMI_PHYCTRL_CONF2 (1 << 26)
-
-#define USB_UTMI_PHYCTRL_UTMI_ENABLE (1 << 24)
-#define USB_UTMI_PHYCTRL_CHGRDETEN (1 << 24) /* Enable Charger Detector */
-#define USB_UTMI_PHYCTRL_CHGRDETON (1 << 23) /* Charger Detector Power On Control */
-#define USB_UTMI_PHYCTRL_OC_POL (1 << 9) /* OTG Polarity of Overcurrent */
-#define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */
-#define USB_UH1_OC_DIS (1 << 5) /* UH1 Disable Overcurrent Event */
-#define USB_UH1_OC_POL (1 << 6) /* UH1 Polarity of OC,Low active */
-/* USB_PHY_CTRL_FUNC2*/
-#define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3
-#define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0
-#define USB_UTMI_PHYCTRL2_HSDEVSEL_MASK 0x3
-#define USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT 19
-
-/* USB_CTRL_1 */
-#define USB_CTRL_UH1_EXT_CLK_EN (1 << 25)
-#define USB_CTRL_UH2_EXT_CLK_EN (1 << 26)
-#define USB_CTRL_UH2_CLK_FROM_ULPI_PHY (1 << 2)
-/* ULPIVIEW register bits */
-#define ULPIVW_OFF (0x170)
-#define ULPIVW_WU (1 << 31) /* Wakeup */
-#define ULPIVW_RUN (1 << 30) /* read/write run */
-#define ULPIVW_WRITE (1 << 29) /* 0=read 1=write */
-#define ULPIVW_SS (1 << 27) /* SyncState */
-#define ULPIVW_PORT_MASK 0x07 /* Port field */
-#define ULPIVW_PORT_SHIFT 24
-#define ULPIVW_ADDR_MASK 0xFF /* data address field */
-#define ULPIVW_ADDR_SHIFT 16
-#define ULPIVW_RDATA_MASK 0xFF /* read data field */
-#define ULPIVW_RDATA_SHIFT 8
-#define ULPIVW_WDATA_MASK 0xFF /* write data field */
-#define ULPIVW_WDATA_SHIFT 0
-
-#define HCSPARAMS_PPC (0x1<<4) /* Port Power Control */
-/* USB Clock on/off Control Register */
-#define OTG_AHBCLK_OFF (0x1<<17) /* 1: OFF */
-#define H1_AHBCLK_OFF (0x1<<18) /* 1: OFF */
-extern enum fsl_usb2_modes get_usb_mode(struct fsl_usb2_platform_data *pdata);
-#endif
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index a94367163449..01466e514680 100755
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -229,6 +229,10 @@ struct platform_device *__init imx_add_mxc_ehci(
const struct imx_mxc_ehci_data *data,
const struct mxc_usbh_platform_data *pdata);
+struct platform_device *__init imx_add_fsl_ehci(
+ const struct imx_mxc_ehci_data *data,
+ const struct fsl_usb2_platform_data *pdata);
+
#include <mach/mmc.h>
struct imx_mxc_mmc_data {
int id;
@@ -485,6 +489,23 @@ struct imx_dcp_data {
};
struct platform_device *__init imx_add_dcp(
+
+struct imx_fsl_usb2_otg_data {
+ resource_size_t iobase;
+ resource_size_t irq;
+};
+struct platform_device *__init imx_add_fsl_usb2_otg(
+ const struct imx_fsl_usb2_otg_data *data,
+ const struct fsl_usb2_platform_data *pdata);
+
+struct imx_fsl_usb2_wakeup_data {
+ int id;
+ resource_size_t irq_phy;
+ resource_size_t irq_core;
+};
+struct platform_device *__init imx_add_fsl_usb2_wakeup(
+ const struct imx_fsl_usb2_wakeup_data *data,
+ const struct fsl_usb2_wakeup_platform_data *pdata);
const struct imx_dcp_data *data);
/* gpmi-nfc */
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx6q.h b/arch/arm/plat-mxc/include/mach/iomux-mx6q.h
index a8fb08b0f394..7d403e1ae9ad 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx6q.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx6q.h
@@ -2239,6 +2239,8 @@ typedef enum iomux_config {
IOMUX_PAD(0x05F4, 0x0224, 1, 0x0000, 0, 0)
#define _MX6Q_PAD_GPIO_1__KPP_ROW_5 \
IOMUX_PAD(0x05F4, 0x0224, 2, 0x08F4, 0, 0)
+#define MX6Q_PAD_GPIO_1__USBOTG_ID \
+ IOMUX_PAD(0x05F4, 0x0224, 3, 0x0000, 0, MX6Q_USDHC_PAD_CTRL)
#define _MX6Q_PAD_GPIO_1__PWM2_PWMO \
IOMUX_PAD(0x05F4, 0x0224, 4, 0x0000, 0, 0)
#define _MX6Q_PAD_GPIO_1__GPIO_1_1 \
diff --git a/arch/arm/plat-mxc/include/mach/mx6.h b/arch/arm/plat-mxc/include/mach/mx6.h
index 36bcd5f2bb6c..451fc7f093a3 100644
--- a/arch/arm/plat-mxc/include/mach/mx6.h
+++ b/arch/arm/plat-mxc/include/mach/mx6.h
@@ -164,6 +164,8 @@
#define WDOG2_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x40000)
#define CCM_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x44000)
#define ANATOP_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x48000)
+#define USB_PHY0_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x49000)
+#define USB_PHY1_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x4a000)
#define SNVS_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x4C000)
#define EPIT1_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x50000)
#define EPIT2_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x54000)
@@ -184,11 +186,9 @@
#define CAAM_BASE_ADDR ATZ2_BASE_ADDR
#define ARM_BASE_ADDR (ATZ2_BASE_ADDR + 0x40000)
-#define USBOH3_PL301_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x0000)
-#define USBOH3_USB_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x4000)
-/* Frank Li Need IC confirm OTG base address*/
-/* Zeng Zhaoming: FIXME, conflict with plat-mxc/include/mach/arc_otg.h:21 */
-/* #define OTG_BASE_ADDR USBOH3_USB_BASE_ADDR */
+#define MX6Q_PL301_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x0000)
+#define MX6Q_USB_OTG_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x4000)
+#define MX6Q_USB_HS1_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x4200)
#define ENET_BASE_ADDR (AIPS2_OFF_BASE_ADDR+0x8000)
#define MLB_BASE_ADDR (AIPS2_OFF_BASE_ADDR+0xC000)
@@ -218,8 +218,6 @@
#define UART3_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x6C000)
#define UART4_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x70000)
#define UART5_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x74000)
-#define IP2APB_USBPHY1_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x78000)
-#define IP2APB_USBPHY2_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x7C000)
/* Cortex-A9 MPCore private memory region */
#define ARM_PERIPHBASE 0x00A00000
@@ -306,12 +304,12 @@
#define MX6Q_INT_I2C2 69
#define MX6Q_INT_I2C3 70
#define MXC_INT_SATA 71
-#define MXC_INT_USBOH3_UH1 72
-#define MXC_INT_USBOH3_UH2 73
-#define MXC_INT_USBOH3_UH3 74
-#define MXC_INT_USBOH3_UOTG 75
-#define MXC_INT_ANATOP_UTMI0 76
-#define MXC_INT_ANATOP_UTMI1 77
+#define MX6Q_INT_USB_HS1 72
+#define MX6Q_INT_USB_HS2 73
+#define MX6Q_INT_USB_HS3 74
+#define MX6Q_INT_USB_OTG 75
+#define MX6Q_INT_USB_PHY0 76
+#define MX6Q_INT_USB_PHY1 77
#define MXC_INT_SSI1 78
#define MXC_INT_SSI2 79
#define MXC_INT_SSI3 80
diff --git a/arch/arm/mach-mx6/regs-usbphy.h b/arch/arm/plat-mxc/include/mach/regs-usbphy-mx6.h
index 6161062c0c16..645846820a35 100644
--- a/arch/arm/mach-mx6/regs-usbphy.h
+++ b/arch/arm/plat-mxc/include/mach/regs-usbphy-mx6.h
@@ -1,22 +1,22 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Freescale USBPHY Register Definitions
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/*
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
* This file is created by xml file. Don't Edit it.
*
* Xml Revision: 1.2
@@ -320,4 +320,159 @@
#define BM_USBPHY_IP_EN_USB_CLKS 0x00000004
#define BM_USBPHY_IP_PLL_LOCKED 0x00000002
#define BM_USBPHY_IP_PLL_POWER 0x00000001
+
+/* The register definition for usbphy which includes at usb core's register set
+ * (from USB_CORE_BASE + 0x800)
+ */
+#define USB_CTRL USBOTHER_REG(0x00) /* USB OTG Control register */
+#define USB_H1_CTRL USBOTHER_REG(0x04) /* USB H1 Control register */
+#define USB_H2_CTRL USBOTHER_REG(0x08) /* USB H2 Control register */
+#define USB_H3_CTRL USBOTHER_REG(0x0c) /* USB H3 Control register */
+#define USB_UH2_HSIC_CTRL USBOTHER_REG(0x10) /* USB Host2 HSIC Control Register */
+#define USB_UH3_HSIC_CTRL USBOTHER_REG(0x14) /* USB Host3 HSIC Control Register */
+#define USB_OTG_PHY_CTRL_0 USBOTHER_REG(0x18) /* OTG UTMI PHY Control 0 Register */
+#define USB_H1_PHY_CTRL_0 USBOTHER_REG(0x1c) /* OTG UTMI PHY Control 1 Register */
+#define USB_UH2_HSIC_DLL_CFG1 USBOTHER_REG(0x20) /* USB Host2 HSIC DLL Configuration Register 1 */
+#define USB_UH2_HSIC_DLL_CFG2 USBOTHER_REG(0x24) /* USB Host2 HSIC DLL Configuration Register 2 */
+#define USB_UH2_HSIC_DLL_CFG3 USBOTHER_REG(0x28) /* USB Host2 HSIC DLL Configuration Register 3 */
+#define USB_UH3_HSIC_DLL_CFG1 USBOTHER_REG(0x30) /* USB Host3 HSIC DLL Configuration Register 1 */
+#define USB_UH3_HSIC_DLL_CFG2 USBOTHER_REG(0x34) /* USB Host3 HSIC DLL Configuration Register 2 */
+#define USB_UH3_HSIC_DLL_CFG3 USBOTHER_REG(0x38) /* USB Host3 HSIC DLL Configuration Register 3 */
+
+/*
+ * register bits
+ */
+
+/* USBCTRL */
+#define UCTRL_OSIC_MASK (3 << 29) /* OTG Serial Interface Config: */
+#define UCTRL_OSIC_DU6 (0 << 29) /* Differential/unidirectional 6 wire */
+#define UCTRL_OSIC_DB4 (1 << 29) /* Differential/bidirectional 4 wire */
+#define UCTRL_OSIC_SU6 (2 << 29) /* single-ended/unidirectional 6 wire */
+#define UCTRL_OSIC_SB3 (3 << 29) /* single-ended/bidirectional 3 wire */
+#define UCTRL_OUIE (1 << 28) /* OTG ULPI intr enable */
+#define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */
+#define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */
+#define UCTRL_OPM (1 << 24) /* OTG power mask */
+#define UCTRL_O_PWR_POL (1 << 24) /* OTG power pin polarity */
+#define UCTRL_H2WIR (1 << 17) /* HOST2 wakeup intr request received */
+#define UCTRL_H2SIC_MASK (3 << 21) /* HOST2 Serial Interface Config: */
+#define UCTRL_H2SIC_DU6 (0 << 21) /* Differential/unidirectional 6 wire */
+#define UCTRL_H2SIC_DB4 (1 << 21) /* Differential/bidirectional 4 wire */
+#define UCTRL_H2SIC_SU6 (2 << 21) /* single-ended/unidirectional 6 wire */
+#define UCTRL_H2SIC_SB3 (3 << 21) /* single-ended/bidirectional 3 wire */
+#define UCTRL_H2UIE (1 << 8) /* HOST2 ULPI intr enable */
+#define UCTRL_H2WIE (1 << 7) /* HOST2 wakeup intr enable */
+#define UCTRL_H2PP 0 /* Power Polarity for uh2 */
+#define UCTRL_H2PM (1 << 4) /* HOST2 power mask */
+#define UCTRL_H2OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */
+#define UCTRL_H2OIDWK_EN (1 << 5) /* OTG ID Wakeup Enable */
+
+#define UCTRL_H1WIR (1 << 15) /* HOST1 wakeup intr request received */
+#define UCTRL_H1SIC_MASK (3 << 13) /* HOST1 Serial Interface Config: */
+#define UCTRL_H1SIC_DU6 (0 << 13) /* Differential/unidirectional 6 wire */
+#define UCTRL_H1SIC_DB4 (1 << 13) /* Differential/bidirectional 4 wire */
+#define UCTRL_H1SIC_SU6 (2 << 13) /* single-ended/unidirectional 6 wire */
+#define UCTRL_H1SIC_SB3 (3 << 13) /* single-ended/bidirectional 3 wire */
+#define UCTRL_OLOCKD (1 << 13) /* otg lock disable */
+#define UCTRL_H2LOCKD (1 << 12) /* HOST2 lock disable */
+#define UCTRL_H1UIE (1 << 12) /* Host1 ULPI interrupt enable */
+
+#define UCTRL_PP (1 << 11) /* power polarity bit */
+#define UCTRL_H1WIE (1 << 11) /* HOST1 wakeup intr enable */
+#define UCTRL_H1BPVAL_RXDP (1 << 10) /* HOST1 RxDp status in bypass mode */
+#define UCTRL_XCSO (1 << 10) /* Xcvr Clock Select for OTG port */
+#define UCTRL_H1BPVAL_RXDM (1 << 9) /* HOST1 RxDm status in bypass mode */
+#define UCTRL_XCSH2 (1 << 9) /* Xcvr Clock Select for Host port */
+#define UCTRL_H1PM (1 << 8) /* HOST1 power mask */
+#define UCTRL_IP_PULIDP (1 << 8) /* Ipp_Puimpel_Pullup_Dp */
+
+#define UCTRL_IP_PUE_UP (1 << 7) /* ipp_pue_pullup_dp */
+#define UCTRL_IP_PUE_DOWN (1 << 6) /* ipp_pue_pulldwn_dpdm */
+#define UCTRL_H2DT (1 << 5) /* HOST2 TLL disabled */
+#define UCTRL_H1DT (1 << 4) /* HOST1 TLL disabled */
+#define UCTRL_USBTE (1 << 4) /* USBT Transceiver enable */
+#define UCTRL_OCPOL (1 << 3) /* OverCurrent Polarity */
+#define UCTRL_OCE (1 << 2) /* OverCurrent Enable */
+#define UCTRL_H2OCPOL (1 << 2) /* OverCurrent Polarity of Host2 */
+#define UCTRL_H2OCS (1 << 1) /* Host OverCurrent State */
+#define UCTRL_BPE (1 << 0) /* bypass mode enable */
+#define UCTRL_OTD (1 << 0) /* OTG TLL Disable */
+#define UCTRL_OOCS (1 << 0) /* OTG OverCurrent State */
+
+/* OTG_MIRROR */
+#define OTGM_SESEND (1 << 4) /* B device session end */
+#define OTGM_VBUSVAL (1 << 3) /* Vbus valid */
+#define OTGM_BSESVLD (1 << 2) /* B session Valid */
+#define OTGM_ASESVLD (1 << 1) /* A session Valid */
+#define OTGM_IDIDG (1 << 0) /* OTG ID pin status */
+ /* 1=high: Operate as B-device */
+ /* 0=low : Operate as A-device */
+
+/* USB_PHY_CTRL_FUNC */
+/* PHY control0 Register Bit Masks */
+#define USB_UTMI_PHYCTRL_CONF2 (1 << 26)
+
+#define USB_UTMI_PHYCTRL_UTMI_ENABLE (1 << 24)
+#define USB_UTMI_PHYCTRL_CHGRDETEN (1 << 24) /* Enable Charger Detector */
+#define USB_UTMI_PHYCTRL_CHGRDETON (1 << 23) /* Charger Detector Power On Control */
+#define USB_UTMI_PHYCTRL_OC_POL (1 << 9) /* OTG Polarity of Overcurrent */
+#define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */
+#define USB_UH1_OC_DIS (1 << 5) /* UH1 Disable Overcurrent Event */
+#define USB_UH1_OC_POL (1 << 6) /* UH1 Polarity of OC,Low active */
+/* USB_PHY_CTRL_FUNC2*/
+#define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3
+#define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0
+#define USB_UTMI_PHYCTRL2_HSDEVSEL_MASK 0x3
+#define USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT 19
+
+/* USB_CTRL_1 */
+#define USB_CTRL_UH1_EXT_CLK_EN (1 << 25)
+#define USB_CTRL_UH2_EXT_CLK_EN (1 << 26)
+#define USB_CTRL_UH2_CLK_FROM_ULPI_PHY (1 << 2)
+/* ULPIVIEW register bits */
+#define ULPIVW_OFF (0x170)
+#define ULPIVW_WU (1 << 31) /* Wakeup */
+#define ULPIVW_RUN (1 << 30) /* read/write run */
+#define ULPIVW_WRITE (1 << 29) /* 0=read 1=write */
+#define ULPIVW_SS (1 << 27) /* SyncState */
+#define ULPIVW_PORT_MASK 0x07 /* Port field */
+#define ULPIVW_PORT_SHIFT 24
+#define ULPIVW_ADDR_MASK 0xFF /* data address field */
+#define ULPIVW_ADDR_SHIFT 16
+#define ULPIVW_RDATA_MASK 0xFF /* read data field */
+#define ULPIVW_RDATA_SHIFT 8
+#define ULPIVW_WDATA_MASK 0xFF /* write data field */
+#define ULPIVW_WDATA_SHIFT 0
+
+/* USB Clock on/off Control Register */
+#define OTG_AHBCLK_OFF (0x1<<17) /* 1: OFF */
+#define H1_AHBCLK_OFF (0x1<<18) /* 1: OFF */
+
+/* mx6q's register bit begins*/
+
+/* OTG CTRL - H3 CTRL */
+#define UCTRL_OWIR (1 << 31) /* OTG wakeup intr request received */
+/* bit 18 - bit 30 is reserved at mx6q */
+#define UCTRL_WKUP_VBUS_EN (1 << 17) /* OTG wake-up on VBUS change enable */
+#define UCTRL_WKUP_ID_EN (1 << 16) /* OTG wake-up on ID change enable */
+#define UCTRL_WKUP_SW (1 << 15) /* OTG Software Wake-up */
+#define UCTRL_WKUP_SW_EN (1 << 14) /* OTG Software Wake-up enable */
+#define UCTRL_UTMI_ON_CLOCK (1 << 13) /* Force OTG UTMI PHY clock output on even if suspend mode */
+#define UCTRL_SUSPENDM (1 << 12) /* Force OTG UTMI PHY Suspend */
+#define UCTRL_RESET (1 << 11) /* Force OTG UTMI PHY Reset */
+#define UCTRL_OWIE (1 << 10) /* OTG wakeup intr request received */
+#define UCTRL_PM (1 << 9) /* OTG Power Mask */
+#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
+/* bit 0 - bit 6 is reserved at mx6q */
+
+/* Host2/3 HSIC Ctrl */
+#define H2_CLK_VLD (1 << 31) /* Indicating whether Host2 HSIC clock is valid */
+#define H2_HSIC_EN (1 << 12) /* Host2 HSIC enable */
+#define H2_HSIC_CLK_ON (1 << 11) /* Force Host2 HSIC module 480M clock on,
+ * even when in Host 2 is in suspend mode
+ */
+/* OTG/HOST1 Phy Ctrl */
+#define PHY_UTMI_CLK_VLD (1 << 31) /* Indicating whether OTG UTMI PHY Clock Valida */
+
#endif /* __ARCH_ARM___USBPHY_H */
diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c
index 300d2756394d..a6a32ee4a02e 100755
--- a/arch/arm/plat-mxc/usb_common.c
+++ b/arch/arm/plat-mxc/usb_common.c
@@ -1,14 +1,19 @@
/*
- * Copyright (C) 2004-2011 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:
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*!
@@ -39,9 +44,11 @@
#include <linux/usb/otg.h>
#include <linux/usb/fsl_xcvr.h>
#include <linux/regulator/consumer.h>
+#include <linux/io.h>
+#include <asm/mach-types.h>
#include <mach/arc_otg.h>
#include <mach/hardware.h>
-#include <asm/mach-types.h>
+#include <mach/mxc.h>
void __iomem *imx_otg_base;
@@ -81,12 +88,20 @@ static int fsl_check_usbclk(void)
usb_ahb_clk = clk_get(NULL, "usb_ahb_clk");
if (clk_enable(usb_ahb_clk)) {
+ if (cpu_is_mx6q())
+ return 0; /* there is no ahb clock at mx6 */
printk(KERN_ERR "clk_enable(usb_ahb_clk) failed\n");
return -EINVAL;
}
clk_put(usb_ahb_clk);
usb_clk = clk_get(NULL, "usb_clk");
+ if (clk_enable(usb_clk)) {
+ if (cpu_is_mx6q())
+ return 0; /* there is usb_clk at mx6 */
+ printk(KERN_ERR "clk_enable(usb_clk) failed\n");
+ return -EINVAL;
+ }
freq = clk_get_rate(usb_clk);
clk_put(usb_clk);
if ((freq < 59999000) || (freq > 60001000)) {
@@ -390,18 +405,7 @@ static void usbh2_set_serial_xcvr(void)
UCTRL_USBTE | /* USBT is enabled */
UCTRL_H2DT; /* Disable H2 TLL */
- if (cpu_is_mx35() && (imx_cpu_ver() < IMX_CHIP_REVISION_2_0)) {
- /* Disable Host2 bus Lock for i.MX35 1.0 */
- USBCTRL |= UCTRL_H2LOCKD;
- /* USBOTG_PWR low active */
- USBCTRL &= ~UCTRL_PP;
- /* OverCurrent Polarity is Low Active */
- USBCTRL &= ~UCTRL_OCPOL;
- } else if (cpu_is_mx35() && (imx_cpu_ver() >= IMX_CHIP_REVISION_2_0)) {
- /* i.MX35 2.0 OTG and Host2 have seperate OC/PWR polarity */
- USBCTRL &= ~UCTRL_H2PP;
- USBCTRL &= ~UCTRL_H2OCPOL;
- } else if (cpu_is_mx25()) {
+ if (cpu_is_mx25()) {
/*
* USBH2_PWR and USBH2_OC are active high.
* Must force xcvr clock to "internal" so that
@@ -481,11 +485,6 @@ int fsl_usb_host_init(struct platform_device *pdev)
if (pdata->gpio_usb_active && pdata->gpio_usb_active())
return -EINVAL;
- if (clk_enable(usb_clk)) {
- printk(KERN_ERR "clk_enable(usb_clk) failed\n");
- return -EINVAL;
- }
-
if (cpu_is_mx50())
/* Turn on AHB CLK for H1*/
USB_CLKONOFF_CTRL &= ~H1_AHBCLK_OFF;
@@ -503,23 +502,24 @@ int fsl_usb_host_init(struct platform_device *pdev)
if (usb_register_remote_wakeup(pdev))
pr_debug("%s port is not a wakeup source.\n", pdata->name);
-
- if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
- if (cpu_is_mx35()) {
- usbh2_set_serial_xcvr();
- /* Close the internal 60Mhz */
- USBCTRL &= ~UCTRL_XCSH2;
- } else if (cpu_is_mx25())
- usbh2_set_serial_xcvr();
- else
- usbh1_set_serial_xcvr();
- } else if (xops->xcvr_type == PORTSC_PTS_ULPI) {
- if (!strcmp("Host 1", pdata->name))
- usbh1_set_ulpi_xcvr();
- if (!strcmp("Host 2", pdata->name))
- usbh2_set_ulpi_xcvr();
- } else if (xops->xcvr_type == PORTSC_PTS_UTMI) {
- usbh1_set_utmi_xcvr();
+ if (!cpu_is_mx6q()) {
+ if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
+ if (cpu_is_mx35()) {
+ usbh2_set_serial_xcvr();
+ /* Close the internal 60Mhz */
+ USBCTRL &= ~UCTRL_XCSH2;
+ } else if (cpu_is_mx25())
+ usbh2_set_serial_xcvr();
+ else
+ usbh1_set_serial_xcvr();
+ } else if (xops->xcvr_type == PORTSC_PTS_ULPI) {
+ if (!strcmp("Host 1", pdata->name))
+ usbh1_set_ulpi_xcvr();
+ if (!strcmp("Host 2", pdata->name))
+ usbh2_set_ulpi_xcvr();
+ } else if (xops->xcvr_type == PORTSC_PTS_UTMI) {
+ usbh1_set_utmi_xcvr();
+ }
}
pr_debug("%s: %s success\n", __func__, pdata->name);
@@ -730,6 +730,11 @@ static void otg_set_utmi_xcvr(void)
/* Set the PHY clock to 19.2MHz */
USB_PHY_CTR_FUNC2 &= ~USB_UTMI_PHYCTRL2_PLLDIV_MASK;
USB_PHY_CTR_FUNC2 |= 0x01;
+ } else if (machine_is_mx37_3ds()) {
+ /* Reference voltage for HS disconnect envelope detector */
+ /* adjust the Squelch level */
+ USB_PHY_CTR_FUNC2 &= ~(USB_UTMI_PHYCTRL2_HSDEVSEL_MASK <<
+ USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT);
}
/* Workaround an IC issue for ehci driver:
@@ -764,6 +769,12 @@ static void otg_set_utmi_xcvr(void)
*/
msleep(100);
+ if (cpu_is_mx37()) {
+ /* fix USB PHY Power Gating leakage issue for i.MX37 */
+ USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CHGRDETON;
+ USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CHGRDETEN;
+ }
+
/* Turn off the usbpll for UTMI tranceivers */
clk_disable(usb_clk);
}
@@ -796,29 +807,26 @@ int usbotg_init(struct platform_device *pdev)
pr_debug("%s: grab pins\n", __func__);
if (pdata->gpio_usb_active && pdata->gpio_usb_active())
return -EINVAL;
-
- if (clk_enable(usb_clk)) {
- printk(KERN_ERR "clk_enable(usb_clk) failed\n");
- return -EINVAL;
- }
-
if (xops->init)
xops->init(xops);
-
- UOG_PORTSC1 = UOG_PORTSC1 & ~PORTSC_PHCD;
- if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
- if (pdata->operating_mode == FSL_USB2_DR_HOST) {
- otg_set_serial_host();
- /* need reset */
- UOG_USBCMD |= UCMD_RESET;
- msleep(100);
- } else if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
- otg_set_serial_peripheral();
- 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();
+ if (!(cpu_is_mx6q())) {
+ UOG_PORTSC1 = UOG_PORTSC1 & ~PORTSC_PHCD;
+
+
+ if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
+ if (pdata->operating_mode == FSL_USB2_DR_HOST) {
+ otg_set_serial_host();
+ /* need reset */
+ UOG_USBCMD |= UCMD_RESET;
+ msleep(100);
+ } else if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
+ otg_set_serial_peripheral();
+ 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();
+ }
}
}
@@ -864,40 +872,30 @@ EXPORT_SYMBOL(usbotg_uninit);
*/
void usb_debounce_id_vbus(void)
{
- mdelay(3);
+ msleep(3);
}
EXPORT_SYMBOL(usb_debounce_id_vbus);
-int usb_host_wakeup_irq(struct device *wkup_dev)
+int usb_event_is_otg_wakeup(struct fsl_usb2_platform_data *pdata)
{
- int wakeup_req = 0;
- struct fsl_usb2_platform_data *pdata = wkup_dev->platform_data;
-
- if (!strcmp("Host 1", pdata->name)) {
- wakeup_req = USBCTRL & UCTRL_H1WIR;
- } else if (!strcmp("Host 2", pdata->name)) {
- wakeup_req = USBCTRL_HOST2 & UCTRL_H2WIR;
- } else if (!strcmp("DR", pdata->name)) {
- wakeup_req = USBCTRL & UCTRL_OWIR;
- /*if only host mode is enabled, the wakeup event
- * must be host wakeup event */
-#ifdef CONFIG_USB_OTG
- /* if ID change status, it is host wakeup event */
- if (wakeup_req && (UOG_OTGSC & OTGSC_IS_USB_ID))
- wakeup_req = 0;
-#endif
- }
-
- return wakeup_req;
+ return (USBCTRL & UCTRL_OWIR) ? true : false;
}
-EXPORT_SYMBOL(usb_host_wakeup_irq);
+EXPORT_SYMBOL(usb_event_is_otg_wakeup);
-int usb_event_is_otg_wakeup(void)
+#ifdef CONFIG_ARCH_MX6
+/* enable/disable high-speed disconnect detector of phy ctrl */
+void fsl_platform_set_usb_phy_dis(struct fsl_usb2_platform_data *pdata,
+ bool enable)
{
- int ret = (USBCTRL & UCTRL_OWIR) ? 1 : 0;
- return ret;
+ if (enable)
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_SET);
+ else
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_CLR);
}
-EXPORT_SYMBOL(usb_event_is_otg_wakeup);
+EXPORT_SYMBOL(fsl_platform_set_usb_phy_dis);
+#endif
void usb_host_set_wakeup(struct device *wkup_dev, bool para)
{
diff --git a/arch/arm/plat-mxc/usb_wakeup.c b/arch/arm/plat-mxc/usb_wakeup.c
index 80bc6c9861df..d55abc47d10b 100755
--- a/arch/arm/plat-mxc/usb_wakeup.c
+++ b/arch/arm/plat-mxc/usb_wakeup.c
@@ -1,16 +1,21 @@
/*
- * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-/*
- * 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/sched.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -21,6 +26,8 @@
#include <linux/mutex.h>
#include <linux/fsl_devices.h>
#include <linux/suspend.h>
+#include <linux/io.h>
+#include <mach/arc_otg.h>
struct wakeup_ctrl {
int wakeup_irq;
@@ -31,7 +38,7 @@ struct wakeup_ctrl {
};
static struct wakeup_ctrl *g_ctrl;
-extern int usb_event_is_otg_wakeup(void);
+extern int usb_event_is_otg_wakeup(struct fsl_usb2_platform_data *pdata);
extern void usb_debounce_id_vbus(void);
static void wakeup_clk_gate(struct fsl_usb2_wakeup_platform_data *pdata, bool on)
@@ -51,6 +58,7 @@ static bool usb2_is_in_lowpower(struct wakeup_ctrl *ctrl)
return false;
}
}
+
return true;
}
@@ -67,6 +75,7 @@ static void delay_process_wakeup(struct wakeup_ctrl *ctrl)
pdata->usb_pdata[i]->irq_delay = 1;
}
}
+
pdata->usb_wakeup_is_pending = true;
complete(&ctrl->event);
}
@@ -75,9 +84,8 @@ static irqreturn_t usb_wakeup_handler(int irq, void *_dev)
{
struct wakeup_ctrl *ctrl = (struct wakeup_ctrl *)_dev;
irqreturn_t ret = IRQ_NONE;
-
if (usb2_is_in_lowpower(ctrl)) {
- printk(KERN_INFO "usb wakeup is here\n");
+ printk("usb wakeup is here\n");
delay_process_wakeup(ctrl);
ret = IRQ_HANDLED;
}
@@ -97,23 +105,24 @@ static void wakeup_event_handler(struct wakeup_ctrl *ctrl)
struct fsl_usb2_wakeup_platform_data *pdata = ctrl->pdata;
int already_waked = 0;
enum usb_wakeup_event wakeup_evt;
- int i, cnt = 0;
+ int i;
wakeup_clk_gate(ctrl->pdata, true);
recheck:
- /* In order to get the real id/vbus value */
- if (usb_event_is_otg_wakeup())
- msleep(10); /* usb_debounce_id_vbus(); */
-
for (i = 0; i < 3; i++) {
struct fsl_usb2_platform_data *usb_pdata = pdata->usb_pdata[i];
if (usb_pdata) {
+ /* In order to get the real id/vbus value */
+ if (usb_event_is_otg_wakeup(usb_pdata))
+ usb_debounce_id_vbus();
+
usb_pdata->irq_delay = 0;
wakeup_evt = is_wakeup(usb_pdata);
if (wakeup_evt != WAKEUP_EVENT_INVALID) {
- if (usb_pdata->usb_clock_for_pm)
- usb_pdata->usb_clock_for_pm(true);
+ if (usb2_is_in_lowpower(ctrl))
+ if (usb_pdata->usb_clock_for_pm)
+ usb_pdata->usb_clock_for_pm(true);
usb_pdata->lowpower = 0;
already_waked = 1;
if (usb_pdata->wakeup_handler) {
@@ -122,9 +131,7 @@ recheck:
}
}
}
- /* for IC: ID/VBUS status change after wakeup interrupt */
- if ((cnt++ < 5) && (already_waked == 0))
- goto recheck;
+
/* If nothing to wakeup, clear wakeup event */
if ((already_waked == 0) && pdata->usb_wakeup_exhandle)
pdata->usb_wakeup_exhandle();
@@ -157,6 +164,7 @@ static int wakeup_dev_probe(struct platform_device *pdev)
struct fsl_usb2_wakeup_platform_data *pdata;
struct wakeup_ctrl *ctrl = NULL;
int status;
+ unsigned long interrupt_flag;
printk(KERN_INFO "IMX usb wakeup probe\n");
@@ -166,24 +174,31 @@ static int wakeup_dev_probe(struct platform_device *pdev)
if (!ctrl)
return -ENOMEM;
pdata = pdev->dev.platform_data;
+ ctrl->pdata = pdata;
init_waitqueue_head(&pdata->wq);
pdata->usb_wakeup_is_pending = false;
- ctrl->pdata = pdata;
init_completion(&ctrl->event);
- ctrl->wakeup_irq = platform_get_irq(pdev, 0);
- status = request_irq(ctrl->wakeup_irq, usb_wakeup_handler, IRQF_SHARED, "usb_wakeup", (void *)ctrl);
+ /* Currently, both mx5x and mx6q uses usb controller's irq
+ * as wakeup irq.
+ */
+ ctrl->wakeup_irq = platform_get_irq(pdev, 1);
+ ctrl->usb_irq = platform_get_irq(pdev, 1);
+ if (ctrl->wakeup_irq != ctrl->usb_irq)
+ interrupt_flag = IRQF_DISABLED;
+ else
+ interrupt_flag = IRQF_SHARED;
+ status = request_irq(ctrl->wakeup_irq, usb_wakeup_handler, interrupt_flag, "usb_wakeup", (void *)ctrl);
if (status)
goto error1;
- ctrl->usb_irq = platform_get_irq(pdev, 1);
ctrl->thread = kthread_run(wakeup_event_thread, (void *)ctrl, "usb_wakeup thread");
status = IS_ERR(ctrl->thread) ? -1 : 0;
if (status)
goto error2;
g_ctrl = ctrl;
- printk(KERN_DEBUG "the wakeup pdata is 0x%p\n", pdata);
+ printk(KERN_DEBUG "the wakeup pdata is 0x%p\n", pdata);
return 0;
error2:
free_irq(ctrl->wakeup_irq, (void *)ctrl);
@@ -206,7 +221,7 @@ static struct platform_driver wakeup_d = {
.probe = wakeup_dev_probe,
.remove = wakeup_dev_exit,
.driver = {
- .name = "usb_wakeup",
+ .name = "usb-wakeup",
},
};