From a1e331dcbf391628afa90d6e9fbce12982d8950a Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Thu, 7 Feb 2013 14:55:05 +0530 Subject: [PATCH] usb: dwc3-msm: Add support for proprietary charger detection Proprietary chargers pull D+/- to specific voltages between 2.0-3.3V (VLGC) for identification. The DM voltage may not exceed VLGC due to pull-down resistor. Hence a proprietary charger is detected as a Standard downstream port (SDP). Read line state to distinguish between SDP and proprietary charger. The DP voltage would exceed VLGC for proprietary chargers. CRs-fixed: 383075 Change-Id: Ic9afbdd0996a4c1c7a2af76cd99182d8ae5f3b68 Signed-off-by: Manu Gautam --- drivers/usb/dwc3/dwc3-msm.c | 32 ++++++++++++++++++++++++++------ drivers/usb/dwc3/dwc3_otg.c | 4 +++- drivers/usb/dwc3/dwc3_otg.h | 3 +++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index d659b261d14..ac15ff11083 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1326,6 +1326,17 @@ static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc) dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x34); } +static bool dwc3_chg_det_check_linestate(struct dwc3_msm *mdwc) +{ + u32 chg_det; + bool ret = false; + + chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG); + ret = chg_det & (3 << 8); + + return ret; +} + static bool dwc3_chg_det_check_output(struct dwc3_msm *mdwc) { u32 chg_det; @@ -1391,9 +1402,10 @@ static void dwc3_chg_block_reset(struct dwc3_msm *mdwc) static const char *chg_to_string(enum dwc3_chg_type chg_type) { switch (chg_type) { - case USB_SDP_CHARGER: return "USB_SDP_CHARGER"; - case USB_DCP_CHARGER: return "USB_DCP_CHARGER"; - case USB_CDP_CHARGER: return "USB_CDP_CHARGER"; + case DWC3_SDP_CHARGER: return "USB_SDP_CHARGER"; + case DWC3_DCP_CHARGER: return "USB_DCP_CHARGER"; + case DWC3_CDP_CHARGER: return "USB_CDP_CHARGER"; + case DWC3_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER"; default: return "INVALID_CHARGER"; } } @@ -1423,6 +1435,14 @@ static void dwc3_chg_detect_work(struct work_struct *w) tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES; if (is_dcd || tmout) { dwc3_chg_disable_dcd(mdwc); + if (dwc3_chg_det_check_linestate(mdwc)) { + dev_dbg(mdwc->dev, "proprietary charger\n"); + mdwc->charger.chg_type = + DWC3_PROPRIETARY_CHARGER; + mdwc->chg_state = USB_CHG_STATE_DETECTED; + delay = 0; + break; + } dwc3_chg_enable_primary_det(mdwc); delay = DWC3_CHG_PRIMARY_DET_TIME; mdwc->chg_state = USB_CHG_STATE_DCD_DONE; @@ -1437,7 +1457,7 @@ static void dwc3_chg_detect_work(struct work_struct *w) delay = DWC3_CHG_SECONDARY_DET_TIME; mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE; } else { - mdwc->charger.chg_type = USB_SDP_CHARGER; + mdwc->charger.chg_type = DWC3_SDP_CHARGER; mdwc->chg_state = USB_CHG_STATE_DETECTED; delay = 0; } @@ -1445,9 +1465,9 @@ static void dwc3_chg_detect_work(struct work_struct *w) case USB_CHG_STATE_PRIMARY_DONE: vout = dwc3_chg_det_check_output(mdwc); if (vout) - mdwc->charger.chg_type = USB_DCP_CHARGER; + mdwc->charger.chg_type = DWC3_DCP_CHARGER; else - mdwc->charger.chg_type = USB_CDP_CHARGER; + mdwc->charger.chg_type = DWC3_CDP_CHARGER; mdwc->chg_state = USB_CHG_STATE_SECONDARY_DONE; /* fall through */ case USB_CHG_STATE_SECONDARY_DONE: diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c index 8bdaa5d03df..01fad7613c7 100644 --- a/drivers/usb/dwc3/dwc3_otg.c +++ b/drivers/usb/dwc3/dwc3_otg.c @@ -482,7 +482,8 @@ static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA) power_supply_type = POWER_SUPPLY_TYPE_USB; else if (dotg->charger->chg_type == DWC3_CDP_CHARGER) power_supply_type = POWER_SUPPLY_TYPE_USB_CDP; - else if (dotg->charger->chg_type == DWC3_DCP_CHARGER) + else if (dotg->charger->chg_type == DWC3_DCP_CHARGER || + dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER) power_supply_type = POWER_SUPPLY_TYPE_USB_DCP; else power_supply_type = POWER_SUPPLY_TYPE_BATTERY; @@ -685,6 +686,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) /* Has charger been detected? If no detect it */ switch (charger->chg_type) { case DWC3_DCP_CHARGER: + case DWC3_PROPRIETARY_CHARGER: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h index 07d641186a3..d3b1b4a96ec 100644 --- a/drivers/usb/dwc3/dwc3_otg.h +++ b/drivers/usb/dwc3/dwc3_otg.h @@ -61,12 +61,15 @@ struct dwc3_otg { * DWC3_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger). * DWC3_CDP_CHARGER Charging downstream port. Enumeration can happen and * IDEV_CHG_MAX can be drawn irrespective of USB state. + * DWC3_PROPRIETARY_CHARGER A proprietary charger pull DP and DM to specific + * voltages between 2.0-3.3v for identification. */ enum dwc3_chg_type { DWC3_INVALID_CHARGER = 0, DWC3_SDP_CHARGER, DWC3_DCP_CHARGER, DWC3_CDP_CHARGER, + DWC3_PROPRIETARY_CHARGER, }; struct dwc3_charger {