From 12cfe15dd28f043523a75581b89f2c7203409f49 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Tue, 31 Aug 2010 15:38:09 -0700 Subject: [PATCH] [ARM] tegra: usb_phy: Moved suspend/resume code to ehci driver The suspend/resume methods should go to the ehci driver as they only save/restore ehci registers. Remove phy_init and initialize all phy registers in power_on as all the registers need to be reinitialized after LP0. Change-Id: I649d2cb66339aaff2d7db442a5441d2d3f06268b Signed-off-by: Benoit Goby --- arch/arm/mach-tegra/include/mach/usb_phy.h | 5 +- arch/arm/mach-tegra/usb_phy.c | 267 +++++---------------- 2 files changed, 61 insertions(+), 211 deletions(-) diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index 8f6bd2a948f3..2fe707070307 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -52,6 +52,7 @@ enum tegra_usb_phy_mode { struct tegra_usb_phy { int instance; + int freq_sel; void __iomem *regs; void __iomem *pad_regs; struct clk *pll_u; @@ -67,10 +68,6 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, int tegra_usb_phy_power_on(struct tegra_usb_phy *phy); -int tegra_usb_phy_suspend(struct tegra_usb_phy *phy); - -int tegra_usb_phy_resume(struct tegra_usb_phy *phy); - int tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy); int tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 50b099fedd09..fe3b7f8ecff2 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -28,16 +28,9 @@ #include #include -#define USB_USBCMD 0x140 - #define USB_USBSTS 0x144 #define USB_USBSTS_PCI (1 << 2) -#define USB_USBINTR 0x148 -#define USB_PERIODICLISTBASE 0x154 -#define USB_ASYNCLISTADDR 0x158 -#define USB_TXFILLTUNING 0x164 - #define USB_PORTSC1 0x184 #define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) #define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26) @@ -48,9 +41,6 @@ #define USB_PORTSC1_PE (1 << 2) #define USB_PORTSC1_CCS (1 << 0) -#define USB_OTGSC 0x1a4 -#define USB_USBMODE 0x1a8 - #define USB_SUSP_CTRL 0x400 #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) @@ -118,6 +108,9 @@ #define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) #define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) +#define UTMIP_BIAS_CFG1 0x83c +#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) + static DEFINE_SPINLOCK(utmip_pad_lock); static int utmip_pad_count; @@ -208,6 +201,8 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) } spin_unlock_irqrestore(&utmip_pad_lock, flags); + + clk_disable(phy->pad_clk); } static int utmip_pad_power_off(struct tegra_usb_phy *phy) @@ -220,6 +215,8 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy) return -1; } + clk_enable(phy->pad_clk); + spin_lock_irqsave(&utmip_pad_lock, flags); if (--utmip_pad_count == 0) { @@ -228,15 +225,16 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy) writel(val, base + UTMIP_BIAS_CFG0); } + spin_unlock_irqrestore(&utmip_pad_lock, flags); + clk_disable(phy->pad_clk); - spin_unlock_irqrestore(&utmip_pad_lock, flags); return 0; } static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) { - unsigned long timeout = 1000000; + unsigned long timeout = 2000; do { if ((readl(reg) & mask) == result) return 0; @@ -246,134 +244,62 @@ static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) return -1; } -static int utmi_phy_restore_context(struct tegra_usb_phy *phy) +static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) { + unsigned long val; void __iomem *base = phy->regs; - unsigned long val = 0; - int count = 0; - - /* If any saved context is present, restore it */ - if (!phy->context.valid) - return -1; - - /* Restore register context */ - count = phy->context.regs_count; - count--; - writel(phy->context.regs[count--], base + USB_USBMODE); - writel(phy->context.regs[count--], base + USB_OTGSC); - writel(phy->context.regs[count--], base + USB_TXFILLTUNING); - writel(phy->context.regs[count--], base + USB_ASYNCLISTADDR); - writel(phy->context.regs[count--], base + USB_PERIODICLISTBASE); - /* Restore interrupt context later */ - count--; - writel(phy->context.regs[count--], base + USB_USBCMD); - - /* Enable Port Power */ - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_PP; - writel(val, base + USB_PORTSC1); - udelay(10); - - /* Program the field PTC in PORTSC based on the saved speed mode */ - if (phy->context.port_speed == TEGRA_USB_PHY_PORT_HIGH) { - val = readl(base + USB_PORTSC1); - val &= ~(USB_PORTSC1_PTC(~0)); - val |= USB_PORTSC1_PTC(5); - writel(val, base + USB_PORTSC1); - } else if (phy->context.port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) { - val = readl(base + USB_PORTSC1); - val &= ~(USB_PORTSC1_PTC(~0)); - val |= USB_PORTSC1_PTC(6); - writel(val, base + USB_PORTSC1); - } else if (phy->context.port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) { - val = readl(base + USB_PORTSC1); - val &= ~(USB_PORTSC1_PTC(~0)); - val |= USB_PORTSC1_PTC(7); - writel(val, base + USB_PORTSC1); - } else { - pr_err("%s: speed is not configureed properly\n", __func__); - return -1; - } - udelay(10); - - /* Disable test mode by setting PTC field to NORMAL_OP */ - val = readl(base + USB_PORTSC1); - val &= ~(USB_PORTSC1_PTC(~0)); - writel(val, base + USB_PORTSC1); - /* Poll until CCS is enabled */ - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_CCS, - USB_PORTSC1_CCS)) { - pr_err("%s: timeout waiting for USB_PORTSC1_CCS\n", __func__); - return -1; - } + if (phy->instance == 0) { + val = readl(base + USB_SUSP_CTRL); + val |= USB_SUSP_SET; + writel(val, base + USB_SUSP_CTRL); - /* Poll until PE is enabled */ - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_PE, - USB_PORTSC1_PE)) { - pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); - return -1; - } + udelay(10); - /* Clear the PCI status, to avoid an interrupt taken upon resume */ - val = readl(base + USB_USBSTS); - val |= USB_USBSTS_PCI; - writel(val, base + USB_USBSTS); - if (utmi_wait_register(base + USB_USBSTS, USB_USBSTS_PCI, 0) < 0) { - pr_err("%s: timeout waiting for USB_USBSTS_PCI\n", __func__); - return -1; + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_SUSP_SET; + writel(val, base + USB_SUSP_CTRL); } - /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ - val = readl(base + USB_PORTSC1); - if ((val & USB_PORTSC1_PP) && (val & USB_PORTSC1_PE)) { - val |= USB_PORTSC1_SUSP; + if (phy->instance == 2) { + val = readl(base + USB_PORTSC1); + val |= USB_PORTSC1_PHCD; writel(val, base + USB_PORTSC1); - - /* Wait until port suspend completes */ - if (utmi_wait_register(base + USB_PORTSC1, USB_PORTSC1_SUSP, - USB_PORTSC1_SUSP)) { - pr_err("%s: timeout waiting for USB_PORTSC1_SUSP\n", - __func__); - return -1; - } } - /* Restore interrupt register */ - writel(phy->context.regs[1], base + USB_USBINTR); - udelay(10); - - return 0; + if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); } -static int utmi_phy_save_context(struct tegra_usb_phy *phy) +static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) { + unsigned long val; void __iomem *base = phy->regs; - int count = 0; - phy->context.port_speed = (readl(base + USB_PORTSC1) - & USB_PORTSC1_PSPD(3)) >> 26; + if (phy->instance == 0) { + val = readl(base + USB_SUSP_CTRL); + val |= USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); + + udelay(10); - /* If no device connection or invalid speeds just return */ - if (phy->context.port_speed > TEGRA_USB_PHY_PORT_HIGH) { - phy->context.valid = false; - return 0; + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); } - phy->context.regs[count++] = readl(base + USB_USBCMD); - phy->context.regs[count++] = readl(base + USB_USBINTR); - phy->context.regs[count++] = readl(base + USB_PERIODICLISTBASE); - phy->context.regs[count++] = readl(base + USB_ASYNCLISTADDR); - phy->context.regs[count++] = readl(base + USB_TXFILLTUNING); - phy->context.regs[count++] = readl(base + USB_OTGSC); - phy->context.regs[count++] = readl(base + USB_USBMODE); - phy->context.regs_count = count; - phy->context.valid = true; + if (phy->instance == 2) { + val = readl(base + USB_PORTSC1); + val &= ~USB_PORTSC1_PHCD; + writel(val, base + USB_PORTSC1); + } - return 0; + if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + USB_PHY_CLK_VALID)) + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); } -static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) +static void utmi_phy_power_on(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; @@ -389,6 +315,10 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) writel(val, base + USB1_LEGACY_CTRL); } + val = readl(base + UTMIP_TX_CFG0); + val &= ~UTMIP_FS_PREABMLE_J; + writel(val, base + UTMIP_TX_CFG0); + val = readl(base + UTMIP_HSRX_CFG0); val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0)); val |= UTMIP_IDLE_WAIT(config->idle_wait_delay); @@ -402,7 +332,7 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) val = readl(base + UTMIP_DEBOUNCE_CFG0); val &= ~UTMIP_BIAS_DEBOUNCE_A(~0); - val |= UTMIP_BIAS_DEBOUNCE_A(udc_debounce_table[freq_sel]); + val |= UTMIP_BIAS_DEBOUNCE_A(udc_debounce_table[phy->freq_sel]); writel(val, base + UTMIP_DEBOUNCE_CFG0); val = readl(base + UTMIP_MISC_CFG0); @@ -411,77 +341,15 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) val = readl(base + UTMIP_MISC_CFG1); val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0)); - val |= UTMIP_PLL_ACTIVE_DLY_COUNT(udc_delay_table[freq_sel][2]) | - UTMIP_PLLU_STABLE_COUNT(udc_delay_table[freq_sel][1]); + val |= UTMIP_PLL_ACTIVE_DLY_COUNT(udc_delay_table[phy->freq_sel][2]) | + UTMIP_PLLU_STABLE_COUNT(udc_delay_table[phy->freq_sel][1]); writel(val, base + UTMIP_MISC_CFG1); val = readl(base + UTMIP_PLL_CFG1); val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); - val |= UTMIP_XTAL_FREQ_COUNT(udc_delay_table[freq_sel][3]) | - UTMIP_PLLU_ENABLE_DLY_COUNT(udc_delay_table[freq_sel][0]); + val |= UTMIP_XTAL_FREQ_COUNT(udc_delay_table[phy->freq_sel][3]) | + UTMIP_PLLU_ENABLE_DLY_COUNT(udc_delay_table[phy->freq_sel][0]); writel(val, base + UTMIP_PLL_CFG1); -} - -static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *base = phy->regs; - - if (phy->instance == 0) { - val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_SET; - writel(val, base + USB_SUSP_CTRL); - - udelay(10); - - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_SET; - writel(val, base + USB_SUSP_CTRL); - } - - if (phy->instance == 2) { - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_PHCD; - writel(val, base + USB_PORTSC1); - } - - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); -} - -static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *base = phy->regs; - - if (phy->instance == 0) { - val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - - udelay(10); - - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - } - - if (phy->instance == 2) { - val = readl(base + USB_PORTSC1); - val &= ~USB_PORTSC1_PHCD; - writel(val, base + USB_PORTSC1); - } - - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID)) - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); -} - -static void utmi_phy_power_on(struct tegra_usb_phy *phy) -{ - unsigned long val; - void __iomem *base = phy->regs; - struct tegra_utmip_config *config = phy->config; if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { val = readl(base + USB_SUSP_CTRL); @@ -511,6 +379,11 @@ static void utmi_phy_power_on(struct tegra_usb_phy *phy) val &= ~UTMIP_PD_CHRG; writel(val, base + UTMIP_BAT_CHRG_CFG0); + val = readl(base + UTMIP_BIAS_CFG1); + val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); + val |= UTMIP_BIAS_PDTRK_COUNT(0x5); + writel(val, base + UTMIP_BIAS_CFG1); + if (phy->instance == 2) { val = readl(base + USB_SUSP_CTRL); val |= UTMIP_PHY_ENABLE; @@ -613,13 +486,13 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, err = -EINVAL; goto err1; } + phy->freq_sel = freq_sel; /* TODO usb2 ulpi */ if (phy->instance != 1) { err = utmip_pad_open(phy); if (err < 0) goto err1; - utmi_phy_init(phy, freq_sel); } return phy; @@ -666,26 +539,6 @@ int tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) return 0; } -int tegra_usb_phy_suspend(struct tegra_usb_phy *phy) -{ - if (phy->instance != 1) { - utmi_phy_save_context(phy); - utmi_phy_power_off(phy); - } - - return 0; -} - -int tegra_usb_phy_resume(struct tegra_usb_phy *phy) -{ - if (phy->instance != 1) { - utmi_phy_power_on(phy); - return utmi_phy_restore_context(phy); - } - - return 0; -} - int tegra_usb_phy_close(struct tegra_usb_phy *phy) { if (phy->instance != 1) -- 2.34.1