From ce3a041d2eb6d21544b311de6d7b337becf5ef74 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Wed, 28 Jul 2010 00:10:13 -0700 Subject: [PATCH] [ARM] tegra: Add USB PHY configuration Configure board dependant phy settings from the board file. Change-Id: I29f6ffe0b84a2a6eb55bade1379002f561d92d17 Signed-off-by: Benoit Goby --- arch/arm/mach-tegra/include/mach/usb_phy.h | 14 +++++- arch/arm/mach-tegra/usb_phy.c | 52 ++++++++++++++++------ drivers/usb/gadget/fsl_tegra_udc.c | 4 +- drivers/usb/host/ehci-tegra.c | 5 ++- include/linux/fsl_devices.h | 1 + 5 files changed, 60 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index 285c65cc511c..85de3df94774 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -20,10 +20,21 @@ #include #include +struct tegra_utmip_config { + u8 hssync_start_delay; + u8 elastic_limit; + u8 idle_wait_delay; + u8 term_range_adj; + u8 xcvr_setup; + u8 xcvr_lsfslew; + u8 xcvr_lsrslew; +}; + struct tegra_usb_phy { int instance; void __iomem *regs; struct clk *pll_u; + struct tegra_utmip_config *config; }; enum tegra_usb_phy_mode { @@ -31,7 +42,8 @@ enum tegra_usb_phy_mode { TEGRA_USB_PHY_MODE_HOST, }; -struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs); +struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, + struct tegra_utmip_config *config); int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, enum tegra_usb_phy_mode phy_mode); diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index fb829861f5d4..40358d3532ab 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -120,6 +120,27 @@ static const u16 udc_debounce_table[] = { 0xFDE8, /* 26 MHz */ }; +static struct tegra_utmip_config utmip_default[] = { + [0] = { + .hssync_start_delay = 9, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 9, + .xcvr_lsfslew = 1, + .xcvr_lsrslew = 1, + }, + [2] = { + .hssync_start_delay = 9, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 9, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + }, +}; + static int utmi_phy_wait_stable(struct tegra_usb_phy *phy) { void __iomem *base = phy->regs; @@ -141,6 +162,7 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) { unsigned long val; void __iomem *base = phy->regs; + struct tegra_utmip_config *config = phy->config; val = readl(base + USB_SUSP_CTRL); val |= UTMIP_RESET; @@ -154,12 +176,13 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) val = readl(base + UTMIP_HSRX_CFG0); val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0)); - val |= UTMIP_IDLE_WAIT(17) | UTMIP_ELASTIC_LIMIT(16); + val |= UTMIP_IDLE_WAIT(config->idle_wait_delay); + val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit); writel(val, base + UTMIP_HSRX_CFG0); val = readl(base + UTMIP_HSRX_CFG1); val &= ~UTMIP_HS_SYNC_START_DLY(~0); - val |= UTMIP_HS_SYNC_START_DLY(9); + val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay); writel(val, base + UTMIP_HSRX_CFG1); val = readl(base + UTMIP_DEBOUNCE_CFG0); @@ -189,6 +212,7 @@ 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); @@ -198,15 +222,12 @@ void utmi_phy_power_on(struct tegra_usb_phy *phy, val = readl(base + UTMIP_XCVR_CFG0); val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0)); - if (phy_mode == TEGRA_USB_PHY_MODE_HOST) { - val &= ~(UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0)); - val |= UTMIP_XCVR_LSFSLEW(2) | UTMIP_XCVR_LSRSLEW(2); - val |= UTMIP_XCVR_SETUP(0x9); - } else { - val &= ~(UTMIP_XCVR_HSSLEW_MSB(~0)); - val |= UTMIP_XCVR_SETUP(0xF); - } + UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) | + UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) | + UTMIP_XCVR_HSSLEW_MSB(~0)); + val |= UTMIP_XCVR_SETUP(config->xcvr_setup); + val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); + val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); writel(val, base + UTMIP_XCVR_CFG0); val = readl(base + UTMIP_BIAS_CFG0); @@ -216,7 +237,7 @@ void utmi_phy_power_on(struct tegra_usb_phy *phy, val = readl(base + UTMIP_XCVR_CFG1); val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0)); - val |= UTMIP_XCVR_TERM_RANGE_ADJ(0x6); + val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj); writel(val, base + UTMIP_XCVR_CFG1); val = readl(base + UTMIP_BAT_CHRG_CFG0); @@ -310,7 +331,8 @@ void utmi_phy_power_off(struct tegra_usb_phy *phy) writel(val, base + UTMIP_XCVR_CFG1); } -struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs) +struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, + struct tegra_utmip_config *config) { struct tegra_usb_phy *phy; unsigned long parent_rate; @@ -323,6 +345,10 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs) phy->instance = instance; phy->regs = regs; + phy->config = config; + + if (!phy->config) + phy->config = &utmip_default[instance]; phy->pll_u = clk_get_sys(NULL, "pll_u"); if (IS_ERR(phy->pll_u)) { diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c index fc666bbd6b8b..42f3effd3ba5 100644 --- a/drivers/usb/gadget/fsl_tegra_udc.c +++ b/drivers/usb/gadget/fsl_tegra_udc.c @@ -22,6 +22,8 @@ int fsl_udc_clk_init(struct platform_device *pdev) struct resource *res; int err; int instance; + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + udc_clk = clk_get(&pdev->dev, NULL); if (IS_ERR(udc_clk)) { @@ -49,7 +51,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) if (instance == -1) instance = 0; - phy = tegra_usb_phy_open(instance, udc_base); + phy = tegra_usb_phy_open(instance, udc_base, pdata->phy_config); if (IS_ERR(phy)) { dev_err(&pdev->dev, "Can't open phy\n"); err = PTR_ERR(phy); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index b93aefb6f3c3..6c3618291d20 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -366,6 +366,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) struct usb_hcd *hcd; struct ehci_hcd *ehci; struct tegra_ehci_hcd *tegra; + struct tegra_utmip_config *config; int err = 0; int irq; unsigned int temp; @@ -412,7 +413,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_io; } - tegra->phy = tegra_usb_phy_open(instance, hcd->regs); + config = pdev->dev.platform_data; + + tegra->phy = tegra_usb_phy_open(instance, hcd->regs, config); if (IS_ERR(tegra->phy)) { dev_err(&pdev->dev, "Failed to open USB phy\n"); err = -ENXIO; diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 28e33fea5107..b39a195775e3 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -63,6 +63,7 @@ struct fsl_usb2_platform_data { enum fsl_usb2_operating_modes operating_mode; enum fsl_usb2_phy_modes phy_mode; unsigned int port_enables; + void *phy_config; }; /* Flags in fsl_usb2_mph_platform_data */ -- 2.34.1