Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af19ab90 authored by Sriharsha Allenki's avatar Sriharsha Allenki
Browse files

usb: dwc3: Fix invalid charger type detection for float



The charger driver on certain platform depends on the
USB to differentiate between a Standard Downstream Port
and a Float charger, so that the case of slow insertion
is taken care of. The USB driver has to set the current
to -ETIMEDOUT for float and a valid value (100mA, 500mA, 900mA)
for SDP so that the charger can differentiate between the two.

Add the support for the same by checking the linkstate
in a second in the case the charger detected is Float
to differentiate between Standard Downstream Port
and a Float charger.

Change-Id: Ibfbf1225543a8d3c097dae8772b0ce5f1bce0205
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent 6a91a7d5
Loading
Loading
Loading
Loading
+47 −3
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@
#include "debug.h"
#include "xhci.h"

#define SDP_CONNECTION_CHECK_TIME 10000 /* in ms */

/* time out to wait for USB cable status notification (in ms)*/
#define SM_INIT_TIMEOUT 30000

@@ -473,6 +475,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;
	struct mutex suspend_resume_mutex;

	enum usb_device_speed override_usb_speed;
@@ -3536,6 +3539,24 @@ static int dwc3_msm_id_notifier(struct notifier_block *nb,
	return NOTIFY_DONE;
}

static void check_for_sdp_connection(struct work_struct *w)
{
	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) {
		mdwc->vbus_active = false;
		dbg_event(0xFF, "Q RW SPD CHK", mdwc->vbus_active);
		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
	}
}

#define DP_PULSE_WIDTH_MSEC 200

static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
@@ -4073,6 +4094,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) {
@@ -4893,20 +4915,36 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
	if (!mdwc->usb_psy)
		return 0;

	chg_type = get_chg_type(mdwc);
	if (chg_type == QTI_POWER_SUPPLY_TYPE_USB_FLOAT) {
		/*
		 * Do not notify charger driver for any current and
		 * bail out if suspend happened with float cable
		 * connected
		 */
		if (mA == 2)
			return 0;

		if (!mA)
			pval.intval = -ETIMEDOUT;
		else
			pval.intval = 1000 * mA;
		goto set_prop;
	}

	/*
	 * Set the valid current only when the device
	 * is connected to a Standard Downstream Port.
	 */
	chg_type = get_chg_type(mdwc);
	if (mdwc->max_power == mA || (chg_type != -ENODEV
				&& chg_type != POWER_SUPPLY_TYPE_USB))
		return 0;

	dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);

	/* Set max current limit in uA */
	pval.intval = 1000 * mA;

set_prop:
	dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
	ret = power_supply_set_property(mdwc->usb_psy,
				POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &pval);
	if (ret) {
@@ -4987,6 +5025,10 @@ static void dwc3_otg_sm_work(struct work_struct *w)
			work = true;
		} else if (test_bit(B_SESS_VLD, &mdwc->inputs)) {
			dev_dbg(mdwc->dev, "b_sess_vld\n");
			if (get_chg_type(mdwc) == QTI_POWER_SUPPLY_TYPE_USB_FLOAT)
				queue_delayed_work(mdwc->dwc3_wq,
						&mdwc->sdp_check,
				msecs_to_jiffies(SDP_CONNECTION_CHECK_TIME));
			/*
			 * Increment pm usage count upon cable connect. Count
			 * is decremented in DRD_STATE_PERIPHERAL state on
@@ -5009,6 +5051,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
				!test_bit(ID, &mdwc->inputs)) {
			dev_dbg(mdwc->dev, "!id || !bsv\n");
			mdwc->drd_state = DRD_STATE_IDLE;
			cancel_delayed_work_sync(&mdwc->sdp_check);
			dwc3_otg_start_peripheral(mdwc, 0);
			/*
			 * Decrement pm usage count upon cable disconnect
@@ -5041,6 +5084,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->drd_state = DRD_STATE_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");
+1 −0
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ int dwc3_gadget_get_link_state(struct dwc3 *dwc)

	return DWC3_DSTS_USBLNKST(reg);
}
EXPORT_SYMBOL(dwc3_gadget_get_link_state);

/**
 * dwc3_gadget_set_link_state - sets usb link to a particular state