由于近来做的一个项目是基于android 2.3的版本,所以就对该版本的电源管理大致分析了下,跟大家分享,有错误之处,敬请指正,谢谢!
针对的处理器是高通MSM8260,主要是针对一些挂起唤醒流程进行分析,以便对整个usb框架流程更好的理解。
废话少说,开始分析。
由于linux中的电源管理比较复杂,我就找了一个统一的接口,也就是要想操纵usb的电源管理必定要调的函数。顺便说下,跟踪代码最好的方法是用WARN_ON(1)打调用栈。
先看电源管理子系统的一些初始化:
/*系统初始化所用的结构体*/
struct device {
.....
struct dev_pm_info power;//电源管理结构体
.........
};
/*该结构体定义如下*/
struct dev_pm_info {
pm_message_t power_state;
unsigned int can_wakeup:1;//can_wakeup标志表示设备(或驱动)物理上支持唤醒事件
unsigned int should_wakeup:1;//should_wakeup标志控制设备是否应该尝试启用他的唤醒机制
unsigned async_suspend:1;
enum dpm_state status; /* Owned by the PM core */
#ifdef CONFIG_PM_SLEEP
struct list_head entry;//链接到dpm_list链表的节点
struct completion completion;
#endif
#ifdef CONFIG_PM_RUNTIME
struct timer_list suspend_timer;//处理自动挂起的timer
unsigned long timer_expires;
struct work_struct work;//请求处理用的work
wait_queue_head_t wait_queue;//等待队列头
spinlock_t lock;
atomic_t usage_count;
atomic_t child_count;
unsigned int disable_depth:3;
unsigned int ignore_children:1;
unsigned int idle_notification:1;
unsigned int request_pending:1;
unsigned int deferred_resume:1;
unsigned int run_wake:1;
unsigned int runtime_auto:1;
enum rpm_request request;
enum rpm_status runtime_status;
int runtime_error;
#endif
};
/*在设备加入设备驱动模型时,对设备进行初始化*/
device_initialize(&dev->dev);
void device_initialize(struct device *dev)
{
............
device_pm_init(dev);//继续进行初始化
...............
}
void device_pm_init(struct device *dev)
{
dev->power.status = DPM_ON;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
pm_runtime_init(dev);//调用该函数继续进行初始化
}
void pm_runtime_init(struct device *dev)
{
spin_lock_init(&dev->power.lock);
dev->power.runtime_status = RPM_SUSPENDED;
dev->power.idle_notification = false;
dev->power.disable_depth = 1;//初始化时,disable该pm runtime功能
atomic_set(&dev->power.usage_count, 0);
dev->power.runtime_error = 0;
atomic_set(&dev->power.child_count, 0);
pm_suspend_ignore_children(dev, false);
dev->power.runtime_auto = true;
dev->power.request_pending = false;
dev->power.request = RPM_REQ_NONE;
dev->power.deferred_resume = false;
INIT_WORK(&dev->power.work, pm_runtime_work);//处理autosuspend请求用的work
/*处理work请求定时器*/
dev->power.timer_expires = 0;
setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,(unsigned long)dev);
init_waitqueue_head(&dev->power.wait_queue);//初始化等待队列
}
***************************************************************
/*注册的usb总线级别的操作*/
static int usb_runtime_suspend(struct device *dev)//usb的挂机函数
{
int status = 0;
/* A USB device can be suspended if it passes the various autosuspend
* checks. Runtime suspend for a USB device means suspending all the
* interfaces and then the device itself.
*/
if (is_usb_device(dev)) {//针对usb设备
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)//是否支持自动挂起?
return -EAGAIN;
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);// 如果不支持,则继续挂机流程
/* If an interface fails the suspend, adjust the last_busy
* time so that we don't get another suspend attempt right
* away.
*/
if (status) {
udev->last_busy = jiffies + (udev->autosuspend_delay == 0 ? HZ/2 : 0);
}
/* Prevent the parent from suspending immediately after */
else if (udev->parent) {
udev->parent->last_busy = jiffies;
}
}
/* Runtime suspend for a USB interface doesn't mean anything. */
return status;
}
static int usb_runtime_resume(struct device *dev)//usb的唤醒函数
{
/* Runtime resume for a USB device means resuming both the device
* and all its interfaces.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
int status;
status = usb_resume_both(udev, PMSG_AUTO_RESUME);
udev->last_busy = jiffies;
return status;
}
/* Runtime resume for a USB interface doesn't mean anything. */
return 0;
}
static int usb_runtime_idle(struct device *dev)//usb设备的idle函数
{
/* An idle USB device can be suspended if it passes the various
* autosuspend checks. An idle interface can be suspended at
* any time.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)//支持自动挂起
return 0;
}
pm_runtime_suspend(dev);
return 0;
}
static struct dev_pm_ops usb_bus_pm_ops = {
.runtime_suspend = usb_runtime_suspend,
.runtime_resume = usb_runtime_resume,
.runtime_idle = usb_runtime_idle,
};
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
.pm = &usb_bus_pm_ops,
};
上面是系统和usb子系统的电源管理初始化部分。
/**************************************************************************/
usb子系统电源管理的调用过程,必须要调用下面两个函数,就从这两个函数开始跟起。
/*驱动调用的接口开始,传入的是usb设备结构体或者usb接口设备结构体*/
static inline int pm_runtime_put(struct device *dev)
{
return __pm_runtime_put(dev, false);
}
static inline int pm_runtime_put_sync(struct device *dev)
{
return __pm_runtime_put(dev, true);
}
上面两个函数一个是同步的一个是不同步的。先跟同步的:
/*当sync为true时,走的如下流程*/
int __pm_runtime_put(struct device *dev, bool sync)
{
int retval = 0;
if (atomic_dec_and_test(&dev->power.usage_count))
retval = sync ? pm_runtime_idle(dev) : pm_request_idle(dev);
return retval;
}
int pm_runtime_idle(struct device *dev)
{
int retval;
spin_lock_irq(&dev->power.lock);
retval = __pm_runtime_idle(dev);
spin_unlock_irq(&dev->power.lock);
return retval;
}
static int __pm_runtime_idle(struct device *dev)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
dev->power.idle_notification = true;
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->bus->pm->runtime_idle(dev);//调用usb总线的idle函数
spin_lock_irq(&dev->power.lock);
} else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->type->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
} else if (dev->class && dev->class->pm
&& dev->class->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->class->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
}
dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);
out:
return retval;
}
/*usb总线的idle函数如下*/
static int usb_runtime_idle(struct device *dev)
{
/* An idle USB device can be suspended if it passes the various
* autosuspend checks. An idle interface can be suspended at
* any time.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)//检测是否自动挂起,如果是自动挂起的话,走自动挂起流程
return 0;
}
pm_runtime_suspend(dev);//如果不是自动挂起,则继续suspend
return 0;
}
int pm_runtime_suspend(struct device *dev)
{
int retval;
spin_lock_irq(&dev->power.lock);
retval = __pm_runtime_suspend(dev, false);
spin_unlock_irq(&dev->power.lock);
return retval;
}
int __pm_runtime_suspend(struct device *dev, bool from_wq)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
struct device *parent = NULL;
bool notify = false;
int retval = 0;
dev_dbg(dev, "__pm_runtime_suspend()%s!\n",
from_wq ? " from workqueue" : "");
repeat:
/* Other scheduled or pending requests need to be canceled. */
pm_runtime_cancel_pending(dev);
if (dev->power.runtime_status == RPM_SUSPENDING) {
DEFINE_WAIT(wait);
if (from_wq) {
retval = -EINPROGRESS;
goto out;
}
/* Wait for the other suspend running in parallel with us. */
for (;;) {
prepare_to_wait(&dev->power.wait_queue, &wait, TASK_UNINTERRUPTIBLE);
if (dev->power.runtime_status != RPM_SUSPENDING)
break;
spin_unlock_irq(&dev->power.lock);
schedule();
spin_lock_irq(&dev->power.lock);
}
finish_wait(&dev->power.wait_queue, &wait);
goto repeat;
}
dev->power.runtime_status = RPM_SUSPENDING;
dev->power.deferred_resume = false;
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->bus->pm->runtime_suspend(dev);//调用总线的runtime suspend函数
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->type->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->class && dev->class->pm
&& dev->class->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->class->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else {
retval = -ENOSYS;
}
wake_up_all(&dev->power.wait_queue);
if (dev->power.deferred_resume) {
__pm_runtime_resume(dev, false);
retval = -EAGAIN;
goto out;
}
if (notify)
__pm_runtime_idle(dev);
if (parent && !parent->power.ignore_children) {
spin_unlock_irq(&dev->power.lock);
pm_request_idle(parent);
spin_lock_irq(&dev->power.lock);
}
out:
dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval);
return retval;
}
static int usb_runtime_suspend(struct device *dev)
{
int status = 0;
/* A USB device can be suspended if it passes the various autosuspend
* checks. Runtime suspend for a USB device means suspending all the
* interfaces and then the device itself.
*/
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)//是否自動挂起,如果是走自动挂起流程
return -EAGAIN;
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);//否则继续suspend
/* If an interface fails the suspend, adjust the last_busy
* time so that we don't get another suspend attempt right
* away.
*/
if (status) {
udev->last_busy = jiffies +(udev->autosuspend_delay == 0 ? HZ/2 : 0);
}
/* Prevent the parent from suspending immediately after */
else if (udev->parent) {
udev->parent->last_busy = jiffies;
}
}
/* Runtime suspend for a USB interface doesn't mean anything. */
return status;
}
static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
{
int status = 0;
int i = 0, n = 0;
struct usb_interface *intf;
if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED)
goto done;
/* Suspend all the interfaces and then udev itself */
if (udev->actconfig) {//挂起所有的接口
n = udev->actconfig->desc.bNumInterfaces;
for (i = n - 1; i >= 0; --i) {
intf = udev->actconfig->interface[i];
status = usb_suspend_interface(udev, intf, msg);
if (status != 0)
break;
}
}
if (status == 0)
status = usb_suspend_device(udev, msg);//挂起该设备本身
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
while (++i < n) {
intf = udev->actconfig->interface[i];
usb_resume_interface(udev, intf, msg, 0);
}
/* If the suspend succeeded then prevent any more URB submissions
* and flush any outstanding URBs.
*/
} else {
udev->can_submit = 0;
for (i = 0; i < 16; ++i) {
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
}
}
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
{
struct usb_device_driver *udriver;
int status = 0;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED)
goto done;
/* For devices that don't have a driver, we do a generic suspend. */
if (udev->dev.driver)
udriver = to_usb_device_driver(udev->dev.driver);
else {
udev->do_remote_wakeup = 0;
udriver = &usb_generic_driver;
}
status = udriver->suspend(udev, msg);//调用通用的设备驱动挂起函数
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
int rc;
/* Normal USB devices suspend through their upstream port.
* Root hubs don't have upstream ports to suspend,
* so we have to shut down their downstream HC-to-USB
* interfaces manually by doing a bus (or "global") suspend.
*/
if (!udev->parent)//针对root hub的
rc = hcd_bus_suspend(udev, msg);//挂起root hub
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
rc = 0;
else
rc = usb_port_suspend(udev, msg);//挂起每个端口设备
return rc;
}
*********************************************************************
下面是自动挂起的流程(上面的蓝色字体标出调用的地方),最终也会走到generic_suspend,相当于两条小溪最终汇成一起。
/* Internal routine to check whether we may autosuspend a device. */
static int autosuspend_check(struct usb_device *udev)
{
int w, i;
struct usb_interface *intf;
unsigned long suspend_time, j;
/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
*/
w = 0;
if (udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
/* We don't need to check interfaces that are
* disabled for runtime PM. Either they are unbound
* or else their drivers don't support autosuspend
* and so they are permanently active.
*/
if (intf->dev.power.disable_depth)
continue;
if (atomic_read(&intf->dev.power.usage_count) > 0)
return -EBUSY;
w |= intf->needs_remote_wakeup;
/* Don't allow autosuspend if the device will need
* a reset-resume and any of its interface drivers
* doesn't include support or needs remote wakeup.
*/
if (udev->quirks & USB_QUIRK_RESET_RESUME) {
struct usb_driver *driver;
driver = to_usb_driver(intf->dev.driver);
if (!driver->reset_resume ||
intf->needs_remote_wakeup)
return -EOPNOTSUPP;
}
}
}
if (w && !device_can_wakeup(&udev->dev)) {
dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
return -EOPNOTSUPP;
}
udev->do_remote_wakeup = w;
/* If everything is okay but the device hasn't been idle for long
* enough, queue a delayed autosuspend request.
*/
j = ACCESS_ONCE(jiffies);
suspend_time = udev->last_busy + udev->autosuspend_delay;
if (time_before(j, suspend_time)) {
pm_schedule_suspend(&udev->dev, jiffies_to_msecs(round_jiffies_up_relative(suspend_time - j)));//调度
return -EAGAIN;
}
return 0;
}
/**
* pm_schedule_suspend - Set up a timer to submit a suspend request in future.
* @dev: Device to suspend.
* @delay: Time to wait before submitting a suspend request, in milliseconds.
*/
int pm_schedule_suspend(struct device *dev, unsigned int delay)
{
unsigned long flags;
int retval = 0;
spin_lock_irqsave(&dev->power.lock, flags);
if (dev->power.runtime_error) {
retval = -EINVAL;
goto out;
}
if (!delay) {
retval = __pm_request_suspend(dev);//如果没有delay,则立即执行
goto out;
}
pm_runtime_deactivate_timer(dev);
if (dev->power.request_pending) {
/*
* Pending resume requests take precedence over us, but any
* other pending requests have to be canceled.
*/
if (dev->power.request == RPM_REQ_RESUME) {
retval = -EAGAIN;
goto out;
}
dev->power.request = RPM_REQ_NONE;
}
if (dev->power.runtime_status == RPM_SUSPENDED)
retval = 1;
else if (atomic_read(&dev->power.usage_count) > 0
|| dev->power.disable_depth > 0)
retval = -EAGAIN;
else if (!pm_children_suspended(dev))
retval = -EBUSY;
if (retval)
goto out;
dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
if (!dev->power.timer_expires)
dev->power.timer_expires = 1;
mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);//如果有超时,等待定时器到期,执行处理函数pm_suspend_timer_fn
out:
spin_unlock_irqrestore(&dev->power.lock, flags);
return retval;
}
/*定时器到期处理函数*/
static void pm_suspend_timer_fn(unsigned long data)
{
struct device *dev = (struct device *)data;
unsigned long flags;
unsigned long expires;
spin_lock_irqsave(&dev->power.lock, flags);
expires = dev->power.timer_expires;
/* If 'expire' is after 'jiffies' we've been called too early. */
if (expires > 0 && !time_after(expires, jiffies)) {
dev->power.timer_expires = 0;
__pm_request_suspend(dev);//定时器到时,执行该函数
}
spin_unlock_irqrestore(&dev->power.lock, flags);
}
/*无论是定时器超时,还是直接调用,都会调用下面该函数*/
static int __pm_request_suspend(struct device *dev)
{
int retval = 0;
if (dev->power.runtime_error)
return -EINVAL;
if (dev->power.runtime_status == RPM_SUSPENDED)
retval = 1;
else if (atomic_read(&dev->power.usage_count) > 0
|| dev->power.disable_depth > 0)
retval = -EAGAIN;
else if (dev->power.runtime_status == RPM_SUSPENDING)
retval = -EINPROGRESS;
else if (!pm_children_suspended(dev))
retval = -EBUSY;
if (retval < 0)
return retval;
pm_runtime_deactivate_timer(dev);
if (dev->power.request_pending) {
/*
* Pending resume requests take precedence over us, but we can
* overtake any other pending request.
*/
if (dev->power.request == RPM_REQ_RESUME)
retval = -EAGAIN;
else if (dev->power.request != RPM_REQ_SUSPEND)
dev->power.request = retval ?
RPM_REQ_NONE : RPM_REQ_SUSPEND;
return retval;
} else if (retval) {
return retval;
}
dev->power.request = RPM_REQ_SUSPEND;//请求状态为suspend
dev->power.request_pending = true;
queue_work(pm_wq, &dev->power.work);//调度work
return 0;
}
static void pm_runtime_work(struct work_struct *work)
{
struct device *dev = container_of(work, struct device, power.work);
enum rpm_request req;
spin_lock_irq(&dev->power.lock);
if (!dev->power.request_pending)
goto out;
req = dev->power.request;
dev->power.request = RPM_REQ_NONE;
dev->power.request_pending = false;
switch (req) {
case RPM_REQ_NONE:
break;
case RPM_REQ_IDLE:
__pm_runtime_idle(dev);
break;
case RPM_REQ_SUSPEND:
__pm_runtime_suspend(dev, true); //调用suspend函数
break;
case RPM_REQ_RESUME:
__pm_runtime_resume(dev, true);
break;
}
out:
spin_unlock_irq(&dev->power.lock);
}
int __pm_runtime_suspend(struct device *dev, bool from_wq)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
struct device *parent = NULL;
bool notify = false;
int retval = 0;
dev_dbg(dev, "__pm_runtime_suspend()%s!\n",from_wq ? " from workqueue" : "");
...................
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->bus->pm->runtime_suspend(dev);//调用usb总线的runtime_suspend函数
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
}
...................
out:
dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval);
return retval;
}
static int usb_runtime_suspend(struct device *dev)
{
int status = 0;
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
if (autosuspend_check(udev) != 0)
return -EAGAIN;
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);//3
...............
return status;
}
static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
{
int status = 0;
int i = 0, n = 0;
struct usb_interface *intf;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED)
goto done;
/* Suspend all the interfaces and then udev itself */
if (udev->actconfig) {//挂起所以端口
n = udev->actconfig->desc.bNumInterfaces;
for (i = n - 1; i >= 0; --i) {
intf = udev->actconfig->interface[i];
status = usb_suspend_interface(udev, intf, msg);
if (status != 0)
break;
}
}
if (status == 0)
status = usb_suspend_device(udev, msg);//挂起usb设备本身
..............
} else {
udev->can_submit = 0;
for (i = 0; i < 16; ++i) {
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
}
}
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
{
if (udev->dev.driver)
udriver = to_usb_device_driver(udev->dev.driver);
else {
udev->do_remote_wakeup = 0;
udriver = &usb_generic_driver;
}
status = udriver->suspend(udev, msg);//5
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,//6
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
int rc;
if (!udev->parent)
rc = hcd_bus_suspend(udev, msg);//7
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
rc = 0;
else
rc = usb_port_suspend(udev, msg);
return rc;
}
***************************************************
/*通用usb设备的suspend函数,上面的自动挂起和正常挂起都会走*/
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
int rc;
/* Normal USB devices suspend through their upstream port.
* Root hubs don't have upstream ports to suspend,
* so we have to shut down their downstream HC-to-USB
* interfaces manually by doing a bus (or "global") suspend.
*/
if (!udev->parent)//针对root hub
rc = hcd_bus_suspend(udev, msg);//挂起root hub的下流口
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
rc = 0;
else
rc = usb_port_suspend(udev, msg);//关闭usb设备的上流口
return rc;
}
int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
{
struct usb_hub *hub = hdev_to_hub(udev->parent);
int port1 = udev->portnum;
int status;
// dev_dbg(hub->intfdev, "suspend port %d\n", port1);
/* enable remote wakeup when appropriate; this lets the device
* wake up the upstream hub (including maybe the root hub).
*
* NOTE: OTG devices may issue remote wakeup (or SRP) even when
* we don't explicitly enable it here.
*/
if (udev->do_remote_wakeup) {
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
/* see 7.1.7.6 */
status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
/* device has up to 10 msec to fully suspend */
dev_dbg(&udev->dev, "usb %ssuspend\n",(msg.event & PM_EVENT_AUTO ? "auto-" : ""));
usb_set_device_state(udev, USB_STATE_SUSPENDED);//设置usb设备为挂起状态
msleep(10);
}
return status;
}
/*挂起root hub*/
int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
{
struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
int status;
int old_state = hcd->state;
dev_dbg(&rhdev->dev, "bus %s%s\n",
(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend");
if (!hcd->driver->bus_suspend) {
status = -ENOENT;
} else {
hcd->state = HC_STATE_QUIESCING;
status = hcd->driver->bus_suspend(hcd);//调用主机控制器driver的bus suspend
}
if (status == 0) {
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);//设置root hub设备的状态为suspend状态
hcd->state = HC_STATE_SUSPENDED;
} else {
hcd->state = old_state;
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n","suspend", status);
}
return status;
}
static struct hc_driver msm_hc_driver = {
.description = hcd_name,
.product_desc = "Qualcomm On-Chip EHCI Host Controller",
.hcd_priv_size = sizeof(struct msmusb_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_msm_irq,
.flags = HCD_USB2,
.reset = ehci_msm_reset,
.start = ehci_msm_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.bus_suspend = ehci_msm_bus_suspend,//调用该suspend函数
.bus_resume = ehci_msm_bus_resume,
.relinquish_port = ehci_relinquish_port,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int ehci_msm_bus_suspend(struct usb_hcd *hcd)
{
int ret;
struct msmusb_hcd *mhcd = hcd_to_mhcd(hcd);
struct device *dev = hcd->self.controller;
ret = ehci_bus_suspend(hcd);//root hub挂起
if (ret) {
pr_err("ehci_bus suspend faield\n");
return ret;
}
/*下面是挂起otg控制器*/
if (PHY_TYPE(mhcd->pdata->phy_info) == USB_PHY_INTEGRATED)
ret = otg_set_suspend(mhcd->xceiv, 1);//otg挂起,调用该函数
else
ret = usb_lpm_enter(hcd);
pm_runtime_put_noidle(dev);
pm_runtime_suspend(dev);
wake_unlock(&mhcd->wlock);
return ret;
}
static inline int otg_set_suspend(struct otg_transceiver *otg, int suspend)
{
if (otg->set_suspend != NULL)
return otg->set_suspend(otg, suspend);
else
return 0;
}
dev->otg.set_suspend = msm_otg_set_suspend;
static int msm_otg_set_suspend(struct otg_transceiver *xceiv, int suspend)
{
struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
enum usb_otg_state state;
unsigned long flags;
if (!dev || (dev != the_msm_otg))
return -ENODEV;
spin_lock_irqsave(&dev->lock, flags);
state = dev->otg.state;
spin_unlock_irqrestore(&dev->lock, flags);
pr_debug("suspend request in state: %s\n",
state_string(state));
if (suspend) {
switch (state) {
#ifndef CONFIG_MSM_OTG_ENABLE_A_WAIT_BCON_TIMEOUT
case OTG_STATE_A_WAIT_BCON:
if (test_bit(ID_A, &dev->inputs))
msm_otg_set_power(xceiv, USB_IDCHG_MIN - 100);
msm_otg_put_suspend(dev);//如果没有usb设备连接,则进入该函数
break;
#endif
case OTG_STATE_A_HOST:
clear_bit(A_BUS_REQ, &dev->inputs);
wake_lock(&dev->wlock);
queue_work(dev->wq, &dev->sm_work);
break;
case OTG_STATE_B_PERIPHERAL:
if (xceiv->gadget->b_hnp_enable) {
set_bit(A_BUS_SUSPEND, &dev->inputs);
set_bit(B_BUS_REQ, &dev->inputs);
wake_lock(&dev->wlock);
queue_work(dev->wq, &dev->sm_work);
}
break;
case OTG_STATE_A_PERIPHERAL:
msm_otg_start_timer(dev, TA_BIDL_ADIS,
A_BIDL_ADIS);
break;
default:
break;
}
} else {
unsigned long timeout;
switch (state) {
case OTG_STATE_A_PERIPHERAL:
/* A-peripheral observed activity on bus.
* clear A_BIDL_ADIS timer.
*/
msm_otg_del_timer(dev);
break;
case OTG_STATE_A_SUSPEND:
/* Remote wakeup or resume */
set_bit(A_BUS_REQ, &dev->inputs);
spin_lock_irqsave(&dev->lock, flags);
dev->otg.state = OTG_STATE_A_HOST;
spin_unlock_irqrestore(&dev->lock, flags);
if (test_bit(ID_A, &dev->inputs) &&
(get_aca_bmaxpower(dev) < USB_IDCHG_MIN))
msm_otg_set_power(xceiv,
USB_IDCHG_MIN - get_aca_bmaxpower(dev));
break;
default:
break;
}
if (suspend == atomic_read(&dev->in_lpm))
return 0;
disable_irq(dev->irq);
if (dev->pmic_vbus_notif_supp)
if (can_phy_power_collapse(dev) &&
dev->pdata->ldo_enable)
dev->pdata->ldo_enable(1);
msm_otg_get_resume(dev);
if (!is_phy_clk_disabled())
goto out;
timeout = jiffies + usecs_to_jiffies(100);
enable_phy_clk();
while (is_phy_clk_disabled()) {
if (time_after(jiffies, timeout)) {
pr_err("%s: Unable to wakeup phy\n", __func__);
/* Reset both phy and link */
otg_reset(&dev->otg, 1);
break;
}
udelay(10);
}
if (dev->pmic_id_notif_supp) {
dev->pdata->pmic_id_notif_init(
&msm_otg_set_id_state, 0);
dev->pmic_id_notif_supp = 0;
enable_idgnd(dev);
}
out:
enable_idabc(dev);
enable_irq(dev->irq);
}
return 0;
}
//上面是主机控制器调用到的该流程.
//设备控制器直接调用该函数是设备进入suspend状态
/***************************************************************/
static void msm_otg_put_suspend(struct msm_otg *dev)
{
#ifdef CONFIG_PM_RUNTIME
pm_runtime_put_sync(dev->otg.dev);//调用该函数,注意:传入的是平台设备
if (!atomic_read(&dev->in_lpm))
pm_runtime_get_sync(dev->otg.dev);
#else
msm_otg_suspend(dev);
#endif
}
static inline int pm_runtime_put_sync(struct device *dev)
{
return __pm_runtime_put(dev, true);//调用该函数
}
int __pm_runtime_put(struct device *dev, bool sync)
{
int retval = 0;
if (atomic_dec_and_test(&dev->power.usage_count))
retval = sync ? pm_runtime_idle(dev)/*调用该函数*/: pm_request_idle(dev);
return retval;
}
int pm_runtime_idle(struct device *dev)
{
int retval;
spin_lock_irq(&dev->power.lock);
retval = __pm_runtime_idle(dev);//调用该函数
spin_unlock_irq(&dev->power.lock);
return retval;
}
static int __pm_runtime_idle(struct device *dev)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
int retval = 0;
...............
dev->power.idle_notification = true;
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->bus->pm->runtime_idle(dev);//调用该函数
spin_lock_irq(&dev->power.lock);
} else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->type->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
} else if (dev->class && dev->class->pm
&& dev->class->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->class->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
}
dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);
out:
return retval;
}
static const struct dev_pm_ops platform_dev_pm_ops = {
.prepare = platform_pm_prepare,
.complete = platform_pm_complete,
.suspend = platform_pm_suspend,
.resume = platform_pm_resume,
.freeze = platform_pm_freeze,
.thaw = platform_pm_thaw,
.poweroff = platform_pm_poweroff,
.restore = platform_pm_restore,
.suspend_noirq = platform_pm_suspend_noirq,
.resume_noirq = platform_pm_resume_noirq,
.freeze_noirq = platform_pm_freeze_noirq,
.thaw_noirq = platform_pm_thaw_noirq,
.poweroff_noirq = platform_pm_poweroff_noirq,
.restore_noirq = platform_pm_restore_noirq,
.runtime_suspend = platform_pm_runtime_suspend,
.runtime_resume = platform_pm_runtime_resume,
.runtime_idle = platform_pm_runtime_idle,//调用该处的函数
};
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
int __weak platform_pm_runtime_idle(struct device *dev)
{
return pm_generic_runtime_idle(dev);//调用该函数
};
int pm_generic_runtime_idle(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm && pm->runtime_idle) {
int ret = pm->runtime_idle(dev);
if (ret)
return ret;
}
pm_runtime_suspend(dev);//调用该函数
return 0;
}
int pm_runtime_suspend(struct device *dev)
{
int retval;
spin_lock_irq(&dev->power.lock);
retval = __pm_runtime_suspend(dev, false);//调用该函数
spin_unlock_irq(&dev->power.lock);
return retval;
}
int __pm_runtime_suspend(struct device *dev, bool from_wq)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
struct device *parent = NULL;
bool notify = false;
int retval = 0;
dev_dbg(dev, "__pm_runtime_suspend()%s!\n",from_wq ? " from workqueue" : "");
repeat:
dev->power.runtime_status = RPM_SUSPENDING;
dev->power.deferred_resume = false;
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->bus->pm->runtime_suspend(dev); //调用平台总线的suspend函数
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->type && dev->type->pm
&& dev->type->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->type->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->class && dev->class->pm
&& dev->class->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->class->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else {
retval = -ENOSYS;
}
if (notify)
__pm_runtime_idle(dev);
if (parent && !parent->power.ignore_children) {
spin_unlock_irq(&dev->power.lock);
pm_request_idle(parent);
spin_lock_irq(&dev->power.lock);
}
out:
dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval);
return retval;
}
int __weak platform_pm_runtime_suspend(struct device *dev)
{
return pm_generic_runtime_suspend(dev);
};
int pm_generic_runtime_suspend(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int ret;
ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL;//调用平台驱动的runtime_suspend函数
return ret;
}
/*平台驱动的注册函数*/
/*******************************************************************/
static int msm_otg_runtime_suspend(struct device *dev)
{
struct msm_otg *otg = the_msm_otg;
dev_dbg(dev, "pm_runtime: suspending...\n");
msm_otg_suspend(otg);
return 0;
}
static int msm_otg_runtime_resume(struct device *dev)
{
struct msm_otg *otg = the_msm_otg;
dev_dbg(dev, "pm_runtime: resuming...\n");
msm_otg_resume(otg);
return 0;
}
static int msm_otg_runtime_idle(struct device *dev)
{
dev_dbg(dev, "pm_runtime: idling...\n");
return 0;
}
static struct dev_pm_ops msm_otg_dev_pm_ops = {
.runtime_suspend = msm_otg_runtime_suspend,
.runtime_resume = msm_otg_runtime_resume,
.runtime_idle = msm_otg_runtime_idle,
};
static struct platform_driver msm_otg_driver = {
.remove = __exit_p(msm_otg_remove),
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &msm_otg_dev_pm_ops,
},
};
/*******************************************************************/
static int msm_otg_suspend(struct msm_otg *dev)
{
unsigned long timeout;
bool host_bus_suspend;
unsigned ret;
enum chg_type chg_type = atomic_read(&dev->chg_type);
unsigned long flags;
disable_irq(dev->irq);
if (atomic_read(&dev->in_lpm))
goto out;
atomic_set(&dev->in_lpm, 1);//设置low power mode为1,唤醒的时候要判断该标记
...............
if (dev->pdata->config_vddcx)
dev->pdata->config_vddcx(0);
pr_info("%s: usb in low power mode\n", __func__);
return 0;
}
到此整个睡眠流程分析完了。