summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorRakesh Bodla <rbodla@nvidia.com>2013-02-18 14:17:58 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:00:18 -0700
commit44d0919e5c3fd3b82bc59e33ff2c379e42e17f18 (patch)
treeab32cf8f3202759dda70819f75d129e1262fffff /drivers/usb
parente5c48c741c83b6d732e9b6b88ec60537d123444c (diff)
usb: gadget: tegra: add NV charger detection
Adding the support to detect NV charger and set current limit to withdraw as 2.0amps. Bug 1193528 Reviewed-on: http://git-master/r/192055 (cherry picked from commit bb144cc9933df39cf88a68e256e93e1529922ffa) Change-Id: I32c10817bf21b226fcefdc9409d2c1405251ccbd Signed-off-by: Rakesh Bodla <rbodla@nvidia.com> Reviewed-on: http://git-master/r/196703 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/tegra_udc.c25
-rw-r--r--drivers/usb/gadget/tegra_udc.h6
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c11
-rw-r--r--drivers/usb/phy/tegra11x_usb_phy.c65
-rw-r--r--drivers/usb/phy/tegra_usb_phy.h1
5 files changed, 96 insertions, 12 deletions
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c
index 9e6b9a3448b2..6d2509e36af1 100644
--- a/drivers/usb/gadget/tegra_udc.c
+++ b/drivers/usb/gadget/tegra_udc.c
@@ -1320,6 +1320,10 @@ static int tegra_usb_set_charging_current(struct tegra_udc *udc)
pr_debug("detected CDP port(1A USB port)");
max_ua = USB_CHARGING_CDP_CURRENT_LIMIT_UA;
break;
+ case CONNECT_TYPE_NV_CHARGER:
+ pr_debug("detected NV charging port");
+ max_ua = USB_CHARGING_NV_CHARGER_CURRENT_LIMIT_UA;
+ break;
case CONNECT_TYPE_NON_STANDARD_CHARGER:
pr_debug("detected non-standard charging port");
max_ua = USB_CHARGING_NON_STANDARD_CHARGER_CURRENT_LIMIT_UA;
@@ -1408,15 +1412,18 @@ static int tegra_vbus_session(struct usb_gadget *gadget, int is_active)
if (tegra_usb_phy_charger_detected(udc->phy)) {
tegra_detect_charging_type_is_cdp_or_dcp(udc);
} else {
- udc->connect_type = CONNECT_TYPE_SDP;
- /*
- * Schedule work to wait for 1000 msec and check for
- * a non-standard charger if setup packet is not
- * received.
- */
- schedule_delayed_work(&udc->non_std_charger_work,
- msecs_to_jiffies(
- USB_CHARGER_DETECTION_WAIT_TIME_MS));
+ if (tegra_usb_phy_nv_charger_detected(udc->phy)) {
+ udc->connect_type = CONNECT_TYPE_NV_CHARGER;
+ } else {
+ udc->connect_type = CONNECT_TYPE_SDP;
+ /* Schedule work to wait for 4000 msec and check
+ * for a non-standard charger if setup packet is
+ * not received.
+ */
+ schedule_delayed_work(&udc->non_std_charger_work
+ , msecs_to_jiffies(
+ USB_CHARGER_DETECTION_WAIT_TIME_MS));
+ }
}
/* start the controller */
dr_controller_run(udc);
diff --git a/drivers/usb/gadget/tegra_udc.h b/drivers/usb/gadget/tegra_udc.h
index 465c1385627b..efb4ca65f029 100644
--- a/drivers/usb/gadget/tegra_udc.h
+++ b/drivers/usb/gadget/tegra_udc.h
@@ -41,10 +41,11 @@
#define USB_CHARGING_DCP_CURRENT_LIMIT_UA 1800000
#define USB_CHARGING_CDP_CURRENT_LIMIT_UA 1500000
#define USB_CHARGING_SDP_CURRENT_LIMIT_UA 100000
+#define USB_CHARGING_NV_CHARGER_CURRENT_LIMIT_UA 2000000
#define USB_CHARGING_NON_STANDARD_CHARGER_CURRENT_LIMIT_UA 1800000
- /* 1 sec wait time for charger detection after vbus is detected */
-#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000
+ /* 4 sec wait time for charger detection after vbus is detected */
+#define USB_CHARGER_DETECTION_WAIT_TIME_MS 4000
#define BOOST_TRIGGER_SIZE 4096
#define UDC_RESET_TIMEOUT_MS 1000
@@ -413,6 +414,7 @@ enum tegra_connect_type {
CONNECT_TYPE_SDP,
CONNECT_TYPE_DCP,
CONNECT_TYPE_CDP,
+ CONNECT_TYPE_NV_CHARGER,
CONNECT_TYPE_NON_STANDARD_CHARGER
};
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index 81fdffef1028..58a9321f704f 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -572,6 +572,17 @@ bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy)
return status;
}
+bool tegra_usb_phy_nv_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->nv_charger_detect)
+ status = phy->ops->nv_charger_detect(phy);
+
+ return status;
+}
+
bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy)
{
if (!phy->hw_accessible)
diff --git a/drivers/usb/phy/tegra11x_usb_phy.c b/drivers/usb/phy/tegra11x_usb_phy.c
index 29e31b98eca1..046a8530f0b5 100644
--- a/drivers/usb/phy/tegra11x_usb_phy.c
+++ b/drivers/usb/phy/tegra11x_usb_phy.c
@@ -190,10 +190,17 @@
#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
-#define FORCE_PULLDN_DM (1 << 8)
+#define DISABLE_PULLUP_DP (1 << 15)
+#define DISABLE_PULLUP_DM (1 << 14)
+#define DISABLE_PULLDN_DP (1 << 13)
+#define DISABLE_PULLDN_DM (1 << 12)
+#define FORCE_PULLUP_DP (1 << 11)
+#define FORCE_PULLUP_DM (1 << 10)
#define FORCE_PULLDN_DP (1 << 9)
+#define FORCE_PULLDN_DM (1 << 8)
#define COMB_TERMS (1 << 0)
#define ALWAYS_FREE_RUNNING_TERMS (1 << 1)
+#define MASK_ALL_PULLUP_PULLDOWN (0xff << 8)
#define UTMIP_SPARE_CFG0 0x834
#define FUSE_SETUP_SEL (1 << 3)
@@ -1378,6 +1385,61 @@ static bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
return status;
}
+static bool utmi_phy_nv_charger_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ bool status;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* Turn off all terminations so we see DPDN states clearly,
+ and only leave on DM pulldown */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~MASK_ALL_PULLUP_PULLDOWN;
+ val |= (DISABLE_PULLUP_DP | DISABLE_PULLUP_DM
+ | FORCE_PULLDN_DP | DISABLE_PULLDN_DM);
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ udelay(100);
+
+ val = readl(base + USB_PORTSC);
+ status = (USB_PORTSC_LINE_STATE(val) == 0);
+
+ /* Turn off all terminations except for DP pullup */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~MASK_ALL_PULLUP_PULLDOWN;
+ val |= (FORCE_PULLUP_DP | DISABLE_PULLUP_DM
+ | DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ udelay(100);
+
+ val = readl(base + USB_PORTSC);
+ if (status & (USB_PORTSC_LINE_STATE(val) == 0x3)) {
+ status = false;
+ } else {
+ status = false;
+
+ /* Check for NV charger DISABLE all terminations */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~MASK_ALL_PULLUP_PULLDOWN;
+ val |= (DISABLE_PULLUP_DP | DISABLE_PULLUP_DM
+ | DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ val = readl(base + USB_PORTSC);
+ if (USB_PORTSC_LINE_STATE(val) == 0x3)
+ status = true;
+ }
+
+ /* Restore standard termination by hardware. */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~MASK_ALL_PULLUP_PULLDOWN;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ return status;
+}
+
static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
{
void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -2558,6 +2620,7 @@ static struct tegra_usb_phy_ops utmi_phy_ops = {
.pre_resume = utmi_phy_pre_resume,
.resume = utmi_phy_resume,
.charger_detect = utmi_phy_charger_detect,
+ .nv_charger_detect = utmi_phy_nv_charger_detect,
};
static struct tegra_usb_phy_ops uhsic_phy_ops = {
diff --git a/drivers/usb/phy/tegra_usb_phy.h b/drivers/usb/phy/tegra_usb_phy.h
index ef7fd79a08b1..f4058b58e860 100644
--- a/drivers/usb/phy/tegra_usb_phy.h
+++ b/drivers/usb/phy/tegra_usb_phy.h
@@ -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 (*nv_charger_detect)(struct tegra_usb_phy *phy);
};
/**