Loading drivers/usb/dwc3/dwc3-msm.c +46 −3 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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> Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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")) { Loading @@ -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) { Loading @@ -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. * Loading drivers/usb/phy/phy-msm-qusb-v2.c +72 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading include/linux/usb/dwc3-msm.h +8 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/usb/dwc3/dwc3-msm.c +46 −3 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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> Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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")) { Loading @@ -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) { Loading @@ -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. * Loading
drivers/usb/phy/phy-msm-qusb-v2.c +72 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading
include/linux/usb/dwc3-msm.h +8 −0 Original line number Diff line number Diff line Loading @@ -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