]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
usb: phy: tegra: Add CDP charger detection
authorPhilip Rakity <prakity@nvidia.com>
Wed, 26 Mar 2014 05:56:04 +0000 (11:26 +0530)
committerRiham Haidar <rhaidar@nvidia.com>
Mon, 28 Apr 2014 22:20:37 +0000 (15:20 -0700)
Add CDP charger detection code and reset
the charger before doing QC2.0 charger detection
to handle misc cases.

Bug 1424733
Bug 1458999

Change-Id: Ibf07d1f9416f8cfefe808129babef2e590bd8150
Reviewed-on: http://git-master/r/384597
Reviewed-on: http://git-master/r/396041
(cherry picked from commit 35be4ca44e5c4e16619e2b7a6b186d2bb2b94b78)
(cherry picked from commit 0c4b2de8640ebb0a8bf5d2477afc6aab043cce24)
Signed-off-by: Rakesh Bodla <rbodla@nvidia.com>
Signed-off-by: Philip Rakity <prakity@nvidia.com>
Reviewed-on: http://git-master/r/401888
GVS: Gerrit_Virtual_Submit
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/phy/tegra11x_usb_phy.c
drivers/usb/phy/tegra_usb_phy.h

index 4d35ba58b3a48d6ca10f7c2756d80d456ca5a61b..ce98e7258fc359e926086a68192746da3ab952e9 100644 (file)
@@ -607,6 +607,17 @@ bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy)
        return status;
 }
 
+bool tegra_usb_phy_cdp_charger_detected(struct tegra_usb_phy *phy)
+{
+       bool status = 0;
+
+       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+       if (phy->ops && phy->ops->cdp_charger_detect)
+               status = phy->ops->cdp_charger_detect(phy);
+
+       return status;
+}
+
 bool tegra_usb_phy_qc2_charger_detected(struct tegra_usb_phy *phy,
                        int max_voltage)
 {
index 22df714c1f45dfd79be213fce20fecf76d2af9a4..0b9f44971ee138cc7c0f5714606864e9a4d3b3eb 100644 (file)
@@ -1414,6 +1414,7 @@ static void disable_charger_detection(void __iomem *base)
        /* Disable charger detection logic */
        val = readl(base + UTMIP_BAT_CHRG_CFG0);
        val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
+       val &= ~(UTMIP_ON_SRC_EN | UTMIP_OP_SINK_EN);
        writel(val, base + UTMIP_BAT_CHRG_CFG0);
 
        /* Delay of 40 ms before we pull the D+ as per battery charger spec */
@@ -1518,8 +1519,47 @@ static bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
                status = false;
                disable_charger_detection(base);
        }
+       DBG("%s(%d) inst:[%d], UTMIP_BAT_CHRG_CFG0 = %08X\n",
+               __func__, __LINE__,
+               phy->inst, readl(base + UTMIP_BAT_CHRG_CFG0));
+       DBG("%s(%d) inst:[%d], UTMIP_MISC_CFG0 = %08X\n",
+               __func__, __LINE__,
+               phy->inst, readl(base + UTMIP_MISC_CFG0));
+
        DBG("%s(%d) inst:[%d] DONE Status = %d\n",
                __func__, __LINE__, phy->inst, status);
+
+       return status;
+}
+
+static bool cdp_charger_detection(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       int status;
+       void __iomem *base = phy->regs;
+
+       /* SRC D- to D+ */
+       val = readl(base + UTMIP_BAT_CHRG_CFG0);
+       val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
+       val |= UTMIP_ON_SRC_EN | UTMIP_OP_SINK_EN;
+       writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+       DBG("%s(%d) UTMIP_BAT_CHRG_CFG0 = %08x\n",
+               __func__, __LINE__,
+               readl(base + UTMIP_BAT_CHRG_CFG0));
+
+       msleep(10);
+
+       val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+       if (val & VDAT_DET_STS) {
+               status = false;
+               DBG("%s: DCP detected\n", __func__);
+       } else {
+               status = true;
+               disable_charger_detection(base);
+               DBG("%s: No voltage from D- to D+ found\n", __func__);
+       }
+
        return status;
 }
 
@@ -1531,6 +1571,7 @@ static bool utmi_phy_qc2_charger_detect(struct tegra_usb_phy *phy,
        int status;
        int qc2_timeout_ms;
        int vbus_stat = 0;
+       unsigned long org_flags;
 #ifdef QC_MEASURE_VOLTAGES
        int timeout;
 #endif
@@ -1539,23 +1580,40 @@ static bool utmi_phy_qc2_charger_detect(struct tegra_usb_phy *phy,
                __func__, __LINE__, phy->inst, max_voltage);
 
        status = false;
-
        /* no need to detect qc2 if operating at 5V */
        switch (max_voltage) {
+       case TEGRA_USB_QC2_5V:
        case TEGRA_USB_QC2_9V:
        case TEGRA_USB_QC2_12V:
        case TEGRA_USB_QC2_20V:
                break;
-
-       case TEGRA_USB_QC2_5V:
        default:
                disable_charger_detection(base);
                return status;
        }
 
+       /* Ensure we start from an initial state */
+       writel(0, base + UTMIP_BAT_CHRG_CFG0);
+       utmi_phy_set_dp_dm_pull_up_down(phy, 0);
+
+       /* Force wall charger detection logic to reset */
+       org_flags = utmi_phy_set_dp_dm_pull_up_down(phy,
+               FORCE_PULLDN_DP | FORCE_PULLDN_DM);
+       ssleep(1);
+       msleep(500);
+       utmi_phy_set_dp_dm_pull_up_down(phy, org_flags);
+
+       /* Enable charger detection logic */
+       val = readl(base + UTMIP_BAT_CHRG_CFG0);
+       val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN;
+       writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+       /* Source should be on for 100 ms as per USB charging spec */
+       msleep(TDP_SRC_ON_MS);
+
        /* if vbus drops we are connected to quick charge 2 */
        qc2_timeout_ms = 0;
-       while (qc2_timeout_ms < 2000) {
+       while (qc2_timeout_ms < 1500) {
                usleep_range(1000, 1200);
                qc2_timeout_ms += 1;
                val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
@@ -1565,14 +1623,15 @@ static bool utmi_phy_qc2_charger_detect(struct tegra_usb_phy *phy,
                }
        }
 
-       if (vbus_stat) {
-               unsigned long org_flags;
-
+       if (vbus_stat && qc2_timeout_ms > 100) {
                status = true;
 
                DBG("%s(%d) inst:[%d], QC2 DETECTED !!!",
                        __func__, __LINE__, phy->inst);
 
+               /* Wall charger needs time before setting D+/D- */
+               mdelay(25);
+
                switch (max_voltage) {
                case TEGRA_USB_QC2_9V:
                        /* Set the input voltage to 9V */
@@ -1642,15 +1701,14 @@ static bool utmi_phy_qc2_charger_detect(struct tegra_usb_phy *phy,
 #endif
        }
 
+       /*
+        * If QC2 charger detected do not disable the charger
+        * detection voltage on D- and D+. Doing this will
+        * cause it to move to 5V
+        */
+       if (!status)
+               disable_charger_detection(base);
 
-       DBG("%s(%d) inst:[%d], UTMIP_BAT_CHRG_CFG0 = %08X\n",
-               __func__, __LINE__,
-               phy->inst, readl(base + UTMIP_BAT_CHRG_CFG0));
-       DBG("%s(%d) inst:[%d], UTMIP_MISC_CFG0 = %08X\n",
-               __func__, __LINE__,
-               phy->inst, readl(base + UTMIP_MISC_CFG0));
-
-       disable_charger_detection(base);
        DBG("%s(%d) inst:[%d] DONE Status = %d\n",
                __func__, __LINE__, phy->inst, status);
        return status;
@@ -2414,6 +2472,7 @@ static struct tegra_usb_phy_ops utmi_phy_ops = {
        .post_resume    = utmi_phy_post_resume,
        .charger_detect = utmi_phy_charger_detect,
        .qc2_charger_detect = utmi_phy_qc2_charger_detect,
+       .cdp_charger_detect = cdp_charger_detection,
        .nv_charger_detect = utmi_phy_nv_charger_detect,
        .apple_charger_1000ma_detect = utmi_phy_apple_charger_1000ma_detect,
        .apple_charger_2000ma_detect = utmi_phy_apple_charger_2000ma_detect,
index 27174bd8059528c867ed5afc1f4a22b235331e5e..213c24e19617000a0dca6b0ff65fa00d6497780b 100644 (file)
@@ -67,6 +67,7 @@ struct tegra_usb_phy_ops {
        int (*power_off)(struct tegra_usb_phy *phy);
        int (*power_on)(struct tegra_usb_phy *phy);
        bool (*charger_detect)(struct tegra_usb_phy *phy);
+       bool (*cdp_charger_detect)(struct tegra_usb_phy *phy);
        bool (*qc2_charger_detect)(struct tegra_usb_phy *phy, int max_voltage);
        bool (*nv_charger_detect)(struct tegra_usb_phy *phy);
        bool (*apple_charger_1000ma_detect)(struct tegra_usb_phy *phy);