summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx5/usb_dr.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mx5/usb_dr.c')
-rw-r--r--arch/arm/mach-mx5/usb_dr.c176
1 files changed, 159 insertions, 17 deletions
diff --git a/arch/arm/mach-mx5/usb_dr.c b/arch/arm/mach-mx5/usb_dr.c
index 658583b65ab6..4f36379b8d64 100644
--- a/arch/arm/mach-mx5/usb_dr.c
+++ b/arch/arm/mach-mx5/usb_dr.c
@@ -18,12 +18,12 @@
#include <linux/fsl_devices.h>
#include <mach/arc_otg.h>
#include <mach/hardware.h>
+#include <asm/delay.h>
#include "usb.h"
#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC)
static int usbotg_init_ext(struct platform_device *pdev);
static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata);
-static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable);
static void usbotg_clock_gate(bool on);
/*
@@ -40,7 +40,6 @@ static struct fsl_usb2_platform_data dr_utmi_config = {
.gpio_usb_active = gpio_usbotg_hs_active,
.gpio_usb_inactive = gpio_usbotg_hs_inactive,
.usb_clock_for_pm = usbotg_clock_gate,
- .wake_up_enable = _wake_up_enable,
.transceiver = "utmi",
};
@@ -48,6 +47,13 @@ static struct fsl_usb2_platform_data dr_utmi_config = {
static int usbotg_init_ext(struct platform_device *pdev)
{
struct clk *usb_clk;
+ if (cpu_is_mx50()) {
+ usb_clk = clk_get(&pdev->dev, "usb_phy1_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ return usbotg_init(pdev);
+ }
usb_clk = clk_get(NULL, "usboh3_clk");
clk_enable(usb_clk);
@@ -69,6 +75,15 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata)
{
struct clk *usb_clk;
+ if (cpu_is_mx50()) {
+ usb_clk = clk_get(&pdata->pdev->dev, "usb_phy1_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+
+ usbotg_uninit(pdata);
+ return;
+ }
+
usb_clk = clk_get(NULL, "usboh3_clk");
clk_disable(usb_clk);
clk_put(usb_clk);
@@ -80,33 +95,149 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata)
usbotg_uninit(pdata);
}
-static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+#define ENABLED_BY_HOST (0x1 << 0)
+#define ENABLED_BY_DEVICE (0x1 << 1)
+#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC)
+/* Below two macros are used at otg mode to indicate usb mode*/
+static u32 wakeup_irq_enable_src = 0;
+static void __wakeup_irq_enable(bool on, int source)
{
- if (get_usb_mode(pdata) == FSL_USB_DR_DEVICE) {
- if (enable) {
+ /* 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) {
+ wakeup_irq_enable_src |= source;
+ if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
USBCTRL |= UCTRL_OWIE;
- USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN;
USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2;
- } else {
- USBCTRL &= ~UCTRL_OWIE;
- USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN;
- USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2;
+ printk("OTG wakeup irq is enabled\n");
}
- } else {
- if (enable) {
- USBCTRL |= UCTRL_OWIE;
- USBCTRL_HOST2 |= (1 << 5);
- } else {
- USBCTRL &= ~UCTRL_OWIE;
- USBCTRL_HOST2 &= ~(1 << 5);
+ }else {
+ printk("OTG wakeup irq disable\n");
+ USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2;
+ USBCTRL &= ~UCTRL_OWIE;
+ 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);
+ }
+}
+#else
+static void __wakeup_irq_enable(bool on, int source)
+{
+ if (on) {
+ USBCTRL |= UCTRL_OWIE;
+ USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2;
+ }else {
+ USBCTRL &= ~UCTRL_OWIE;
+ USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2;
+ /* The interrupt must be disabled for at least 3 clock
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+#endif
+
+#ifdef CONFIG_USB_EHCI_ARC_OTG
+static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __wakeup_irq_enable(enable, ENABLED_BY_HOST);
+ /* host only care the ID change wakeup event */
+ if (enable) {
+ USBCTRL_HOST2 |= UCTRL_H2OIDWK_EN;
+ }else {
+ USBCTRL_HOST2 &= ~UCTRL_H2OIDWK_EN;
+ /* The interrupt must be disabled for at least 2 clock
+ * cycles of the standby clock(32k Hz) , that is 0.0625 ms*/
+ udelay(100);
+ }
+}
+#endif
+
+#ifdef CONFIG_USB_GADGET_ARC
+static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __wakeup_irq_enable(enable, ENABLED_BY_DEVICE);
+ /* if udc is not used by any gadget, we can not enable the vbus wakeup */
+ if (!pdata->port_enables)
+ {
+ USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN;
+ return;
+ }
+ if (enable) {
+ USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN;
+ }else {
+ USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN;
+ }
+}
+#endif
+
+#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC)
+static u32 low_power_enable_src = 0;
+static void __phy_lowpower_suspend(bool enable, int source)
+{
+ if (enable) {
+ low_power_enable_src |= source;
+ if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
+ UOG_PORTSC1 |= PORTSC_PHCD;
+ printk("OTG phy lowpower enable\n");
}
+ }else {
+ printk("OTG phy lowpower disable\n");
+ UOG_PORTSC1 &= ~PORTSC_PHCD;
+ low_power_enable_src &= ~source;
+ }
+}
+#else
+static void __phy_lowpower_suspend(bool enable, int source)
+{
+ if (enable) {
+ UOG_PORTSC1 |= PORTSC_PHCD;
+ }else {
+ UOG_PORTSC1 &= ~PORTSC_PHCD;
}
}
+#endif
+
+#ifdef CONFIG_USB_EHCI_ARC_OTG
+static void _host_phy_lowpower_suspend(bool enable)
+{
+ __phy_lowpower_suspend(enable, ENABLED_BY_HOST);
+}
+#endif
+
+#ifdef CONFIG_USB_GADGET_ARC
+static void _device_phy_lowpower_suspend(bool enable)
+{
+ __phy_lowpower_suspend(enable, ENABLED_BY_DEVICE);
+}
+#endif
static void usbotg_clock_gate(bool on)
{
struct clk *usb_clk;
+ if (cpu_is_mx50()) {
+ if (on) {
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ usb_clk = clk_get(NULL, "usb_phy1_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+ } else {
+ usb_clk = clk_get(NULL, "usb_phy1_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+ }
+ return;
+ }
+
if (on) {
usb_clk = clk_get(NULL, "usb_ahb_clk");
clk_enable(usb_clk);
@@ -140,6 +271,13 @@ static void usbotg_clock_gate(bool on)
}
#endif
+void mx5_set_otghost_vbus_func(driver_vbus_func driver_vbus)
+{
+#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC)
+ dr_utmi_config.platform_driver_vbus = driver_vbus;
+#endif
+}
+
void __init mx5_usb_dr_init(void)
{
#ifdef CONFIG_USB_OTG
@@ -149,11 +287,15 @@ void __init mx5_usb_dr_init(void)
#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;
platform_device_add_data(&mxc_usbdr_host_device, &dr_utmi_config, sizeof(dr_utmi_config));
platform_device_register(&mxc_usbdr_host_device);
#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;
platform_device_add_data(&mxc_usbdr_udc_device, &dr_utmi_config, sizeof(dr_utmi_config));
platform_device_register(&mxc_usbdr_udc_device);
#endif