android usb电源管理,Android usb子系统的电源管理流程分析

由于近来做的一个项目是基于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;

}

到此整个睡眠流程分析完了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值