USB: msm72k_udc: Add proprietary charger detection support
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). Gadget speed is used to differentiate
between SDP and proprietary charger.
In charger detection work, if the connected charger is not SDP (or) CDP
then re-schedule the work again and if it returns invalid charger, mark
it as proprietary charger.
CRs-Fixed: 377915
Change-Id: I4223c0724c00aea7e755cd07b349c9e597d7960d
Signed-off-by: Chiranjeevi Velempati <cvelempa@codeaurora.org>
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 3e40552..297c183 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -190,6 +190,8 @@
/* max power requested by selected configuration */
unsigned b_max_pow;
unsigned chg_current;
+ unsigned chg_type_retry_cnt;
+ bool proprietary_chg;
struct delayed_work chg_det;
struct delayed_work chg_stop;
struct msm_hsusb_gadget_platform_data *pdata;
@@ -294,11 +296,18 @@
{
if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
return USB_CHG_TYPE__WALLCHARGER;
- else
- return USB_CHG_TYPE__SDP;
+ else {
+ if (ui->gadget.speed == USB_SPEED_LOW ||
+ ui->gadget.speed == USB_SPEED_FULL ||
+ ui->gadget.speed == USB_SPEED_HIGH)
+ return USB_CHG_TYPE__SDP;
+ else
+ return USB_CHG_TYPE__INVALID;
+ }
}
#define USB_WALLCHARGER_CHG_CURRENT 1800
+#define USB_PROPRIETARY_CHG_CURRENT 500
static int usb_get_max_power(struct usb_info *ui)
{
struct msm_otg *otg = to_msm_otg(ui->xceiv);
@@ -321,8 +330,10 @@
if (temp == USB_CHG_TYPE__INVALID)
return -ENODEV;
- if (temp == USB_CHG_TYPE__WALLCHARGER)
+ if (temp == USB_CHG_TYPE__WALLCHARGER && !ui->proprietary_chg)
return USB_WALLCHARGER_CHG_CURRENT;
+ else
+ return USB_PROPRIETARY_CHG_CURRENT;
if (suspended || !configured)
return 0;
@@ -428,6 +439,17 @@
}
temp = usb_get_chg_type(ui);
+ if (temp != USB_CHG_TYPE__WALLCHARGER && temp != USB_CHG_TYPE__SDP
+ && !ui->chg_type_retry_cnt) {
+ schedule_delayed_work(&ui->chg_det, USB_CHG_DET_DELAY);
+ ui->chg_type_retry_cnt++;
+ spin_unlock_irqrestore(&ui->lock, flags);
+ return;
+ }
+ if (temp == USB_CHG_TYPE__INVALID) {
+ temp = USB_CHG_TYPE__WALLCHARGER;
+ ui->proprietary_chg = true;
+ }
spin_unlock_irqrestore(&ui->lock, flags);
atomic_set(&otg->chg_type, temp);
@@ -1737,6 +1759,8 @@
ui->gadget.speed = USB_SPEED_UNKNOWN;
ui->usb_state = USB_STATE_NOTATTACHED;
ui->flags |= USB_FLAG_VBUS_OFFLINE;
+ ui->chg_type_retry_cnt = 0;
+ ui->proprietary_chg = false;
}
if (in_interrupt()) {
schedule_work(&ui->work);