static int wdm_suspend(struct usb_interface *intf, pm_message_t message) { struct wdm_device *desc = usb_get_intfdata(intf); int rv = 0; dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); /* if this is an autosuspend the caller does the locking */ if (!PMSG_IS_AUTO(message)) mutex_lock(&desc->lock); spin_lock_irq(&desc->iuspin); if (PMSG_IS_AUTO(message) && (test_bit(WDM_IN_USE, &desc->flags) || test_bit(WDM_RESPONDING, &desc->flags))) { spin_unlock_irq(&desc->iuspin); rv = -EBUSY; } else { set_bit(WDM_SUSPENDING, &desc->flags); spin_unlock_irq(&desc->iuspin); /* callback submits work - order is essential */ kill_urbs(desc); cancel_work_sync(&desc->rxwork); } if (!PMSG_IS_AUTO(message)) mutex_unlock(&desc->lock); return rv; }
static int btusb_suspend(struct usb_interface *intf, pm_message_t message) { struct btusb_data *data = usb_get_intfdata(intf); BT_DBG("intf %p", intf); if (data->suspend_count++) return 0; spin_lock_irq(&data->txlock); if (!(PMSG_IS_AUTO(message) && data->tx_in_flight)) { set_bit(BTUSB_SUSPENDING, &data->flags); spin_unlock_irq(&data->txlock); } else { spin_unlock_irq(&data->txlock); data->suspend_count--; return -EBUSY; } cancel_work_sync(&data->work); btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); return 0; }
static int acm_suspend(struct usb_interface *intf, pm_message_t message) { struct acm *acm = usb_get_intfdata(intf); int cnt; if (PMSG_IS_AUTO(message)) { int b; spin_lock_irq(&acm->write_lock); b = acm->transmitting; spin_unlock_irq(&acm->write_lock); if (b) return -EBUSY; } spin_lock_irq(&acm->read_lock); spin_lock(&acm->write_lock); cnt = acm->susp_count++; spin_unlock(&acm->write_lock); spin_unlock_irq(&acm->read_lock); if (cnt) return 0; if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) stop_data_traffic(acm); return 0; }
int usbnet_suspend (struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); if (!dev->suspend_count++) { spin_lock_irq(&dev->txq.lock); /* don't autosuspend while transmitting */ if (dev->txq.qlen && PMSG_IS_AUTO(message)) { spin_unlock_irq(&dev->txq.lock); return -EBUSY; } else { set_bit(EVENT_DEV_ASLEEP, &dev->flags); spin_unlock_irq(&dev->txq.lock); } /* * accelerate emptying of the rx and queues, to avoid * having everything error out. */ netif_device_detach (dev->net); usbnet_terminate_urbs(dev); usb_kill_urb(dev->interrupt); /* * reattach so runtime management can use and * wake the device */ netif_device_attach (dev->net); } return 0; }
static int acm_suspend(struct usb_interface *intf, pm_message_t message) { struct acm *acm = usb_get_intfdata(intf); int cnt; spin_lock_irq(&acm->read_lock); spin_lock(&acm->write_lock); if (PMSG_IS_AUTO(message)) { if (acm->transmitting) { spin_unlock(&acm->write_lock); spin_unlock_irq(&acm->read_lock); return -EBUSY; } } cnt = acm->susp_count++; spin_unlock(&acm->write_lock); spin_unlock_irq(&acm->read_lock); if (cnt) return 0; stop_data_traffic(acm); return 0; }
static int acm_suspend(struct usb_interface *intf, pm_message_t message) { struct acm *acm = usb_get_intfdata(intf); int cnt; if (PMSG_IS_AUTO(message)) { int b; spin_lock_irq(&acm->write_lock); b = acm->transmitting; spin_unlock_irq(&acm->write_lock); if (b) return -EBUSY; } spin_lock_irq(&acm->read_lock); spin_lock(&acm->write_lock); cnt = acm->susp_count++; spin_unlock(&acm->write_lock); spin_unlock_irq(&acm->read_lock); if (cnt) return 0; /* we treat opened interfaces differently, we must guard against open */ mutex_lock(&acm->mutex); if (acm->port.count) stop_data_traffic(acm); mutex_unlock(&acm->mutex); return 0; }
/* * Get the device ready for USB port or system standby and hibernation * * USB port and system standby are handled the same. * * When the system hibernates, the USB device is powered down and then * up, so we don't really have to do much here, as it will be seen as * a reconnect. Still for simplicity we consider this case the same as * suspend, so that the device has a chance to do notify the base * station (if connected). * * So at the end, the three cases require common handling. * * If at the time of this call the device's firmware is not loaded, * nothing has to be done. Note we can be "loose" about not reading * i2400m->updown under i2400m->init_mutex. If it happens to change * inmediately, other parts of the call flow will fail and effectively * catch it. * * If the firmware is loaded, we need to: * * - tell the device to go into host interface power save mode, wait * for it to ack * * This is quite more interesting than it is; we need to execute a * command, but this time, we don't want the code in usb-{tx,rx}.c * to call the usb_autopm_get/put_interface() barriers as it'd * deadlock, so we need to decrement i2400mu->do_autopm, that acts * as a poor man's semaphore. Ugly, but it works. * * As well, the device might refuse going to sleep for whichever * reason. In this case we just fail. For system suspend/hibernate, * we *can't* fail. We check PMSG_IS_AUTO to see if the * suspend call comes from the USB stack or from the system and act * in consequence. * * - stop the notification endpoint polling */ static int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) { int result = 0; struct device *dev = &iface->dev; struct i2400mu *i2400mu = usb_get_intfdata(iface); unsigned is_autosuspend = 0; struct i2400m *i2400m = &i2400mu->i2400m; #ifdef CONFIG_PM if (PMSG_IS_AUTO(pm_msg)) is_autosuspend = 1; #endif d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); rmb(); /* see i2400m->updown's documentation */ if (i2400m->updown == 0) goto no_firmware; if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { /* ugh -- the device is connected and this suspend * request is an autosuspend one (not a system standby * / hibernate). * * The only way the device can go to standby is if the * link with the base station is in IDLE mode; that * were the case, we'd be in status * I2400M_SS_CONNECTED_IDLE. But we are not. * * If we *tell* him to go power save now, it'll reset * as a precautionary measure, so if this is an * autosuspend thing, say no and it'll come back * later, when the link is IDLE */ result = -EBADF; d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " "not entering powersave\n"); goto error_not_now; } d_printf(1, dev, "fw up: entering powersave\n"); atomic_dec(&i2400mu->do_autopm); result = i2400m_cmd_enter_powersave(i2400m); atomic_inc(&i2400mu->do_autopm); if (result < 0 && !is_autosuspend) { /* System suspend, can't fail */ dev_err(dev, "failed to suspend, will reset on resume\n"); result = 0; } if (result < 0) goto error_enter_powersave; i2400mu_notification_release(i2400mu); d_printf(1, dev, "powersave requested\n"); error_enter_powersave: error_not_now: no_firmware: d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", iface, pm_msg.event, result); return result; }
static int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) { int result = 0; struct device *dev = &iface->dev; struct i2400mu *i2400mu = usb_get_intfdata(iface); unsigned is_autosuspend = 0; struct i2400m *i2400m = &i2400mu->i2400m; #ifdef CONFIG_PM if (PMSG_IS_AUTO(pm_msg)) is_autosuspend = 1; #endif d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); rmb(); /* */ if (i2400m->updown == 0) goto no_firmware; if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { /* */ result = -EBADF; d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " "not entering powersave\n"); goto error_not_now; } d_printf(1, dev, "fw up: entering powersave\n"); atomic_dec(&i2400mu->do_autopm); result = i2400m_cmd_enter_powersave(i2400m); atomic_inc(&i2400mu->do_autopm); if (result < 0 && !is_autosuspend) { /* */ dev_err(dev, "failed to suspend, will reset on resume\n"); result = 0; } if (result < 0) goto error_enter_powersave; i2400mu_notification_release(i2400mu); d_printf(1, dev, "powersave requested\n"); error_enter_powersave: error_not_now: no_firmware: d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", iface, pm_msg.event, result); return result; }
static int picolcd_suspend(struct hid_device *hdev, pm_message_t message) { if (PMSG_IS_AUTO(message)) return 0; picolcd_suspend_backlight(hid_get_drvdata(hdev)); dbg_hid(PICOLCD_NAME " device ready for suspend\n"); return 0; }
static int sierra_suspend(struct usb_serial *serial, pm_message_t message) { struct sierra_intf_private *intfdata = usb_get_serial_data(serial); spin_lock_irq(&intfdata->susp_lock); if (PMSG_IS_AUTO(message)) { if (intfdata->in_flight) { spin_unlock_irq(&intfdata->susp_lock); return -EBUSY; } } intfdata->suspended = 1; spin_unlock_irq(&intfdata->susp_lock); stop_read_write_urbs(serial); return 0; }
static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message) { struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf); nfc_info(&drv_data->udev->dev, "intf %p", intf); if (drv_data->suspend_count++) return 0; spin_lock_irq(&drv_data->txlock); if (!(PMSG_IS_AUTO(message) && drv_data->tx_in_flight)) { set_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags); spin_unlock_irq(&drv_data->txlock); } else { spin_unlock_irq(&drv_data->txlock); drv_data->suspend_count--; return -EBUSY; } nfcmrvl_usb_stop_traffic(drv_data); usb_kill_anchored_urbs(&drv_data->tx_anchor); return 0; }
static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) { unsigned long flags; int ret; u32 reg; /* Bring core to D0 state */ dwc3_set_usb_core_power(dwc, true); ret = dwc3_core_init(dwc); if (ret) return ret; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: ret = dwc3_core_init_for_resume(dwc); if (ret) return ret; dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_resume(dwc); spin_unlock_irqrestore(&dwc->lock, flags); break; case DWC3_GCTL_PRTCAP_HOST: if (!PMSG_IS_AUTO(msg)) { ret = dwc3_core_init_for_resume(dwc); if (ret) return ret; dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); break; } /* Restore GUSB2PHYCFG bits that were modified in suspend */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); if (dwc->dis_u2_susphy_quirk) reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; if (dwc->dis_enblslpm_quirk) reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); phy_pm_runtime_get_sync(dwc->usb2_generic_phy); phy_pm_runtime_get_sync(dwc->usb3_generic_phy); break; case DWC3_GCTL_PRTCAP_OTG: /* nothing to do on runtime_resume */ if (PMSG_IS_AUTO(msg)) break; ret = dwc3_core_init(dwc); if (ret) return ret; dwc3_set_prtcap(dwc, dwc->current_dr_role); dwc3_otg_init(dwc); if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) { dwc3_otg_host_init(dwc); } else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) { spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_resume(dwc); spin_unlock_irqrestore(&dwc->lock, flags); } break; default: /* do nothing */ break; } return 0; }
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) { unsigned long flags; u32 reg; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_suspend(dwc); spin_unlock_irqrestore(&dwc->lock, flags); dwc3_core_exit(dwc); break; case DWC3_GCTL_PRTCAP_HOST: if (!PMSG_IS_AUTO(msg)) { dwc3_core_exit(dwc); break; } /* Let controller to suspend HSPHY before PHY driver suspends */ if (dwc->dis_u2_susphy_quirk || dwc->dis_enblslpm_quirk) { reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | DWC3_GUSB2PHYCFG_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); /* Give some time for USB2 PHY to suspend */ usleep_range(5000, 6000); } phy_pm_runtime_put_sync(dwc->usb2_generic_phy); phy_pm_runtime_put_sync(dwc->usb3_generic_phy); break; case DWC3_GCTL_PRTCAP_OTG: /* do nothing during runtime_suspend */ if (PMSG_IS_AUTO(msg)) break; if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) { spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_suspend(dwc); spin_unlock_irqrestore(&dwc->lock, flags); } dwc3_otg_exit(dwc); dwc3_core_exit(dwc); break; default: /* do nothing */ break; } dwc3_event_buffers_cleanup(dwc); /* Put the core into D3 state */ dwc3_set_usb_core_power(dwc, false); /* * To avoid reinit of phy during resume, prevent calling the * dwc3_core_exit() when in D3 state */ if (!dwc->is_d3) dwc3_core_exit(dwc); return 0; }