[ARM] tegra: Add USB PHY configuration
authorBenoit Goby <benoit@android.com>
Wed, 28 Jul 2010 07:10:13 +0000 (00:10 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:27:18 +0000 (16:27 -0700)
Configure board dependant phy settings from the board file.

Change-Id: I29f6ffe0b84a2a6eb55bade1379002f561d92d17
Signed-off-by: Benoit Goby <benoit@android.com>
arch/arm/mach-tegra/include/mach/usb_phy.h
arch/arm/mach-tegra/usb_phy.c
drivers/usb/gadget/fsl_tegra_udc.c
drivers/usb/host/ehci-tegra.c
include/linux/fsl_devices.h

index 285c65cc511c1a6f6c6ba7f6557dc3981e3e81d2..85de3df94774340f21faae8c3dd9e2f298b16e13 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 
+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);
index fb829861f5d47b07f9e776b6790b938756d1497d..40358d3532ab24e9dfc7ec48ce5c08eb4c8197bc 100644 (file)
@@ -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)) {
index fc666bbd6b8b8b866e88c2d55688596abdec4f55..42f3effd3ba5588d8dc802fa852ea7254f335f27 100644 (file)
@@ -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);
index b93aefb6f3c3f997c36dd7629ea30b2f4cd6f260..6c3618291d20f058fdb386be7ba081a06ebf8e5b 100644 (file)
@@ -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;
index 28e33fea510736f179ccfdb985e0d630b0aae616..b39a195775e31fe0ea801aefe8a41553eb04757e 100644 (file)
@@ -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 */