diff options
| author | Rakesh Bodla <rbodla@nvidia.com> | 2013-02-18 14:17:58 -0800 |
|---|---|---|
| committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:00:18 -0700 |
| commit | 44d0919e5c3fd3b82bc59e33ff2c379e42e17f18 (patch) | |
| tree | ab32cf8f3202759dda70819f75d129e1262fffff /drivers/usb | |
| parent | e5c48c741c83b6d732e9b6b88ec60537d123444c (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.c | 25 | ||||
| -rw-r--r-- | drivers/usb/gadget/tegra_udc.h | 6 | ||||
| -rw-r--r-- | drivers/usb/phy/phy-tegra-usb.c | 11 | ||||
| -rw-r--r-- | drivers/usb/phy/tegra11x_usb_phy.c | 65 | ||||
| -rw-r--r-- | drivers/usb/phy/tegra_usb_phy.h | 1 |
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); }; /** |
