mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 12:58:12 -04:00
Merge "usb: dwc3: Drive a pulse on DP on CDP detection"
This commit is contained in:
commit
cbd5b7fafc
3 changed files with 126 additions and 3 deletions
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue