Loading drivers/usb/dwc3/dwc3-msm.c +76 −29 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ #define PWR_EVNT_POWERDOWN_OUT_P3_MASK BIT(3) #define PWR_EVNT_LPM_IN_L2_MASK BIT(4) #define PWR_EVNT_LPM_OUT_L2_MASK BIT(5) #define PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK BIT(12) #define PWR_EVNT_LPM_OUT_L1_MASK BIT(13) /* QSCRATCH_GENERAL_CFG register bit offset */ Loading Loading @@ -247,6 +248,7 @@ struct dwc3_msm { bool suspend; bool use_pdc_interrupts; enum dwc3_id_state id_state; bool use_pwr_event_for_wakeup; unsigned long lpm_flags; #define MDWC3_SS_PHY_SUSPEND BIT(0) #define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY BIT(1) Loading Loading @@ -2207,6 +2209,27 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc, } } static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on) { u32 irq_mask, irq_stat; irq_stat = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); /* clear pending interrupts */ dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, irq_stat); irq_mask = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG); if (on) irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK | PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); else irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK | PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG, irq_mask); } static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) { int ret = 0; Loading Loading @@ -2246,6 +2269,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); struct dwc3_event_buffer *evt; struct usb_irq *uirq; bool can_suspend_ssphy, no_active_ss; mutex_lock(&mdwc->suspend_resume_mutex); if (atomic_read(&dwc->in_lpm)) { Loading Loading @@ -2321,8 +2345,20 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) /* Suspend HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 1); /* * Synopsys Superspeed PHY does not support ss_phy_irq, so to detect * any wakeup events in host mode PHY cannot be suspended. * This Superspeed PHY can be suspended only in the following cases: * 1. The core is not in host mode * 2. A Highspeed device is connected but not a Superspeed device */ no_active_ss = (!mdwc->in_host_mode) || (mdwc->in_host_mode && ((mdwc->hs_phy->flags & (PHY_HSFS_MODE | PHY_LS_MODE)) && !dwc3_msm_is_superspeed(mdwc))); can_suspend_ssphy = dwc->maximum_speed >= USB_SPEED_SUPER && (!mdwc->use_pwr_event_for_wakeup || no_active_ss); /* Suspend SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER) { if (can_suspend_ssphy) { if (mdwc->in_host_mode) { u32 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); Loading @@ -2334,6 +2370,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; usb_phy_set_suspend(mdwc->ss_phy, 1); mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; } else if (mdwc->use_pwr_event_for_wakeup) { dwc3_msm_set_ss_pwr_events(mdwc, true); enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); } /* make sure above writes are completed before turning off clocks */ Loading Loading @@ -2489,6 +2528,16 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) if (mdwc->bus_aggr_clk) clk_prepare_enable(mdwc->bus_aggr_clk); /* * Disable any wakeup events that were enabled if pwr_event_irq * is used as wakeup interrupt. */ if (mdwc->use_pwr_event_for_wakeup && !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) { disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); dwc3_msm_set_ss_pwr_events(mdwc, false); } /* Resume SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { Loading Loading @@ -3005,17 +3054,6 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc) struct extcon_dev *edev; int idx, extcon_cnt, ret = 0; bool check_vbus_state, check_id_state, phandle_found = false; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); if (!of_property_read_bool(node, "extcon")) { if (dwc3_is_otg_or_drd(dwc)) { dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", __func__); mdwc->vbus_active = true; queue_work(mdwc->dwc3_wq, &mdwc->resume_work); } return 0; } extcon_cnt = of_count_phandle_with_args(node, "extcon", NULL); if (extcon_cnt < 0) { Loading Loading @@ -3309,7 +3347,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) struct dwc3_msm *mdwc; struct dwc3 *dwc; struct resource *res; bool host_mode; int ret = 0, size = 0, i; u32 val; unsigned long irq_type; Loading Loading @@ -3553,6 +3590,14 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } /* * On platforms with SS PHY that do not support ss_phy_irq for wakeup * events, use pwr_event_irq for wakeup events in superspeed mode. */ mdwc->use_pwr_event_for_wakeup = dwc->maximum_speed >= USB_SPEED_SUPER && !mdwc->wakeup_irq[SS_PHY_IRQ].irq; /* IOMMU will be reattached upon each resume/connect */ if (mdwc->iommu_map) __depr_arm_iommu_detach_device(mdwc->dev); Loading Loading @@ -3580,24 +3625,29 @@ static int dwc3_msm_probe(struct platform_device *pdev) mutex_init(&mdwc->suspend_resume_mutex); if (of_property_read_bool(node, "extcon")) { ret = dwc3_msm_extcon_register(mdwc); if (ret) goto put_dwc3; } else { if (dwc3_is_otg_or_drd(dwc) || dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", __func__); mdwc->vbus_active = true; } else if (dwc->dr_mode == USB_DR_MODE_HOST) { dev_dbg(mdwc->dev, "DWC3 in host only mode\n"); mdwc->id_state = DWC3_ID_GROUND; } schedule_delayed_work(&mdwc->sm_work, 0); dwc3_ext_event_notify(mdwc); } device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode); device_create_file(&pdev->dev, &dev_attr_bus_vote); host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (host_mode) { dev_dbg(&pdev->dev, "DWC3 in host only mode\n"); mdwc->id_state = DWC3_ID_GROUND; dwc3_ext_event_notify(mdwc); } return 0; put_dwc3: Loading Loading @@ -4343,7 +4393,6 @@ static void dwc3_otg_sm_work(struct work_struct *w) #ifdef CONFIG_PM_SLEEP static int dwc3_msm_pm_suspend(struct device *dev) { int ret = 0; struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); Loading @@ -4356,11 +4405,9 @@ static int dwc3_msm_pm_suspend(struct device *dev) return -EBUSY; } ret = dwc3_msm_suspend(mdwc); if (!ret) atomic_set(&mdwc->pm_suspended, 1); return ret; return 0; } static int dwc3_msm_pm_resume(struct device *dev) Loading Loading
drivers/usb/dwc3/dwc3-msm.c +76 −29 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ #define PWR_EVNT_POWERDOWN_OUT_P3_MASK BIT(3) #define PWR_EVNT_LPM_IN_L2_MASK BIT(4) #define PWR_EVNT_LPM_OUT_L2_MASK BIT(5) #define PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK BIT(12) #define PWR_EVNT_LPM_OUT_L1_MASK BIT(13) /* QSCRATCH_GENERAL_CFG register bit offset */ Loading Loading @@ -247,6 +248,7 @@ struct dwc3_msm { bool suspend; bool use_pdc_interrupts; enum dwc3_id_state id_state; bool use_pwr_event_for_wakeup; unsigned long lpm_flags; #define MDWC3_SS_PHY_SUSPEND BIT(0) #define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY BIT(1) Loading Loading @@ -2207,6 +2209,27 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc, } } static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on) { u32 irq_mask, irq_stat; irq_stat = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); /* clear pending interrupts */ dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, irq_stat); irq_mask = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG); if (on) irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK | PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); else irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK | PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG, irq_mask); } static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) { int ret = 0; Loading Loading @@ -2246,6 +2269,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); struct dwc3_event_buffer *evt; struct usb_irq *uirq; bool can_suspend_ssphy, no_active_ss; mutex_lock(&mdwc->suspend_resume_mutex); if (atomic_read(&dwc->in_lpm)) { Loading Loading @@ -2321,8 +2345,20 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) /* Suspend HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 1); /* * Synopsys Superspeed PHY does not support ss_phy_irq, so to detect * any wakeup events in host mode PHY cannot be suspended. * This Superspeed PHY can be suspended only in the following cases: * 1. The core is not in host mode * 2. A Highspeed device is connected but not a Superspeed device */ no_active_ss = (!mdwc->in_host_mode) || (mdwc->in_host_mode && ((mdwc->hs_phy->flags & (PHY_HSFS_MODE | PHY_LS_MODE)) && !dwc3_msm_is_superspeed(mdwc))); can_suspend_ssphy = dwc->maximum_speed >= USB_SPEED_SUPER && (!mdwc->use_pwr_event_for_wakeup || no_active_ss); /* Suspend SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER) { if (can_suspend_ssphy) { if (mdwc->in_host_mode) { u32 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); Loading @@ -2334,6 +2370,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; usb_phy_set_suspend(mdwc->ss_phy, 1); mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; } else if (mdwc->use_pwr_event_for_wakeup) { dwc3_msm_set_ss_pwr_events(mdwc, true); enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); } /* make sure above writes are completed before turning off clocks */ Loading Loading @@ -2489,6 +2528,16 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) if (mdwc->bus_aggr_clk) clk_prepare_enable(mdwc->bus_aggr_clk); /* * Disable any wakeup events that were enabled if pwr_event_irq * is used as wakeup interrupt. */ if (mdwc->use_pwr_event_for_wakeup && !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) { disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); dwc3_msm_set_ss_pwr_events(mdwc, false); } /* Resume SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { Loading Loading @@ -3005,17 +3054,6 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc) struct extcon_dev *edev; int idx, extcon_cnt, ret = 0; bool check_vbus_state, check_id_state, phandle_found = false; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); if (!of_property_read_bool(node, "extcon")) { if (dwc3_is_otg_or_drd(dwc)) { dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", __func__); mdwc->vbus_active = true; queue_work(mdwc->dwc3_wq, &mdwc->resume_work); } return 0; } extcon_cnt = of_count_phandle_with_args(node, "extcon", NULL); if (extcon_cnt < 0) { Loading Loading @@ -3309,7 +3347,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) struct dwc3_msm *mdwc; struct dwc3 *dwc; struct resource *res; bool host_mode; int ret = 0, size = 0, i; u32 val; unsigned long irq_type; Loading Loading @@ -3553,6 +3590,14 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } /* * On platforms with SS PHY that do not support ss_phy_irq for wakeup * events, use pwr_event_irq for wakeup events in superspeed mode. */ mdwc->use_pwr_event_for_wakeup = dwc->maximum_speed >= USB_SPEED_SUPER && !mdwc->wakeup_irq[SS_PHY_IRQ].irq; /* IOMMU will be reattached upon each resume/connect */ if (mdwc->iommu_map) __depr_arm_iommu_detach_device(mdwc->dev); Loading Loading @@ -3580,24 +3625,29 @@ static int dwc3_msm_probe(struct platform_device *pdev) mutex_init(&mdwc->suspend_resume_mutex); if (of_property_read_bool(node, "extcon")) { ret = dwc3_msm_extcon_register(mdwc); if (ret) goto put_dwc3; } else { if (dwc3_is_otg_or_drd(dwc) || dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", __func__); mdwc->vbus_active = true; } else if (dwc->dr_mode == USB_DR_MODE_HOST) { dev_dbg(mdwc->dev, "DWC3 in host only mode\n"); mdwc->id_state = DWC3_ID_GROUND; } schedule_delayed_work(&mdwc->sm_work, 0); dwc3_ext_event_notify(mdwc); } device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode); device_create_file(&pdev->dev, &dev_attr_bus_vote); host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (host_mode) { dev_dbg(&pdev->dev, "DWC3 in host only mode\n"); mdwc->id_state = DWC3_ID_GROUND; dwc3_ext_event_notify(mdwc); } return 0; put_dwc3: Loading Loading @@ -4343,7 +4393,6 @@ static void dwc3_otg_sm_work(struct work_struct *w) #ifdef CONFIG_PM_SLEEP static int dwc3_msm_pm_suspend(struct device *dev) { int ret = 0; struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); Loading @@ -4356,11 +4405,9 @@ static int dwc3_msm_pm_suspend(struct device *dev) return -EBUSY; } ret = dwc3_msm_suspend(mdwc); if (!ret) atomic_set(&mdwc->pm_suspended, 1); return ret; return 0; } static int dwc3_msm_pm_resume(struct device *dev) Loading