wakeup_in休眠唤醒
问题背景:实现一个休眠唤醒的功能,并可控制的使单板进入休眠或者唤醒的状态(管脚拉低进入休眠状态,拉高恢复)。以此来达到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休眠唤醒相关推荐
- 上海域格 1803/1603 平台模块低功耗普通休眠唤醒方法
1.1 USB 支持 suspend/resume 当主机支持 suspend/resume 时, 可通过以下方式对模块进行休眠唤醒操作. 休眠流程: 发送命令 AT+CSCLK=1 使能模块休眠 ...
- android休眠唤醒驱动流程分析【转】
转自:http://blog.csdn.net/hanmengaidudu/article/details/11777501 标准linux休眠过程: l power managemen ...
- 【资源共享】休眠唤醒 开发指南
本文档介绍了休眠唤醒重要概念及开发指引等内容 下载地址:http://dev.t-firefly.com/thread-13752-1-1.html 更多开发资料请到社区精华系列"资源共享& ...
- 2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet)
2440 休眠唤醒的实现过程(作者:wogoyixikexie@gliet) //----------------------------------------------------------- ...
- android保持服务不休眠,Android开发保持屏幕常亮和CPU不休眠唤醒状态
安卓手机 APP 开发,有的时候需要屏幕长时间亮着,也就是不锁屏,这时CPU会一直处于不休眠唤醒状态.下面介绍两种方法. 方法一:通过 PowerManager 实现. 此种方法会在软件安装时用户可以 ...
- android 休眠唤醒驱动流程分析,Android4.0.4休眠唤醒机制分析(基于MSM8260)
当手机满足一定的条件时,会进入休眠状态.从手机进入休眠到唤醒,主要分为三个阶段: early suspend suspend late resume early suspend执行在休眠前需要完成的一 ...
- 苹果Mac休眠唤醒后出现死机情况如何解决?
MacBook AIr进入休眠状态后,从休眠状态唤醒后,鼠标的图标一直处于转动状态,无法登录进入到系统中,出现死机的情况,强行按下电源键后,重启系统才能登录进去.此问题在macOS Catalina ...
- 笔记本计算机待机后显示器,Win10笔记本电脑休眠唤醒后屏幕还是黑屏怎么办?...
一般情况下,如果我们将win10系统笔记本电脑的盖子合上的话,那么会使得笔记本进入休眠状态,而之后可以通过按下键盘上的任意按键使win10恢复工作状态.不过,最近一些朋友反应在笔记本从休眠模式恢复时, ...
- 计算机睡眠重启后无法识别网络,教您一招解决电脑休眠唤醒后无法使用USB键盘的操作方法...
有时,在我们因为情况的需要,就选择进入电脑休眠模式,但是,唤醒电脑后,会发现发现键盘会处于失灵状态,导致无法使用USB键盘,是什么原因呢?遇到这样的问题,有没有什么解决方法呢?为此,小编就给大家带来了 ...
- 20.EC实战 笔记本电脑的休眠唤醒是如何实现的
文章目录 1. EC什么时候(收到什么命令)之后来执行S0-->S3下电时序? 2. S3(休眠)状态应该保留哪些电源? 3. 控制笔记本进入休眠状态的三种方式 总结: 前言: 最近很多朋友在咨 ...
最新文章
- Unity3D第三人称摄像机控制脚本
- wpf控件设计时支持(1)
- SQL:postgresql查询结果加一个自定义的列
- x265源码流程分析
- 2022年低压电工考试及低压电工模拟考试题库
- epoll原理详解及epoll反应堆模型
- react 学习与使用记录
- Maven下载安装及修改setting内容
- winform右下角弹窗
- linux 程序网速监控软件,Linux实时网速监控软件ifstat简易教程
- ghost服务器系统镜像文件,带RAID服务器能GHOST备份吗?
- 林轩田机器学习基石5笔记:训练和测试的不同
- Cocos2D-X Tutorial for iOS and Android: Getting Started
- 正好杠杆炒股五粮液主力资金净流入居首
- 又有12款APP违规收集用户信息,下架整改
- 路由器VRF多个虚拟路由器测试
- 2D - 2D 点对 求解基础矩阵 F 本质矩阵E 单应矩阵 H 进而求 旋转矩阵 R 和 t
- 母亲从大专到考上985高校全日制博士,成了儿子的“学妹”
- matlab动态文字,matlab GUI界面文字动态显示
- 微信小程序 发布新版本后 强制升级
热门文章
- 浙江行游14---千岛湖,清凉的世界里
- python矩阵运算算法_Python常用库Numpy进行矩阵运算详解
- 2022 火狐插件 Tamper Data 下载安装使用教程
- 云服务器+Dock+搭建个人博客网站
- C++ 产生0-1之间的随机数
- 【课程·研】工程伦理学 | 课堂汇报:个性化推荐技术的伦理学——以平台广告精准投放事件为例
- 微客侠:解决微信内直接打开淘宝链接
- windows自带的文件校验工具MD5,SHA1,SHA256
- 2进制原码反码补码,2进制加减乘除原理
- 基于网页的微信小程序——摇色子