Chinaunix首页 | 论坛 | 博客
  • 博客访问: 332419
  • 博文数量: 125
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 160
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-06 15:18
文章分类

全部博文(125)

文章存档

2014年(29)

2013年(93)

2012年(3)

分类: LINUX

2014-05-19 16:01:43

由于近来做的一个项目是基于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;
}
到此整个睡眠流程分析完了。
阅读(1784) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~