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

Commit cbd5b7fa authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: dwc3: Drive a pulse on DP on CDP detection"

parents c9879ecd 119baad7
Loading
Loading
Loading
Loading
+46 −3
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/dmapool.h>
#include <linux/pm_runtime.h>
#include <linux/ratelimit.h>
#include <linux/iio/consumer.h>
#include <linux/interrupt.h>
#include <linux/iommu.h>
#include <linux/ioport.h>
@@ -33,6 +34,7 @@
#include <linux/pm_wakeup.h>
#include <linux/pm_qos.h>
#include <linux/power_supply.h>
#include <linux/qti_power_supply.h>
#include <linux/cdev.h>
#include <linux/completion.h>
#include <linux/interconnect.h>
@@ -441,6 +443,7 @@ struct dwc3_msm {
	enum bus_vote		override_bus_vote;
	struct icc_path		*icc_paths[3];
	struct power_supply	*usb_psy;
	struct iio_channel	*chg_type;
	struct work_struct	vbus_draw_work;
	bool			in_host_mode;
	bool			in_device_mode;
@@ -3396,6 +3399,7 @@ static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data)
}

static void dwc3_otg_sm_work(struct work_struct *w);
static int get_chg_type(struct dwc3_msm *mdwc);

static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc)
{
@@ -3532,6 +3536,7 @@ static int dwc3_msm_id_notifier(struct notifier_block *nb,
	return NOTIFY_DONE;
}

#define DP_PULSE_WIDTH_MSEC 200

static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
	unsigned long event, void *ptr)
@@ -3566,6 +3571,16 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
		mdwc->vbus_active = event;
	}

	/*
	 * Drive a pulse on DP to ensure proper CDP detection
	 * and only when the vbus connect event is a valid one.
	 */
	if (get_chg_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP &&
			mdwc->vbus_active && !mdwc->check_eud_state) {
		dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n");
		usb_phy_drive_dp_pulse(mdwc->hs_phy, DP_PULSE_WIDTH_MSEC);
	}

	mdwc->ext_idx = enb->idx;
	if (dwc->dr_mode == USB_DR_MODE_OTG && !mdwc->in_restart)
		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
@@ -4839,10 +4854,32 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
	return 0;
}

static int get_chg_type(struct dwc3_msm *mdwc)
{
	int ret, value;

	if (!mdwc->chg_type) {
		mdwc->chg_type = devm_iio_channel_get(mdwc->dev, "chg_type");
		if (IS_ERR_OR_NULL(mdwc->chg_type)) {
			dev_dbg(mdwc->dev, "unable to get iio channel\n");
			mdwc->chg_type = NULL;
			return -ENODEV;
		}
	}

	ret = iio_read_channel_processed(mdwc->chg_type, &value);
	if (ret < 0) {
		dev_err(mdwc->dev, "failed to get charger type\n");
		return ret;
	}

	return value;
}

static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
{
	union power_supply_propval pval = {0};
	int ret;
	int ret, chg_type;

	if (!mdwc->usb_psy && of_property_read_bool(mdwc->dev->of_node,
					"qcom,usb-charger")) {
@@ -4856,13 +4893,20 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
	if (!mdwc->usb_psy)
		return 0;

	if (mdwc->max_power == mA)
	/*
	 * 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;

	ret = power_supply_set_property(mdwc->usb_psy,
				POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &pval);
	if (ret) {
@@ -4874,7 +4918,6 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
	return 0;
}


/**
 * dwc3_otg_sm_work - workqueue function.
 *
+72 −0
Original line number Diff line number Diff line
@@ -461,6 +461,25 @@ static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
	}
}

static void msm_usb_write_readback(void __iomem *base, u32 offset,
					const u32 mask, u32 val)
{
	u32 write_val, tmp = readl_relaxed(base + offset);

	tmp &= ~mask;		/* retain other bits */
	write_val = tmp | val;

	writel_relaxed(write_val, base + offset);

	/* Read back to see if val was written */
	tmp = readl_relaxed(base + offset);
	tmp &= mask;		/* clear other bits */

	if (tmp != val)
		pr_err("%s: write: %x to QSCRATCH: %x FAILED\n",
			__func__, val, offset);
}

static void qusb_phy_reset(struct qusb_phy *qphy)
{
	int ret;
@@ -815,6 +834,59 @@ static int qusb_phy_notify_disconnect(struct usb_phy *phy,
	return 0;
}

void usb_phy_drive_dp_pulse(void *phy, unsigned int interval_ms)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
	int ret;

	ret = qusb_phy_enable_power(qphy);
	if (ret < 0) {
		dev_dbg(qphy->phy.dev,
			"dpdm regulator enable failed:%d\n", ret);
		return;
	}
	qusb_phy_enable_clocks(qphy, true);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[PWR_CTRL1],
				PWR_CTRL1_POWR_DOWN, 0x00);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[DEBUG_CTRL4],
				FORCED_UTMI_DPPULLDOWN, 0x00);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[DEBUG_CTRL4],
				FORCED_UTMI_DMPULLDOWN,
				FORCED_UTMI_DMPULLDOWN);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[DEBUG_CTRL3],
				0xd1, 0xd1);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[PWR_CTRL1],
				CLAMP_N_EN, CLAMP_N_EN);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[INTR_CTRL],
				DPSE_INTR_HIGH_SEL, 0x00);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[INTR_CTRL],
				DPSE_INTR_EN, DPSE_INTR_EN);

	msleep(interval_ms);

	msm_usb_write_readback(qphy->base, qphy->phy_reg[INTR_CTRL],
				DPSE_INTR_HIGH_SEL |
				DPSE_INTR_EN, 0x00);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[DEBUG_CTRL3],
				0xd1, 0x00);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[DEBUG_CTRL4],
				FORCED_UTMI_DPPULLDOWN |
				FORCED_UTMI_DMPULLDOWN, 0x00);
	msm_usb_write_readback(qphy->base, qphy->phy_reg[PWR_CTRL1],
				PWR_CTRL1_POWR_DOWN |
				CLAMP_N_EN, 0x00);

	msleep(20);

	qusb_phy_enable_clocks(qphy, false);
	ret = qusb_phy_disable_power(qphy);
	if (ret < 0) {
		dev_dbg(qphy->phy.dev,
			"dpdm regulator disable failed:%d\n", ret);
	}
}
EXPORT_SYMBOL(usb_phy_drive_dp_pulse);

static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev)
{
	int ret = 0;
+8 −0
Original line number Diff line number Diff line
@@ -111,6 +111,14 @@ struct gsi_channel_info {
	struct usb_gsi_request *ch_req;
};

#if IS_ENABLED(CONFIG_MSM_QUSB_PHY)
extern void usb_phy_drive_dp_pulse(void *phy,
					unsigned int interval_ms);
#else
static inline void usb_phy_drive_dp_pulse(void *phy, unsigned int interval_ms)
{ }
#endif

#if IS_ENABLED(CONFIG_USB_DWC3_MSM)
struct usb_ep *usb_ep_autoconfig_by_name(struct usb_gadget *gadget,
		struct usb_endpoint_descriptor *desc, const char *ep_name);