如何设置通过PMU的gpio来唤醒linux gpio子系统详解

驱动移植(26)
RockChip平台(8)
Android5.1
pmic 电路原理
电源分为两种:
DCDC:输入输出压差大时,效率高,但是有纹波问题,成本高,所以大压差,大电流时使用。
LDO:输入输出压差大时,效率低,成本低。
为了提高 LDO 的转换效率,系统上会进行相关优化如:
LDO 输出电压为 1.1V,为了提高效率,其输入电压可以从 VCCIO_3.3V 的 DCDC 给出。
所以电路上如果允许尽量将 LDO 接到 DCDC 输出回路,但是要注意上电时序。
DCDC 一般有两种工作模式:
PWM–纹波瞬态响应好,效率低;
PFM:效率高,但是负载能力差。
RICO619(5路DCDC)
各模块需要供电:
VCCIO 3.3V
LOGIC 1.0V(分立 PWM)
Logic 需要动态调压,如果采用分立DCDC(PWM),调节精度、输出电压一致性不能保证。
双电池 ACT8846 + SYR82X
单电池 RK808 或者 RICOH619 + SYR82X
(本方案采用的 RK808)
开机流程:
当有接适配器时。
VDC 电压 升高; VSYS 上电; PMIC 上电并输出。
当只接电池时,按开机键。
PWRON 拉高; PMIC 上电并输出。PMIC 启动,实现 EPROM 中的默认设置,各路上电完成后,发送 reset 信号,芯片上电,系统启动,PMIC 设备挂载,通过I2C 重新配置 PMIC。
PWM 即通过占空比设置电压。
计算占空比:
利用 pwm_regulator_set_voltage 将设置的电压转换成占空比
pwm_value = (max - vol)/coefficient/10
//计算占空比,max 及 coefficient 由板级传参
设置占空比:
在rockchip-pwm-regulator.c中pwm_set_rate()
RATE为0时设置PWM为GPIO口输出低,控制LOGIC电压最高(1.4V)。
RATE为100时设置PWM为GPIO口输出高,控制LOGIC电压最低(0.9V)。
RATE在0~100之间:
根据当前PWM的CLK计算高电平和低电平的值,然后写到PWM控制寄存器中即可
其驱动方面需要按特定流程,先将 PWM 控制器 disable 并且 RESET,然后设置,最后 enable。
先看 rk808.dtsi
rk808_dcdc1_reg: regulator@0 {
reg = &0&;
regulator-compatible = "rk_dcdc1";
regulator-min-microvolt = &700000&;
regulator-max-microvolt = &1500000&;
regulator-initial-mode = &0x2&;
regulator-initial-state = &3&;
regulator-state-mem {
regulator-state-mode = &0x2&;
regulator-state-disabled;
regulator-state-uv = &900000&;
再看 rk3288-tb_8846.dts
/include/ "rk808.dtsi"
gpios =&&gpio0 GPIO_A4 GPIO_ACTIVE_HIGH&,&&gpio0 GPIO_B3 GPIO_ACTIVE_LOW&;
rk808,system-power-
regulators {
rk808_dcdc1_reg: regulator@0{
regulator-name= "vdd_arm";
//驱动根据这个name 设置 PMU 电压、工作模式、使能。不可重名。
regulator-always-
//表示常开
regulator-boot-
regulator_ops 注册,完成 PMU 驱动与 regulator 之间链接:
kernel/drivers/regulator/
完成 regulator_ops 的注册后,可以使用 regulator 的接口了。(regulator_set_voltage)
用 PWM 调整外挂 DCDC 电压,注册 PWM 驱动
pwm_regulator {
compatible = "rockchip_pwm_regulator";
pwms = &&pwm1 0 2000&;
rockchip,pwm_id= &1&;
rockchip,pwm_voltage_map= &925000 950000 975000 1000000 1025000 1050000 1075000 1100000 1125000 1150000 1175000 1200000 1225000 1250000 1275000 1300000 1325000 1350000 1375000 1400000&;
rockchip,pwm_voltage= &1000000&;
rockchip,pwm_min_voltage= &925000&;
rockchip,pwm_max_voltage= &1400000&;
rockchip,pwm_suspend_voltage= &950000&;
rockchip,pwm_coefficient= &475&;
regulators {
#address-cells = &1&;
#size-cells = &0&;
pwm_reg0: regulator@0 {
regulator-compatible = "pwm_dcdc1";
regulator-name= "vdd_logic";
regulator-min-microvolt = &925000&;
regulator-max-microvolt = &1400000&;
regulator-always-on;
regulator-boot-on;
并且打开 PWM 口
status = "okay";
menuconfig
相关的两个宏打开
修改各路 DCDC 和 LDO
方法一,修改dts
通过设置 dts 里面的
regulator-min-microvolt = & 3300000&;
regulator-max-microvolt = &3300000&;
pwm_regulator {
rockchip,pwm_voltage= &1000000&;
来设置默认电压。
方法二,运行中动态设置
Struct regulator *
dcdc =regulator_get(NULL, "name");
regulator_set_voltage(dcdc, min_uv, max_uv);
regulator_enable(dcdc);
regulator_put(dcdc);
设置 DCDC 工作模式接口
DCDC 有两种模式(PWM、PFM)。
有一种 Auto 模式会自动调整 PWM、PFM。
所以我们常说的两种模式是 PWM 和 AUTO(PWM+PFM)。
AUTO 模式 效率高、纹波瞬态响应差。
现在一般都 PWM 模式。
方法一,初始化设置
regulator-initial-mode& 0x2 &
方法二,运行下切换
dcdc = regulator_get(NULL, "name");
regulator_set_mode(dcdc, REGULATOR_MODE_STANDBY);
//pwm:REGULATOR_MODE_NORMAL pfm: REGULATOR_MODE_STANDBY
ldo =regulator_get(NULL, "act_ldo1");
regulator_enable(ldo);
调试流程与碰到的问题
开机打印 PMU 注册失败,提示 i2c 通信失败,或者直接跑飞
1)测试 i2c 的 CLK 和 data 数据线是否被拉低;
2)核对 i2c 有没有注册错,使用的 i2c 是否跟平台
3)i2c 上是否还有其他设备;
4)测试 PMIC 的各路默认的上电电压是否正确;
5)测试Power_hold 是否为高;
6)测试 PMIC 默认上电完成后 reset 信号是否发送;
7)PMIC 外围部件是
否焊接错误,例如晶振有没有焊反,电感、电容等有没有焊错。
系统运行中死机
1)测试死机时各路的电压,是否有电压异常;
2)测试 DVFS 调整是否正常;
3)测试 arm、logic、DDR、VCCIO 的电压的纹波等,看下在系统异常时是否有明显的电压塌陷。
3 、待机唤醒死机
1)测试 PMU_sleep 脚已经恢复成低;
2)测试各路电压已经从待机电压恢复回来;
3)用示波器测试唤醒时各路电压的的变化波形,有无异常;4)sleep 状态不去关闭电源。不降低电压;
Reset 后无法开机或者某些设备异常
如果出现此问题,请参考本文第三章 pmic 的关机及复位。
Reset 按下时,芯片复位,各个 io 口恢复成默认值,如果 PMU 没有复位功能或者没有完成硬复位,
则 PMU 不会被复位,则无法完成 PMU 的断电并重新上电,这样可能会导致部分设备重启后工作
不正常。(部分项目上发现有些设备在复位时必须要掉电,否则会工作异常)
RTC 无法正常写入
1)如果 PMU 是 act8846(不带 RTC)此时要看下 RTC 设备是否挂载正常;2)PMU 设备的 i2c
通信是否正常
运行时部分 LDO 没有输出
1)确认此 LDO 在其他地方没有被关闭,通过搜索此 LDO 的 name (使用此接口 regulator_disable());
2)测试 PMIC_SLEEP 脚是不是为高,如果为高,PMU 已经进入休眠模式,部分 LDO 会被关闭。
PMIC_SLEEP 脚的配置应该是不对的,需要配置此 io 口:见本文档 1.2 章(注意:硬件上此 io 口,
最好没有复用功能,而且是应该是默认内部下拉口)
关机后随机性的自动开机或者关机失败
关机失败:device_shutdown()中会通过 i2c 写关机命令,i2c 通信失败,无法写关机命令。如果遇到此问题。加一些保护锁,如果一直写失败,直接重启。
关机后自动开机:因为 RTC 闹铃具有开机的功能,在关机后如果 RTC 闹铃产生,即会触发开机条
件而开机。目前已经解决过了,在关机函数中先关闭 RTC 闹铃的中断,在开机时再打开中断。
待机时随机性被唤醒
如果唤醒中断是 PMIC_INT,那么应该是 PMU 的 RTC 闹铃在唤醒系统。除了用户设置的闹铃外,
还有一些谷歌的应用会产生 RTC 闹铃,需要移除相应的应用。查看方法如下:
请客户在命令行中敲入 dumpsys alarm 来查看当前系统的 alarm 申请情况。
android 总共有4种类型 alarm,其中只有2种 alarm 会在休眠唤醒系统,请在相关信息中查找对应的
第三方软件。
这两种分别是 ELAPSED_WAKEUP 和 RTC_WAKEUP。
我们观察到,凡是带了谷歌相关的 apk 就会申请相关 alarm,如下:
RTC_WAKEUP #5: Alarm{ type 0 com.google.android.gsf}
type=0 when=+5d17h1m54s609ms repeatInterval= count=0
operation=PendingIntent{: PendingIntentRecord{413ce158
com.google.android.gsf broadcastIntent}}
注意:此唤醒动作只在二级待机,不会到一级待机唤醒,点亮屏,如果点亮了屏,应该是屏那边没有进
RICOH619无法开机或者开机后电量显示异常
确认电池包上 TS 端是否有10K 电阻,如果没有,请确认板子上 TS 端对地有10K 电阻。如果没有10K
电阻,PMIC 默认电池是不存在的。
RICOH619充电异常,充电电流多小,或者充电充不满
充电电流过小:
我们上电有默认的充电电流,USB:500MA , ADP :1A,开机后 USB 根据枚举结果通过 I2C
重新设置充电电流,最大可设置 3A(一般推荐到 2A),ADP 电流开机后就会修改,最大 3A。
实际往电池充的电流跟设置电流会有一些不一样,有充电效率的关系。详细见下:
ILIM_USB/ILIM_ADP 的设置值 限制 USB/ADP 输入时 VSYS 系统输出的电流极限最大
限流。 ( 实际限制的输出值 大约在 设置值 的 90% 左右 )
因为 工作方式是 DCDC 的关系, 实际的输入电流会小于输出电流。
( 功率转换:理想情况下 输入 5V x 1A
5V = VADP, 1A = I_ADP,
4V = VSYS,
=4V * 1.25A )
ILIM_ADP = 1.25A.
另外,限制电流的侦测方式是 由 ILM, ILP 间的 Sense 电阻 压降而得到。
( ILM , ILP 端口需要直接采集 电阻( 20mohm ) 上的 压降,需要注意版图画法)
关于流入电池的电流 可以 查看一下 ICM , ICP 之间的 Sense 电阻的压降来判断。
当然,也需要小心制版时, PMU 的 ICM, ICP 是否取到的直接时 电阻两端的电压。
1.5A 设置 输入限流, 实际输出限制 大约 1.3A 以上。
( 可通过 检测 ILM /
ILP 间 电阻压降 )
由于是 DCDC 工作的方式,
IUSB= VSYS * I_SYS
V_USB * I_USB * 效率 = VSYS * I_SYS / (V_USB * 效率 )
= 4.0 * 1.3 / ( 5 * 0.9 )
= 1.1A ( 约 )
充电充不满:
充电有充电时间的限制,一般是充电 5 小时就会关闭充电,所以存在一边使用一边充电时电池充
不满,这个问题我们后期会使用软件解决。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:57703次
积分:1268
积分:1268
排名:千里之外
原创:78篇
(3)(9)(4)(9)(5)(7)(6)(12)(11)(3)(2)(3)(14)S5PV210 Android2.3 添加自定义按键:作唤醒功能 - Wince.Android的日志 -
电子工程世界-论坛
S5PV210 Android2.3 添加自定义按键:作唤醒功能
已有 1995 次阅读 11:15
最近需要做个唤醒功能,当按键的时候android系统唤醒并点亮屏,在长按键中,系统不能在进入睡眠。驱动方面:1:在平台设备文件中添加 一个按键,定义为唤醒源\\arch\\arm\\mach-s5pv210[cpp]
static struct gpio_keys_button gpio_buttons[] = {&&&&& & {&&&&.gpio&&= S5PV210_GPH1(3),&&& &.code&&= KEY_F22,&&//对应 192& && &.desc&&= \"F22\",&&& &.active_low = 1,&&& &.wakeup&&= 1,&&& &.debounce_interval =100, //去抖动&&& & },&&&&}&&static struct gpio_keys_platform_data gpio_button_data = {&& .buttons = gpio_buttons,&& .nbuttons = ARRAY_SIZE(gpio_buttons),&&};&&&&static struct platform_device s3c_device_gpio_button = {&& .name&&= \"gpio-keys\",&& .id&&= -1,&& .num_resources = 0,&& .dev&&= {&&&&.platform_data = &gpio_button_data,&& }&&};&&&&platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices));&&
2:添加驱动\\kernel-v.\\drivers\\input\\keyboard\\s3c-gpio-keys.c [cpp]
struct s3c_gpio_key{&&& &&&& &&&& &&&& &&&};&&&&struct s3c_gpio_key s3c_gpio_keys[]=&&{& &&&& && &&&///*&&& && &{& && && && && &&&.pin = S5PV210_GPH1(3), //at base wake up&&& && && && &&&.eintcfg = 0X0f<<12,& && &&&& && && && &&&.inputcfg = 0<<12,&&& && && && &&&.eint = IRQ_EINT11,&&& && &},&&& && &&&& &&&// */&&};&&
//申请中断为上/下沿出发方式。[cpp]
error = request_irq(s3c_gpio_keys.eint, gpio_keys_isr,&&& && &&&IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |&&& && &&&IRQF_TRIGGER_FALLING,&&& && &&&button->desc ? button->desc : \"gpio_keys\",&&& && &&&bdata);&&
static void gpio_keys_report_event(struct gpio_button_data *bdata)&&{&&& & struct gpio_keys_button *button = bdata->&&& & struct input_dev *input = bdata->&&& & unsigned int type = button->type ?: EV_KEY;&&&&& & int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_&&& & //add by xiao@:for wake up mid when it on base.&&& & //上报事件处理下,因会发生系统唤醒后,又马上进入睡眠,造成一种假唤醒状态,所以当按键时,不时上报此事件来唤醒系统&&& & if(button->code == 192){&&& && &&&if(state)&&& && && &&&mod_timer(&bdata->timer,&&& && && && &jiffies + msecs_to_jiffies(button->debounce_interval + 300));&&& & }&&& & input_event(input, type, button->code, !!state);&&& & input_sync(input);&&& & #ifdef key_debug&&& & printk(\"gpio_keys_report_event->code =%d, state = %d\\n\",button->code,state);&&& & #endif&&}&&
驱动按键添加完成,内核能唤醒,但是android系统屏并不会点亮,所以需要修改源码,让系统服务获取到此按键并作一些处理。1:首先看下键值表:\\out\\target\\product\\smdkv210\\system\\usr\\keylayout[cpp]
qwerty.kl&&& &# On an AT keyboard: ESC, F10&& key 1& &&&BACK& && && && &&&WAKE_DROPPED&& key 68& & MENU& && && && &&&WAKE_DROPPED&&& &# on base wake up mid&& key 192& &&&NULL& && && &WAKE_DROPPED& &//需要添加的键NULL。WAKE_DROPPED:唤醒并点亮屏。& &
第一列:key
第二列: SCANCODE是一个整数,是驱动里面定义的,在文件./kernel/include/linux/input.h
第三列: KEYCODE 是一个字串,定义在你描述的布局文件frameworks/base/include/ui/KeycodeLabels.h
另外可以设置相关的FLAGS:
SHIFT: 当按下,自动加上SHIFT键值
ALT:当按下,自动加上ALT
CAPS:当按下,自动带上CAPS大写
WAKE:当按下,当设备进入睡眠的时候,按下这个键将唤醒,而且发送消息给应用层。
WAKE_DROPPED:当按下,且设备正处于睡眠,设备被唤醒,但是不发送消息给应用层。
2:./frameworks/base/include/ui/keycodeLabels.h[cpp]
static const KeycodeLabel KEYCODES[] = {&&& &&&{ \"BUTTON_MODE\", 110 },&&& &&&{ \"NULL\", 111 }, //在最后添加NULL按键, 键值为111 ,后续android根据键值来映射。& && && &&&// NOTE: If you add a new keycode here you must also add it to several other files.&&& &&&//& && & Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.&&& && & { NULL, 0 }&& };&&
3: ./ frameworks/base/native/include/android/Keycodes.h&&[cpp]
enum {&&& &&&AKEYCODE_BUTTON_MODE& &&&= 110,&&& &&&AKEYCODE_NULL& &&&= 111, //& &&&当keyevent处理按键事件时,isSystemKey 判断是否为系统按键才会继续上报上层,所以需要添加进去。&&& &&&// NOTE: If you add a new keycode here you must also add it to several other files.&&& &&&//& && & Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.&& };&&
./frameworks/base/libs/ui/input.java 同时 isSystemKey() 也要添加:[cpp]
bool KeyEvent::isSystemKey(int32_t keyCode) {&&& &&&switch (keyCode) {&&& && && &case AKEYCODE_FOCUS:&&& && && &case AKEYCODE_SEARCH:&&& &case AKEYCODE_NULL: // add by xiao@&&& && && && &&&& &&&}&&& && & & &&& }&&
4: ./frameworks/base/core/java/android/view/KeyEvent.java[cpp]
//根据键值 映射 为 KEYCODE_BUTTON_NULL&&,为PhoneWindowManager.java 提供按键目标。&&& &&&public static final int KEYCODE_BUTTON_NULL& &&&= 111;&&
同时 这也修改:[cpp]
private static final int LAST_KEYCODE& && && &&&= KEYCODE_BUTTON_NULL;&&
5:./frameworks/base/core/res/res/values/attrs.xml[cpp]
通过以上的更改,新的键值就添加上去了,由于更改了 KeyEvent,影响到了API, 所以需要make update-api这样系统就会获取到这个NULL按键,并能够点亮屏幕了。如果对新键值进行处理,可以通过获取相应的keycode,对它进行处理;对于按键事件的处理一般如下文件中
frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.javainterceptKeyBeforeQueueing函数中处理。[java]
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,&&& && && &&&int policyFlags, boolean isScreenOn) {&&&&&&& & //add by xiao@ :wakeup mid when it on base,&&& & else if(keyCode == KeyEvent.KEYCODE_BUTTON_NULL){ //获取NULL按键,不让系统进入睡眠状态,释放按键时,进入可睡眠。&&& && &&&if(down){&&& && && && &if(IS_MID_ONBASE == false)&&& && && && &{&&& && && && && & IS_MID_ONBASE =&&& && && && && & mBroadcastWakeLock.acquire();&&& && && && && & Log.e(TAG,\"MID WAKE UP button: DOwn\");&&& && && && &}&&& && &&&}else{&&& && && && &IS_MID_ONBASE =&&& && && && &mBroadcastWakeLock.release();&&& && && && &Log.e(TAG,\"MID WAKE UP button: release\");&&& && &&&}&&& & }&&&&& &&&}&&
作者的其他最新日志
评论 ( 个评论)
Powered by创新的ATPAK P沟道功率MOSFET
条件监测是预测性维护的重要组成部分。本研讨会重点介绍MEMS加速度计技术给条件监测应用带来的好处。其中会讨论MEMS的固有特性,正是这些特性使得MEMS格外有吸引力,而其他技术相形见绌。另外还会比较当今常用的加速度计技术,评述其性能上的进步。 ADI &&&&日&&&&linux内核中的GPIO系统之(1):软件框架
作为一个工作多年的系统工程师,免不了做两件事情:培训新员工和给新员工分配任务。对于那些刚刚从学校出来的学生,一般在开始的时候总是分配一些非常简单的任务,例如GPIO driver、LED driver。往往CPU datasheet的关于GPIO或者IO ports的章节都是比较简单的,非常适合刚入行的工程师。虽然GPIO子系统相关的硬件比较简单,没有复杂的协议,不过,对于软件抽象而言,其分层次的软件思想是每个嵌入式软件工程师需要掌握的内容。
我更倾向使用GPIO系统这个名字来代替GPIO driver这个名字,GPIO driver仅仅包含了pin signal状态控制和读取的内容,而GPIO系统包括了pin multiplexing、pin configuration、GPIO control、GPIO interrupt control等内容。本文主要是以3.14内核作为例子,讲述linux kernel中GPIO系统的软件框架。
二、GPIO相关硬件有哪些差异
嵌入式工程师总是要处理各种各样的target board,每个target board上的GPIO总是存在不同,例如:
1、和CPU的连接方式不同
对于ARM的嵌入式硬件平台,SOC本身可以提供大量的IO port,SOC上的GPIO controller是通过SOC的总线(AMBA)连接到CPU的。对于嵌入式系统而言,除了SOC的IO port,一些外设芯片也可能会提供IO port,例如:
(1)有些key controller芯片、codec或者PMU的芯片会提供I/O port
(2)有些专用的IO expander芯片可以扩展16个或者32个GPIO
从硬件角度看,这些IO和SOC提供的那些IO完全不同,CPU和IO expander是通过I2C(也有可能是SPI等其他类型的bus)连接的,在这种情况下,访问这些SOC之外的GPIO需要I2C的操作,而控制SOC上的GPIO只需要写寄存器的操作。不要小看这个不同,写一个SOC memory map的寄存器非常快,但是通过I2C来操作IO就不是那么快了,甚至,如果总线繁忙有可能阻塞当前进程,这种情况下,内核同步机制必须有所区别(如果操作GPIO可能导致sleep,那么同步机制不能采用spinlock)。
2、访问方式不同
SOC片内的GPIO controller和SOC片外的IO expander的访问当然不一样,不过,即便都是SOC片内的GPIO controller,不同的ARM芯片,其访问方式也不完全相同,例如:有些SOC的GPIO controller会提供一个寄存器来控制输出电平。向寄存器写1就是set high,向寄存器写0就是set low。但是有些SOC的GPIO controller会提供两个寄存器来控制输出电平。向其中一个寄存器写一就是set high,向另外一个寄存器写一就是set low。
3、配置方式不同
即便是使用了同样的硬件(例如都使用同样的某款SOC),不同硬件系统上GPIO的配置不同。在一个系统上配置为输入,在另外的系统上可能配置为输出。
4、GPIO特性不同。这些特性包括:
(1)是否能触发中断。对一个SOC而言,并非所有的IO port都支持中断功能,可能某些处理器只有一两组GPIO有中断功能。
(2)如果能够触发中断,那么该GPIO是否能够将CPU从sleep状态唤醒
(3)有些有软件可控的上拉或者下拉电阻的特性,有的GPIO不支持这种特性。在设定为输入的时候,有的GPIO可以设定debouce的算法,有的则不可以。
5、多功能复用
有的GPIO就是单纯的作为一个GPIO出现,有些GPIO有其他的复用的功能。例如IO expander上的GPIO只能是GPIO,但是SOC上的某个GPIO除了做普通的IO pin脚,还可以是SPI上clock信号线。
三、硬件功能分类
ARM based SOC的datasheet中总有一个章节叫做GPIO controller(或者I/O ports)的章节来描述如何配置、使用SOC的引脚。虽然GPIO controller的硬件描述中充满了大量的寄存器的描述,但是这些寄存器的功能大概分成下面三个类别:
1、有些硬件逻辑是和IO port本身的功能设定相关的,我们称这个HW block为pin controller。软件通过设定pin controller这个硬件单元的寄存器可以实现:
(1)引脚功能配置。例如该I/O pin是一个普通的GPIO还是一些特殊功能引脚(例如memeory bank上CS信号)。
(2)引脚特性配置。例如pull-up/down电阻的设定,drive-strength的设定等。
2、如果一组GPIO被配置成SPI,那么这些pin脚被连接到了SPI controller,如果配置成GPIO,那么控制这些引脚的就是GPIO controller。通过访问GPIO controller的寄存器,软件可以:
(1)配置GPIO的方向
(2)如果是输出,可以配置high level或者low level
(3)如果是输入,可以获取GPIO引脚上的电平状态
3、如果一组gpio有中断控制器的功能,虽然控制寄存器在datasheet中的I/O ports章节描述,但是实际上这些GPIO已经被组织成了一个interrupt controller的硬件block,它更像是一个GPIO type的中断控制器,通过访问GPIO type的中断控制器的寄存器,软件可以:
(1)中断的enable和disable(mask和unmask)
(2)触发方式
(3)中断状态清除
四、如何通过软件抽象来掩盖硬件差异
传统的GPIO driver是负责上面三大类的控制,而新的linux kernel中的GPIO subsystem则用三个软件模块来对应上面三类硬件功能:
(1)pin control subsystem。驱动pin controller硬件的软件子系统。
(2)GPIO subsystem。驱动GPIO controller硬件的软件子系统。
(3)GPIO interrupt chip driver。这个模块是作为一个interrupt subsystem中的一个底层硬件驱动模块存在的。本文主要描述前两个软件模块,具体GPIO interrupt chip driver以及interrupt subsystem请参考本站其他相关文档。
1、pin control subsystem block diagram
下图描述了pin control subsystem的模块图:
底层的pin controller driver是硬件相关的模组,初始化的时候会向pin control core模块注册pin control设备(通过pinctrl_register这个bootom level interface)。pin control core模块是一个硬件无关模块,它抽象了所有pin controller的硬件特性,仅仅从用户(各个driver就是pin control subsystem的用户)角度给出了top level的接口函数,这样,各个driver不需要关注pin controller的底层硬件相关的内容。
2、GPIO subsystem block diagram
下图描述了GPIO subsystem的模块图:
基本上这个软件框架图和pin control subsystem是一样的,其软件抽象的思想也是一样的,当然其内部具体的实现不一样,我们会在后续的文章中描述。
原创文章,转发请注明出处。蜗窝科技。

我要回帖

更多关于 linux gpio子系统详解 的文章

 

随机推荐