diff options
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", }, }; |