usb: dwc3-msm: Add support to handle floating D+/D- lines

There is a possibility of PMI detecting SDP as a floating charger
when connected to a PC. Workaround this issue by starting peripheral
stack for floating charger as well. After 10 sec check for USB device
enumeration using gadget USB state. If device is indeed connected to
SDP gadget usb state will be USB_STATE_DEFAULT or higher. This change
also helps to start peripheral stack in super speed usb compliance mode
when D+ and D- lines are floating.

Change-Id: Ia6dc668c549dca35e3273ece9a43be52c25d40ad
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
This commit is contained in:
Hemant Kumar 2017-07-12 18:11:25 -07:00
parent 4bf2e9f455
commit ba4eab879d

View file

@ -54,6 +54,8 @@
#include "debug.h"
#include "xhci.h"
#define SDP_CONNETION_CHECK_TIME 10000 /* in ms */
/* time out to wait for USB cable status notification (in ms)*/
#define SM_INIT_TIMEOUT 30000
@ -227,6 +229,7 @@ struct dwc3_msm {
int pm_qos_latency;
struct pm_qos_request pm_qos_req_dma;
struct delayed_work perf_vote_work;
struct delayed_work sdp_check;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@ -2625,6 +2628,42 @@ done:
return NOTIFY_DONE;
}
static void check_for_sdp_connection(struct work_struct *w)
{
int ret;
union power_supply_propval pval = {0};
struct dwc3_msm *mdwc =
container_of(w, struct dwc3_msm, sdp_check.work);
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
if (!mdwc->vbus_active)
return;
/* floating D+/D- lines detected */
if (dwc->gadget.state < USB_STATE_DEFAULT &&
dwc3_gadget_get_link_state(dwc) != DWC3_LINK_STATE_CMPLY) {
if (!mdwc->usb_psy) {
mdwc->usb_psy = power_supply_get_by_name("usb");
if (!mdwc->usb_psy) {
dev_dbg(mdwc->dev,
"Could not get usb power_supply\n");
return;
}
}
pval.intval = -ETIMEDOUT;
ret = power_supply_set_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
if (ret)
dev_dbg(mdwc->dev,
"power supply error when setting property\n");
mdwc->vbus_active = 0;
dbg_event(0xFF, "Q RW SPD CHK", mdwc->vbus_active);
queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
}
}
static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@ -2833,6 +2872,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
INIT_WORK(&mdwc->vbus_draw_work, dwc3_msm_vbus_draw_work);
INIT_DELAYED_WORK(&mdwc->sm_work, dwc3_otg_sm_work);
INIT_DELAYED_WORK(&mdwc->perf_vote_work, msm_dwc3_perf_vote_work);
INIT_DELAYED_WORK(&mdwc->sdp_check, check_for_sdp_connection);
mdwc->dwc3_wq = alloc_ordered_workqueue("dwc3_wq", 0);
if (!mdwc->dwc3_wq) {
@ -3586,28 +3626,38 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
return 0;
}
static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA)
int get_psy_type(struct dwc3_msm *mdwc)
{
union power_supply_propval pval = {0};
int ret;
if (mdwc->charging_disabled)
return 0;
if (mdwc->max_power == mA)
return 0;
return -EINVAL;
if (!mdwc->usb_psy) {
mdwc->usb_psy = power_supply_get_by_name("usb");
if (!mdwc->usb_psy) {
dev_warn(mdwc->dev, "Could not get usb power_supply\n");
dev_err(mdwc->dev, "Could not get usb psy\n");
return -ENODEV;
}
}
power_supply_get_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_REAL_TYPE, &pval);
if (pval.intval != POWER_SUPPLY_TYPE_USB)
power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE,
&pval);
return pval.intval;
}
static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA)
{
union power_supply_propval pval = {0};
int ret, psy_type;
if (mdwc->max_power == mA)
return 0;
psy_type = get_psy_type(mdwc);
if (psy_type != POWER_SUPPLY_TYPE_USB &&
psy_type != POWER_SUPPLY_TYPE_USB_FLOAT)
return 0;
dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
@ -3684,6 +3734,10 @@ static void dwc3_otg_sm_work(struct work_struct *w)
work = 1;
} else if (test_bit(B_SESS_VLD, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "b_sess_vld\n");
if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_FLOAT)
queue_delayed_work(mdwc->dwc3_wq,
&mdwc->sdp_check,
msecs_to_jiffies(SDP_CONNETION_CHECK_TIME));
/*
* Increment pm usage count upon cable connect. Count
* is decremented in OTG_STATE_B_PERIPHERAL state on
@ -3707,6 +3761,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
!test_bit(ID, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "!id || !bsv\n");
mdwc->otg_state = OTG_STATE_B_IDLE;
cancel_delayed_work_sync(&mdwc->sdp_check);
dwc3_otg_start_peripheral(mdwc, 0);
/*
* Decrement pm usage count upon cable disconnect
@ -3739,6 +3794,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
if (!test_bit(B_SESS_VLD, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "BSUSP: !bsv\n");
mdwc->otg_state = OTG_STATE_B_IDLE;
cancel_delayed_work_sync(&mdwc->sdp_check);
dwc3_otg_start_peripheral(mdwc, 0);
} else if (!test_bit(B_SUSPEND, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "BSUSP !susp\n");