summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mvf/usb_dr.c
diff options
context:
space:
mode:
authorRussell Robinson Jr <rrobinson@phytec.com>2013-02-11 13:34:12 -0800
committerRussell Robinson Jr <rrobinson@phytec.com>2013-02-11 15:34:15 -0800
commit16af5ee7d9556c47b332788e4107cbed5ee7ec10 (patch)
treee9424582f1fdc92d360ff58c831ddf801a268e3f /arch/arm/mach-mvf/usb_dr.c
parentfd5b59f7d6fc1736c2b00f306dcfeb574fea4512 (diff)
pcm052: usb: enable both USB0 and USB1 as ehci-host
note: there are still intermittent detection errors with USB0 Signed-off-by: Russell Robinson Jr <rrobinson@phytec.com>
Diffstat (limited to 'arch/arm/mach-mvf/usb_dr.c')
-rw-r--r--arch/arm/mach-mvf/usb_dr.c228
1 files changed, 133 insertions, 95 deletions
diff --git a/arch/arm/mach-mvf/usb_dr.c b/arch/arm/mach-mvf/usb_dr.c
index bbd29f3b45a9..34377c4c19b3 100644
--- a/arch/arm/mach-mvf/usb_dr.c
+++ b/arch/arm/mach-mvf/usb_dr.c
@@ -20,6 +20,7 @@
#include <linux/types.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
#include <linux/fsl_devices.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -37,10 +38,6 @@ static void usbotg_clock_gate(bool on);
static void _dr_discharge_line(bool enable);
static void usbotg_wakeup_event_clear(void);
-/* The usb_phy0_clk do not have enable/disable function at clock.c
- * and PLL output for usb0's phy should be always enabled.
- * usb_phy0_clk only stands for usb uses pll3 as its parent.
- */
static struct clk *usb_phy0_clk;
static u8 otg_used;
@@ -65,24 +62,22 @@ static struct fsl_usb2_platform_data dr_utmi_config = {
/* Platform data for wakeup operation */
static struct fsl_usb2_wakeup_platform_data dr_wakeup_config = {
- .name = "Gadget wakeup",
+ .name = "Host wakeup",
.usb_clock_for_pm = usbotg_clock_gate,
.usb_wakeup_exhandle = usbotg_wakeup_event_clear,
};
static void usbotg_internal_phy_clock_gate(bool on)
{
- u32 reg;
-
void __iomem *phy_reg = MVF_IO_ADDRESS(MVF_USBPHY0_BASE_ADDR);
- reg = __raw_readl(phy_reg + HW_USBPHY_CTRL);
if (on)
- reg &= ~BM_USBPHY_CTRL_CLKGATE;
+ __raw_writel(BM_USBPHY_CTRL_CLKGATE,
+ phy_reg + HW_USBPHY_CTRL_CLR);
else
- reg |= BM_USBPHY_CTRL_CLKGATE;
+ __raw_writel(BM_USBPHY_CTRL_CLKGATE,
+ phy_reg + HW_USBPHY_CTRL_SET);
- __raw_writel(reg, phy_reg + HW_USBPHY_CTRL);
}
static int usb_phy_enable(struct fsl_usb2_platform_data *pdata)
@@ -114,6 +109,13 @@ static int usb_phy_enable(struct fsl_usb2_platform_data *pdata)
/* 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;
}
@@ -136,8 +138,8 @@ static int usbotg_init_ext(struct platform_device *pdev)
usbotg_internal_phy_clock_gate(true);
usb_phy_enable(pdev->dev.platform_data);
/*
- * after the phy reset,can not read the value for id/vbus at
- * the register of otgsc ,cannot read at once ,need delay 3 ms
+ * after the phy reset,can't read the value for id/vbus at
+ * the register of otgsc at once ,need delay 3 ms
*/
mdelay(3);
}
@@ -159,21 +161,18 @@ static void usbotg_uninit_ext(struct platform_device *pdev)
static void usbotg_clock_gate(bool on)
{
- pr_debug("%s: on is %d\n", __func__, on);
+
if (on)
clk_enable(usb_phy0_clk);
else
clk_disable(usb_phy0_clk);
+
}
-/*
-void mvf_set_otghost_vbus_func(driver_vbus_func driver_vbus)
-{
- dr_utmi_config.platform_driver_vbus = driver_vbus;
-}
-*/
+
static void _dr_discharge_line(bool enable)
{
void __iomem *phy_reg = MVF_IO_ADDRESS(MVF_USBPHY0_BASE_ADDR);
+
if (enable) {
__raw_writel(BF_USBPHY_DEBUG_ENHSTPULLDOWN(0x3),
phy_reg + HW_USBPHY_DEBUG_SET);
@@ -191,7 +190,6 @@ static void _dr_discharge_line(bool enable)
/* 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)
{
@@ -233,12 +231,11 @@ static void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata,
static void __phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata,
bool enable, int source)
{
- if (enable) {
- low_power_enable_src |= source;
+ if (enable)
enter_phy_lowpower_suspend(pdata, enable);
- } else {
+ else {
+ pr_debug("phy lowpower disable\n");
enter_phy_lowpower_suspend(pdata, enable);
- low_power_enable_src &= ~source;
}
}
@@ -270,10 +267,9 @@ static void otg_wake_up_enable(struct fsl_usb2_platform_data *pdata,
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) {
+ pr_debug("USB Host %s,on=%d\n", __func__, on);
+ mdelay(3);
+ if (on) {
otg_wake_up_enable(pdata, on);
} else {
otg_wake_up_enable(pdata, on);
@@ -302,125 +298,167 @@ static void usbotg_wakeup_event_clear(void)
}
/* End of Common operation for DR port */
+
#ifdef CONFIG_USB_EHCI_ARC_OTG
-#endif /* CONFIG_USB_EHCI_ARC_OTG */
+/* Beginning of host related operation for DR port */
+static void _host_platform_suspend(struct fsl_usb2_platform_data *pdata)
+{
+ void __iomem *phy_reg = MVF_IO_ADDRESS(MVF_USBPHY0_BASE_ADDR);
+ u32 tmp;
+ 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);
+}
-#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,
+static void _host_platform_resume(struct fsl_usb2_platform_data *pdata)
+{
+ void __iomem *phy_reg = MVF_IO_ADDRESS(MVF_USBPHY0_BASE_ADDR);
+ u32 tmp;
+
+ 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 void _host_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata,
bool enable)
{
- __phy_lowpower_suspend(pdata, enable, ENABLED_BY_DEVICE);
+ __phy_lowpower_suspend(pdata, enable, ENABLED_BY_HOST);
}
-static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata,
+static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata,
bool enable)
{
- __wakeup_irq_enable(pdata, enable, ENABLED_BY_DEVICE);
- if (enable) {
- pr_debug("device wakeup enable\n");
+ __wakeup_irq_enable(pdata, enable, ENABLED_BY_HOST);
+
+ if (enable)
device_wakeup_enable(&pdata->pdev->dev);
- } else {
- pr_debug("device wakeup disable\n");
+ else
device_wakeup_disable(&pdata->pdev->dev);
- }
}
static enum usb_wakeup_event
-_is_device_wakeup(struct fsl_usb2_platform_data *pdata)
+_is_host_wakeup(struct fsl_usb2_platform_data *pdata)
{
- int wakeup_req = USBC0_CTRL & UCTRL_OWIR;
+ u32 wakeup_req = USBC0_CTRL & UCTRL_OWIR;
+ u32 otgsc = UOG_OTGSC;
- /* if ID=1, it is a device wakeup event */
- 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 WAKEUP_EVENT_DPDM;
- }
- if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && \
- ((UOG_USBSTS & USBSTS_PCI) ||
- (UOG_PORTSC1 & PORTSC_PORT_FORCE_RESUME))) {
- /*
- * When the line state from J to K, the Port Change Detect bit
- * in the USBSTS register is also set to '1'.
- */
- printk(KERN_INFO "otg udc wakeup, host sends resume signal\n");
- return WAKEUP_EVENT_DPDM;
+ 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 (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 WAKEUP_EVENT_VBUS;
+ /* 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 && (UOG_OTGSC & OTGSC_STS_USB_ID) &&
- !(UOG_OTGSC & OTGSC_STS_A_VBUS_VALID)) {
- printk(KERN_INFO "otg udc vbus falling wakeup\n");
- return WAKEUP_EVENT_VBUS;
+ if (wakeup_req && (!(otgsc & OTGSC_STS_USB_ID))) {
+ pr_debug("otg host Remote wakeup\n");
+ return WAKEUP_EVENT_DPDM;
}
-
- return WAKEUP_EVENT_DPDM;
+ return WAKEUP_EVENT_INVALID;
}
-static void device_wakeup_handler(struct fsl_usb2_platform_data *pdata)
+static void host_wakeup_handler(struct fsl_usb2_platform_data *pdata)
{
- _device_phy_lowpower_suspend(pdata, false);
- _device_wakeup_enable(pdata, false);
+ _host_phy_lowpower_suspend(pdata, false);
+ _host_wakeup_enable(pdata, false);
}
-/* end of device related operation for DR port */
-#endif /* CONFIG_USB_GADGET_ARC */
+
+/* End of host related operation for DR port */
+#endif /* CONFIG_USB_EHCI_ARC_OTG */
+
void __init mvf_usb_dr_init(void)
{
struct platform_device *pdev, *pdev_wakeup;
u32 reg;
-#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.platform_suspend = NULL;
- dr_utmi_config.platform_resume = NULL;
- dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend;
- dr_utmi_config.is_wakeup_event = _is_device_wakeup;
+
+#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.platform_suspend = _host_platform_suspend;
+ dr_utmi_config.platform_resume = _host_platform_resume;
+ 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 = device_wakeup_handler;
+ dr_utmi_config.wakeup_handler = host_wakeup_handler;
- pdev = mvf_add_fsl_usb2_udc(&dr_utmi_config);
+ pdev = mvf_add_fsl_ehci_otg(0, &dr_utmi_config);
- dr_wakeup_config.usb_pdata[2] = pdev->dev.platform_data;
+ dr_wakeup_config.usb_pdata[0] = pdev->dev.platform_data;
/* register wakeup device */
- pdev_wakeup = mvf_add_fsl_usb2_udc_wakeup(&dr_wakeup_config);
+ pdev_wakeup = mvf_add_fsl_usb2_ehci_otg_wakeup(0, &dr_wakeup_config);
if (pdev != NULL)
((struct fsl_usb2_platform_data *)
(pdev->dev.platform_data))->wakeup_pdata =
(struct fsl_usb2_wakeup_platform_data *)
(pdev_wakeup->dev.platform_data);
- device_set_wakeup_capable(&pdev->dev, true);
- __raw_writel(((0x01 << 30) | 0x2), ANADIG_USB1_MISC);
-
- __raw_writel(0x00000894, USBPHY1_CTRL);
- udelay(10);
+ __raw_writel(0x0220C802, USBPHY1_CTRL);
+ udelay(20);
__raw_writel(0x0, USBPHY1_PWD);
- __raw_writel(0x1, USBPHY1_IP);
- udelay(20);
- __raw_writel(0x7, USBPHY1_IP);
reg = __raw_readl(USBPHY1_DEBUG);
- reg &= ~0x40000000; /* clear gate clock */
+ reg &= ~0x40000000; /* clear clock gate */
__raw_writel(reg, USBPHY1_DEBUG);
+ reg = __raw_readl(ANADIG_USB1_MISC);
+ reg |= (0x01 << 30); /* Enable CLK_TO_UTMI */
+ __raw_writel(reg, ANADIG_USB1_MISC);
+
__raw_writel(0x10000007, USBPHY1_TX);
+ /*__raw_writel(0x100F0F07, USBPHY1_TX);*/
+
+ /* Enable disconnect detect */
reg = __raw_readl(USBPHY1_CTRL);
- reg |= ((0xD1 << 11) | 0x6);
+ reg &= ~0x040; /* clear OTG ID change IRQ */
+ reg |= (0x1 << 14); /* Enable UTMI+ level2 */
+ reg |= (0x1 << 9);
+ reg |= (0x1 << 15); /* Enable UTMI+ level3 */
+ reg &= ~((0xD1 << 11) | 0x6);
__raw_writel(reg, USBPHY1_CTRL);
+ __raw_writel(0x1 << 3, USBPHY1_CTRL + 0x8);
+ /* Disable VBUS and CHARGER detect */
reg = __raw_readl(ANADIG_USB1_VBUS_DETECT);
reg |= 0xE8;
__raw_writel(reg, ANADIG_USB1_VBUS_DETECT);
__raw_writel(0x001c0000, ANADIG_USB1_CHRG_DETECT);
+
#endif
+}
+
+/* USB HIGH_SPEED disconnect detect on/off */
+void fsl_platform_set_usb0_phy_dis(struct fsl_usb2_platform_data *pdata,
+ bool enable)
+{
+ u32 reg;
+ reg = __raw_readl(USBPHY1_CTRL);
+
+ if (enable)
+ reg |= ((0xD1 << 11) | 0x6);
+ else
+ reg &= ~((0xD1 << 11) | 0x6);
+
+ __raw_writel(reg, USBPHY1_CTRL);
+
+ __raw_writel(0x1 << 3, USBPHY1_CTRL + 0x8);
}