问题背景:实现一个休眠唤醒的功能,并可控制的使单板进入休眠或者唤醒的状态(管脚拉低进入休眠状态,拉高恢复)。以此来达到LPM(低功耗模式)的目的。

文档以wakeup_in管脚的休眠唤醒功能为例,描述了一个平台驱动从注册,匹配以及Probe内容的填充的一整个驱动实现的流程。

Wakeup_in管脚休眠唤醒功能的调试,大致可以分为下面这几个步骤来实现:

目录

1. 配置设备树

2. 注册驱动

3. probe函数

4. 驱动内容填充

5. 上层处理


1. 配置设备树

Pinctrl.dtsi配置:

在驱动的注册过程中,设备树起的是信息传递的作用。所以不论是根据驱动找设备树,还是根据设备树找对应的驱动代码,都是可以通过compatible这个属性来查找。

节点名称 {

compatible:compatible属性是一个字符串的列表。(用于驱动和设备的匹配绑定)。wakeup_in_gpio:指向gpio控制器tlmm_pinmux(引用该节点),gpiox_82引脚,低电平有效。qcom,gpio-names:goio名称。

Pinctrl-names:定义了pin脚用到的state列表。

Pinctrl - x:pin脚的两种配置状态。(在驱动中获取pin脚状态时会根据名称来匹配)。

};

GPIO的信息在/sys/kernel/debug/gpio文件内可以查看:

在驱动中获取gpio号时,获取到的不是82,而是一个与Linux通用GPIO API一起使用的GPIO编号,这里是924-1023,其中gpio82对应的GPIO编号是1006。

2. 注册驱动

platfprm_driver结构体如下:

平台驱动结构体内,内嵌继承了一个设备驱动结构体 。后续的注册过程,会完成这个结构体相关内容的填充。

平台驱动的设计主要是完成平台驱动结构体的填充和注册。

以wakeup_in驱动为例,完成了:

平台驱动的probe函数实现:.probe = wakeup_in_probe,。它是驱动的入口函数,当总线完成了设备的 match 操作以后就会进入驱动中该函数的运行。

平台驱动的remove函数实现:.remove= wakeup_in_remove,

实现设备驱动的name、owner、pm、of_match_table变量。

注册的过程

这里是实现对device_driver结构体内相关函数和变量的赋值。并将 driver的总线类型初始化为platform_bus_type。赋值完成后,将device_driver结构体作为参数传递,继续注册:

device_driver结构体如下:

继续跟代码:

driver_find传入两个参数,name和bus。通过驱动的name在bus上查找这个驱动是否已经注册过了,防止重复注册。(未注册则返回NULL)。

接下来的这个bus_add_driver接口,会根据总线类型把驱动添加到bus上,也是驱动正式开始注册的入口:

先通过bus_get接口获取总线(这里bus_type对应的是platform_bus_type)。

klist_init,kobject_init_and_add 和klist_add_tail,主要完成了Kobject的初始化和将初始化的kobject尾插到kset链表中。并给驱动创建目录(sys/bus/xxx/driver/xxx)。

到这块为止,其实已经将驱动注册到了内核中。接下里的操作,就是尝试给这个驱动匹配对应的设备。

driver_attach:尝试将这个驱动和设备进行绑定。

这里会获取设备链表里的每一个device,并调用fn(dev,data),也就是__driver_attach:

这里的match调用的是platform_match来进行匹配:

先将dev和drv转换为平台设备和驱动,然后会进行一个匹配方式的选择:这里采用OF类型(设备树类型)来进行匹配:

这里的drv->of_match_table,是在平台驱动结构体填充时赋值的:

name/type/compatible这三个匹配项,只要有一个不为空,就满足匹配条件,继续往下执行。

of_device_id结构体:

然后这里会进行一个匹配内容的选择,通过name/type/compatible。可以看出来,compatible是匹配优先级最高的项。这里使用compatible来进行匹配。

如果匹配成功了,则最后返回1。然后回到__driver_attach,执行device_driver_attach:

进入really_probe函数:将device结构中的driver指针指向这个驱动,这里就正式完成了驱动设备的匹配

接下来会调用上面注册的drv->probe,也就是平台驱动结构体填充时赋值的probe。并且将与驱动匹配的dev作为参数传给drv的probe函数

至此,驱动的整个注册匹配过程就结束了,接下来就开始probe该驱动。

3. probe函数

定义一个要用到的结构体:

wakeup_in管脚的休眠唤醒,在probe中主要体现在对pin、gpio、irq等资源的申请和初始化,以及相关功能函数的初始化

调用devm_pinctrl_get函数,向内核申请dev的pin脚资源。成功则会返回一个指向申请到的pin脚号的指针。(一个pinctrl的句柄,后面就可以通过该句柄,来对申请的pin脚进行操作)。

pinctrl_lookup_state这个函数,会根据传入的第二个参数state_name去遍历p->state链表的所有的状态,通过name来进行匹配,如果匹配成功,则返回指向这个状态的指针。

然后通过pinctrl_select_state这个函数,来将设备树中的pinctrl中的信息配置到该pin中。

通过of_get_named_gpio函数,根据第二个参数去设备树中查找对应的gpio,如果查询成功,则返回一个与Linux通用GPIO API一起使用的GPIO编号。

像pin/gpio这些在内核中都属于资源,所以使用之前先申请。通过pinctrl_gpio_request函数来向内核申请一个pin脚当作gpio来使用

申请到gpio之后,通过pinctrl_gpio_direction_input函数,将gpio配置为输入方向。

通过gpio_to_irq函数,来获取gpio对应的中断号,成功则返回该中断号。

通过gpio_to_irq获取到gpio对应的中断号后,再调用request_irq函数进行中断的注册:将这个中断号、中断的irq_handler、中断触发方式以及中断的名称注册到内核里。(注册的中断可以在/proc/interrupts文件内查看)。

通过wakeup_source_register函数来创建唤醒源设备,并将唤醒源设备加入全局的唤醒源设备列表,成功则返回指向这个唤醒源设备的指针。(注册的唤醒源设备可以在/sys/kernel/debug/wakeup_sources文件内查看)。

调用create_workqueue函数来创建一个工作队列,成功则返回指向该workqueue的指针。

调用INIT_WORK()函数来创建一个工作函数,并将该工作函数赋值给pdata->wk_work变量。

实现驱动LPM模式的suspend和resume,需要有一个中断唤醒源来将系统从sleep状态唤醒。通过调用enable_irq_wake(irq)函数,使该irq具有唤醒系统的功能 。(如果不设置该函数,则进休眠后就不会醒来)。

Probe主要的流程如图所示:

注:中断注册成功之后,要确保该中断有唤醒系统的特性。调用enable_irq_wake()接口来实现该功能。 

Probe完成之后,接下来需要填充驱动所要实现的内容:在wakeup_in管脚拉低时,表示允许模组进入休眠状态,拉高时唤醒模组。

Linux pm core提供了wakelock及autoslepp内核休眠机制。autosleep 和 wakelock是并行存在,只有 wakelock 唤醒锁全部释放且 autosleep 为 enable 时,系统才能进入休眠。

autosleep节点路径为/sys/power/autosleep,该值为mem表示打开autoslepp功能,值为off表示关闭。

4. 驱动内容填充

外部触发中断(拉高拉低wakeup_in) --> irq_handler() --> timer_handler() --> work() -->odm_notify()。

拉高或者拉低wakeup_in管脚,触发中断,执行irq_handler:

在中断处理函数中调用mod_timer()来重新启动定时器。

定时时间超时后,执行timer_handle:

在定时器处理函数中,调用queue_work()来将pdata->work工作函数提交到pdata->wk_wq工作队列的工作链表中,并唤醒等待队列,然后执行该工作函数。

通过gpio_get_value()接口获取当前wakeup_in管脚的电平状态,来判断是要进休眠还是要唤醒

如果是要进休眠,则调用_pm_relax()来给wakelock释放锁

如果是要唤醒,则调用_pm_stay_awake()来给wakelock持锁。这里传入的参数都是probe中申请的指向唤醒源设备的指针。

串口发送awk '{ printf("%-32s %d\n", $1, $6) }' /sys/kernel/debug/wakeup_sources指令可以查看当前设备持锁情况

要使设备能进休眠或者唤醒,需要满足两个条件:持锁&&autosleep写mem;释放锁&&autosleep写off。

work函数中完成了持锁释放锁的操作,然后在进休眠时调用netlink_report_suspend,唤醒时调用netlink_report_resume函数:

休眠和唤醒对应不同的msg.id,然后调用odm_notify()函数,携带着对应的msg信息传递到上层去处理。

流程框图如图:

5. 上层处理

上层会根据传递上来的msg,根据不同的msg.id来执行对应的case:

如果是要进休眠,则调用frwk_system函数来给autosleep写mem;如果是要唤醒,则给autosleep写off。

至此,休眠和唤醒各自的两个条件都满足了,就可以实现休眠唤醒功能了。

wakeup_in休眠唤醒相关推荐

  1. 上海域格 1803/1603 平台模块低功耗普通休眠唤醒方法

    1.1 USB 支持 suspend/resume 当主机支持 suspend/resume 时, 可通过以下方式对模块进行休眠唤醒操作. 休眠流程:  发送命令 AT+CSCLK=1 使能模块休眠 ...

  2. android休眠唤醒驱动流程分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/11777501 标准linux休眠过程: l        power managemen ...

  3. 【资源共享】休眠唤醒 开发指南

    本文档介绍了休眠唤醒重要概念及开发指引等内容 下载地址:http://dev.t-firefly.com/thread-13752-1-1.html 更多开发资料请到社区精华系列"资源共享& ...

  4. 2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet)

    2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet) //----------------------------------------------------------- ...

  5. android保持服务不休眠,Android开发保持屏幕常亮和CPU不休眠唤醒状态

    安卓手机 APP 开发,有的时候需要屏幕长时间亮着,也就是不锁屏,这时CPU会一直处于不休眠唤醒状态.下面介绍两种方法. 方法一:通过 PowerManager 实现. 此种方法会在软件安装时用户可以 ...

  6. android 休眠唤醒驱动流程分析,Android4.0.4休眠唤醒机制分析(基于MSM8260)

    当手机满足一定的条件时,会进入休眠状态.从手机进入休眠到唤醒,主要分为三个阶段: early suspend suspend late resume early suspend执行在休眠前需要完成的一 ...

  7. 苹果Mac休眠唤醒后出现死机情况如何解决?

    MacBook AIr进入休眠状态后,从休眠状态唤醒后,鼠标的图标一直处于转动状态,无法登录进入到系统中,出现死机的情况,强行按下电源键后,重启系统才能登录进去.此问题在macOS Catalina ...

  8. 笔记本计算机待机后显示器,Win10笔记本电脑休眠唤醒后屏幕还是黑屏怎么办?...

    一般情况下,如果我们将win10系统笔记本电脑的盖子合上的话,那么会使得笔记本进入休眠状态,而之后可以通过按下键盘上的任意按键使win10恢复工作状态.不过,最近一些朋友反应在笔记本从休眠模式恢复时, ...

  9. 计算机睡眠重启后无法识别网络,教您一招解决电脑休眠唤醒后无法使用USB键盘的操作方法...

    有时,在我们因为情况的需要,就选择进入电脑休眠模式,但是,唤醒电脑后,会发现发现键盘会处于失灵状态,导致无法使用USB键盘,是什么原因呢?遇到这样的问题,有没有什么解决方法呢?为此,小编就给大家带来了 ...

  10. 20.EC实战 笔记本电脑的休眠唤醒是如何实现的

    文章目录 1. EC什么时候(收到什么命令)之后来执行S0-->S3下电时序? 2. S3(休眠)状态应该保留哪些电源? 3. 控制笔记本进入休眠状态的三种方式 总结: 前言: 最近很多朋友在咨 ...

最新文章

  1. Unity3D第三人称摄像机控制脚本
  2. wpf控件设计时支持(1)
  3. SQL:postgresql查询结果加一个自定义的列
  4. x265源码流程分析
  5. 2022年低压电工考试及低压电工模拟考试题库
  6. epoll原理详解及epoll反应堆模型
  7. react 学习与使用记录
  8. Maven下载安装及修改setting内容
  9. winform右下角弹窗
  10. linux 程序网速监控软件,Linux实时网速监控软件ifstat简易教程
  11. ghost服务器系统镜像文件,带RAID服务器能GHOST备份吗?
  12. 林轩田机器学习基石5笔记:训练和测试的不同
  13. Cocos2D-X Tutorial for iOS and Android: Getting Started
  14. 正好杠杆炒股五粮液主力资金净流入居首
  15. 又有12款APP违规收集用户信息,下架整改
  16. 路由器VRF多个虚拟路由器测试
  17. 2D - 2D 点对 求解基础矩阵 F 本质矩阵E 单应矩阵 H 进而求 旋转矩阵 R 和 t
  18. 母亲从大专到考上985高校全日制博士,成了儿子的“学妹”
  19. matlab动态文字,matlab GUI界面文字动态显示
  20. 微信小程序 发布新版本后 强制升级

热门文章

  1. 浙江行游14---千岛湖,清凉的世界里
  2. python矩阵运算算法_Python常用库Numpy进行矩阵运算详解
  3. 2022 火狐插件 Tamper Data 下载安装使用教程
  4. 云服务器+Dock+搭建个人博客网站
  5. C++ 产生0-1之间的随机数
  6. 【课程·研】工程伦理学 | 课堂汇报:个性化推荐技术的伦理学——以平台广告精准投放事件为例
  7. 微客侠:解决微信内直接打开淘宝链接
  8. windows自带的文件校验工具MD5,SHA1,SHA256
  9. 2进制原码反码补码,2进制加减乘除原理
  10. 基于网页的微信小程序——摇色子