一、关于电流偏大的问题,这里总结一下一般的调试步骤

1.如果底电流大于10ma以上的,首先需要抓串口log确定系统是否有睡眠,是否有外设一直在运行;从log中可以看有没有发生suspend,看state(0->3)是否有发生,如果有这些log,而且后面没有state(3->0)那说明睡下去了。首先请去掉所有的APK测试,看平均功耗是否有问题,如果跟去掉APK之前一样,说明跟APK没有关系
如果跟去掉APK之前相比,功耗有所降低,说明跟APK有一定的关系跟APK有关系,请自行分析APK。

2.从log确定系统正常睡眠的话,就开始逐个外设排除(排除顺序屏/backlight /wifi/bt/sensor/gps/camera/atv),最好采用硬软件结合,硬件上去除芯片软件上去除驱动,同时将相关的输出的io口pinmap配置为高阻状态。

3.排除外设漏电情况后需要继续排除gpio漏电,方法是修改pinmap配置,特别需要关注与样机使用有差异的gpio。同时如果i2c电路外围有上拉,排除是否有漏电可能性。这需要结合硬件原理图。为方便测试,可使用工具lookat,具体请参考文档《 lookat使用说明.txt 》.

4.排除板子上所有外围下拉电容(与电池电压VBAT相关的),下拉二极管等,这需要硬件人员协助,主要是排除可能贴错了料或者器件偏位等PCBA问题,导致漏电。


5.排除memory漏电的可能性,一般确定是否是认证类型芯片、更换芯片尝试等

6.测量睡眠时BB芯片每个ldo的电压,确定是否有电压,电压值是否正常,最后可以对ldo进行灌电流(高于其输出电压对其供电)确定是否有漏电情况。


7. 总体来说,调底电流主要分为粗调和细调两部分,对于粗调和细调并没有非常明显的界线,一般来说,当底电流大于10mA,或者大于20mA的时候需要进行的是粗调,当底电流小于10mA,但是比参考对比机要大出几个mA的时候就要开始进行细调了,
细调的定位和调试可能比粗调要复杂些。
(1)粗调,当拿到一块调试板,开始调试驱动的时候,粗调底电流就开始了,刚开始,我们一般都会先烧代码进去,看系统是否起来,看起来的过程中电流的大小,
如果能启动,过程中电流也不是特别大的话,一边就会开始调试屏,背光,touch之类的驱动,backlight是耗电大户,曾有一客户,亮屏的时候电流大近150mA,一摸板子,backlight烫得不敢摸,这是驱动跟芯片不匹配导致。Wifi/bt一般至少二合一,也是很容易产生耗电,最近的trout芯片,打开wifi待机要近30mA的电流,问题是如果去掉trout芯片还开不了机,我当时想了个办法,就是trout的供电做一个活动开关,正常时候打开,需要关闭的时候可以活动把它关闭,这样可以更好的测电流。诸如此类情况很多,具体的板子需要具体分析。
(2)细调,当底电流调到一定程度,软件上也都ok了,底电流如果还是大于参考机几个毫安,那这个时候就开始要细调了,首先要将gpio设置为高阻态,一些总线的上下拉,如I2C上拉,还有如二极管,电感等,这些主要是防止存在压差,有压差一定会存在漏电,另外每一个ldo都要进行确认,防止其漏电,主要测量压差及灌电流来确认。细调是一个系统的概念,需要对软硬件有一个比较深入的理解。


二、AP 睡不下去的各种情况

如果底电流大于10mA,很有可能是系统没办法睡下去。AP睡不下去可以分为一直睡不下去和偶尔会被中断或者其他外设唤醒。


1. 对于AP会被中断wakeup的情况:

(1)看中断号是多少,对比irqs.h里面的中断,再对比原理图和spec,确认是哪个模块产生中断,进而查找中断原因。例如:


侧键中断,如果手机放口袋里,总是会碰到侧键,这样会产生中断,进而产生不必要的功耗,并让机器持续发烫。
可做以下简单修改

static int sci_keypad_suspend(struct platform_device *dev, pm_message_t state)
{
keypad_writel(KPD_INT_EN, 0);
return 0;
}
static int sci_keypad_resume(struct platform_device *pdev)
{
keypad_writel(KPD_INT_EN, KPD_INT_ALL);
return 0;
}



请在按键中断驱动中,做以下修改
suspend时,将KPD_INT_EN寄存器清o
resume时,执行probe里面enable动作。
下面是参考代码

{
value = KPD_INT_DOWNUP;

if (pdata->support_long_key)
value |= KPD_INT_LONG;
keypad_writel(KPD_INT_EN, value);
}

(2)定时器中断。很多第三方应用都有这个情况,比如qq等,微信,来往等第三方实时通信软件,这些软件会设定唤醒系统,定时器中断增加平均功耗,当你待机后去测试,是正常的,但放那里待机一晚上,电没了,就是这种情况。(想解决这个问题的话一般只能把wifi和数据给关了)

2. 对于AP根本无法睡眠的情况,一般都是wake lock锁所导致:android的AP 电源管理方案使用Google的wake_lock机制. 在内核中维护了一个wake_lock的链表,如果有应用或者内核模块希望系统不要进入睡眠就可以申请wake_lock,这时就会在wake_lock链表中增加一项,在释放wake_lock后就会删除链表中相应的项.
AP进入suspend前会判断当前是否有活动的wake_lock,如果有则AP不会进入suspend状态。(关于modem详见下面(1)描述)

(1)导致AP不能进睡眠原因 
AP 电源管理方案使用Google的wake_lock机制. 在内核中维护了一个wake_lock的链表,如果有应用或者内核模块希望系统不要进入睡眠就可以申请wake_lock,这时就会在wake_lock链表中增加一项,在释放wake_lock后就会删除链表中相应的项。
AP进入suspend前会判断当前是否有活动的wake_lock,如果有则AP就不会进入suspend状态.
由于modem相对较稳定,目前碰到系统不能进入睡眠的原因主要是由于AP有wake_lock没有释放导致AP没有进入suspend造成的。

(2)查看什么申请了wake_lock导致系统不能睡眠
所有的进程(也包括workqueue/kthread) 都已经停止了,内核态进程有可能在停止的时候握有一些spinlock,所以如果这时候在外设里面去请求这个spinlock有可能会发生死锁, 所以在外设suspend()函数里面作lock/unlock锁要非常小心,建议不要在外设的suspend()里面等待锁。而且suspend的过程中,有一些log是无法输出的,所以一旦出现问题,非常难调试。

    <1>查看用户空间进程是否有活动的wake_lock使用adb shell登陆到手机的控制台 查看/sys/power/wake_lock 节点看是否有活动的 wake_lock  cat /sys/power/wake_lock 如果输出不为空则表示当前有应用申请了wake_lock比较常见的应用是PowerManagerService,java应用都是通过该服务来获得wake_lock。
通过logcat抓取的log可以查看相应的哪些应用通过PowerManagerService申请wake_lock

一般有如下log:
PowerManagerService(  259): mLocks 01Partial_wakelock_Appname
Partial_wakelock_Appname 代表应用程序的名字

   <2>查看内核空间是否有活动的 wake_lock 需要将kernel/power路径下的wakelock.c文件中的打印消息的mask中加上DEBUG_WAKE_LOCK,这样, 内核如果有内核模块申请或释放wake_lock都会打印出来,通过打印就可以看出是那个模块申请了wake_lock
另外,内核中的可以通过看/proc/wakelocks,有哪些wakelock锁。
在kernel/kernel/power/wakelock.c中添加如下函数,那么在/proc/wakelocks下就能看到有哪些wakelock锁,这样看起来会比较清晰。

static void print_active_locks_sprd(struct seq_file *m,int type)
{
struct wake_lock *lock;
bool print_expired = true;
unsigned int ret = 0;

BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
seq_printf(m,"\n************************* ACTIVE WAKE LOCKS: *************************\n");
list_for_each_entry(lock, &active_wake_locks[type], link) {
if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
long timeout = lock->expires - jiffies;
if (timeout > 0)
ret += seq_printf(m,"active wake lock %s, time left %ld\n",lock->name, timeout);
else if (print_expired)
ret += seq_printf(m,"wake lock %s, expired\n", lock->name);
} else {
ret += seq_printf(m,"active wake lock %s\n", lock->name);
if (!(debug_mask & DEBUG_EXPIRE))
print_expired = false;
}
}
return ret;
}
这个函数是在原有函数的基础上添加的,需要在如下函数中添加调用它。
static int wakelock_stats_show(struct seq_file *m, void *unused)
{
unsigned long irqflags;
struct wake_lock *lock;
int ret;
int type;

spin_lock_irqsave(&list_lock, irqflags);

ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
"\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
list_for_each_entry(lock, &inactive_locks, link)
ret = print_lock_stat(m, lock);
for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
list_for_each_entry(lock, &active_wake_locks[type], link)
ret = print_lock_stat(m, lock);
}

print_active_locks_sprd(m, WAKE_LOCK_SUSPEND);
spin_unlock_irqrestore(&list_lock, irqflags);
return 0;
}
通过抓取的kernel的log可以查看相应的哪些驱动申请了wake_lock


三、MODEM不下去或者功耗过大

Ap影响&GPIO配置&Modem本身问题
1.客户使用双卡项目,编译双SIM卡项目,不插SIM手机开机进入待机电流0.9mA
插入双SIM卡的任何一张或者两张SIM一起插上,手机可以正常打电话,这个时候手机进入待机状态待机电流在50mA左右跳动,待机电流大是由于使用的pa芯片不支持edge功能,需要修改nv:
TD_TIANJI2_NV_TYPE\NV_PRAM_TYPE_PREV_UMTS_MS_RA_CAP\support_egprs = 0
pa芯片是否支持edge功能,需要具体查看芯片的手册.


2.平均功耗高怀疑与网络相关的处理流程,如果在实网的唤醒下,测试平均功耗的时候,
如果发现某些情况下,平均功耗比较高,并且怀疑跟网络相关的话:
找对比机在相同的环境,相同的时间地点,相同的SIM卡(比如说都是中国移动或者中国联通等)同样的后台运行APK然后看对比机是否有相同的问题,如果对比机也有相同的问题,那么可以肯定是网络问题引起的,因为网络环境比较复杂,而且各种case比较多,如果测试数据跟对比机不同,请您提供对比机的测试数据。




3.需要说明测试双卡待机电流时一定要在网络好的地方测试,网络差的地方GSM网和TD网会轮流切换,导致待机电流大


四、开机电流过大

连直流电源开机,当电流尖峰大于600mA的时候,甚至能达到1A,或者达到2A,开机开到一半重启甚至直接开不了机的情况。


1.直接开不了机的情况,连上直流电源,按开关机,直接过流保护,那这个时候一般是贴错料了,比如在cpu的供电的电容直接贴成了电阻,或者其他主要供电器件的电容贴成电阻,或者二极管贴成电阻,这样导致供电短路,这样需要检查元器件。


2.开机开到一半,电流过大重启,这一般需要软硬件一起检查,对于我们的8825平台,有一个情况是,当电池没有进行校准的时候,如果直流电源设置一个正常电压开机(比如3.9v),一般会出现开机重启,所以如果出现这种情况的话,可以将电压设置高一点(如4.5v)。对于开机开到一半,如果一些外设的驱动也没有调试,那可以采取排除法,先将屏和触摸都卸掉,直接查PCBA是否也会电流过大,再直接去掉一些芯片,比如背光IC,音频PA,modem PA,touch IC,WIFI,BT,ATV芯片等,这类芯片去掉后不影响开机,还可以去掉T卡,sim卡,确定是哪个芯片的问题后,不见得是硬件问题,有的时候是需要调试驱动,软件上进行修改等。另外一个方法是,当电流很大的时候,一般元器件或者芯片都会有发烫,可以用手感触一下或者用激光温度计测量下那个位置的温度上升特别快,这样可以更快定位模块。


3.开机的过程中有电流特别大的,但开机后是正常的,这种情况一般是软件问题,可以在连上直流电源的情况下,连接上打印log的串口,直接检查在电流大的时候是哪一模块在执行,这样可以很快定位问题出在哪里,偶尔软件上为了测试可以添加一些while循环,来达到延时,以便更多的时间来看log和比对电流大小从而更准确的来定位问题。


五、关机电流过大

手机关机后一般只有rtc在运行,其他所有设备都处于关闭状态,但我们的板子上vbat会直接给很多外设供电,理论上关机后手机的电流在1mA以下,但是有的板子会存在关机电流过大的问题,一般来说存在两种情况:


1.一种是由关机的时候,软件驱动对一些外部设备的下电时序不到位,一些芯片对下电时序也有要求,如果不正确的下电可能会使芯片接口不能完全处于高阻状态,这样可能会导致漏电,这种情况检查比较麻烦,如果漏点很小,可能不容易被发现,这种情况也只能用排除法,硬件上对一些芯片进行物理上断开,连了磁珠或者电感,或者电阻的,可以物理上断开来排查,另外使用万用表测量外设芯片接口pin是否存在电压,这种情况有时候是外设芯片的问题,需要软件来配合解决。


2.另外一种是纯硬件的问题,有元器件构成了环路,或者存在压差的电阻,二极管,或者像mos管的开关电路等,在关机后,都有可能会导致漏电。


六、在线看视频,播放MP3/MP4,玩游戏,录像电流过大

(1)对于在线视频的时候,机器的耗电可能是非常大的,因为有modem的功耗,cpu的功耗,

DSP的功耗,还有GPU,以及DDR和屏,如果这些模块的频率都调到最大的话,那整机功耗可能会非常高,还有比如像录像,播放mp3/mp4,玩游戏,这些都是需要用到CPU,DSP,GPU,DDR,屏的,如果要过移动入库之类的,对这些都有最高功耗要求,其实很多时候机器在执行这些动作的时候,频率可以比较低的情况下达到要求,所以可以在执行这些动作的时候在软件上对频率有一个限制,这个可以特定针对那个软件先自己进行测试,减cpu,gpu,ddr频率,以达到最低要求,
但这个是在不影响性能的前提下,还可以将backlight调暗,但也要基本不影响视觉效果为基础。
(2)还有一些外设是可以不用打开的时候就没必要打开,比如录像的时候蓝牙没必要打开,打开wifi的时候没必要把modem数据也打开,诸如此类。



案例

(1)由于蓝牙模块中的wake_lock导致手机不能进入睡眠,手机不能进入睡眠, 功耗偏高


通过打印log发现由于蓝牙模块申请了wake_lock没有释放导致系统不能进入suspend状态,最终导致手机不能进入睡眠 。




(2)由于第三方应用的合入导致手机不能睡眠


可以查看/sys/power/wake_lock节点发现PowerManagerService申请了wake_lock,应用组通过将合入的应用逐一的卸载,排查出是由于世界地图应用导致系统不能进入睡眠.


(3)AP虽然睡了,但是DSP还火力很猛。
这个时候我们AP已经看不到log,系统睡了。
关于DSP那边,知识有限,下面仅就已经涉及到的问题做有限的讨论,仅供参考。
以下仅针对8825平台
如果查明系统已经睡眠,关注以下引脚是否被使用且配置为如下模式
 
REG_PIN_CLK_REQ1/GPIO189  - 配置为CLK_REQ1(输入)
REG_PIN_CLK_REQ2/GPIO190  - 配置为CLK_REQ2(输入)
REG_PIN_IIS0MCK           - 配置为BTXT_LEN (输入)
REG_PIN_XTL_EN            - 配置为XTL_EN  (输出)
 
在以上模式情况下:
1>当CLK_REQ1/CLK_REQ2/BTXT_LEN任意一个为高电平,REG_PIN_XTL_EN输出为高电平;
2>VDD_RF随XTL_EN变动,默认将会输出2.85V;
该模式仅在dsp模式工作,因此,arm实际已处于睡眠模式。
 
可通过以下配置暂时避免,待功能完善恢复

{REG_PIN_IIS0MCK,             BITS_PIN_DS(1)|BITS_PIN_AF(3)|BIT_PIN_WPD|BIT_PIN_SLP_WPD|BIT_PIN_SLP_Z}
{REG_PIN_CLK_REQ1,            BITS_PIN_DS(1)|BITS_PIN_AF(3)|BIT_PIN_WPD|BIT_PIN_SLP_WPD|BIT_PIN_SLP_Z},
{REG_PIN_CLK_REQ2,            BITS_PIN_DS(1)|BITS_PIN_AF(3)|BIT_PIN_WPD|BIT_PIN_SLP_WPD|BIT_PIN_SLP_Z},

(4)AP睡了,又醒了。
这里涉及唤醒中断的问题。简单的方法是将这个中断号打印出来。
 
(5)一切似乎都结束了,实际才刚刚开始
Ap睡了,BP也睡了,也没有人打扰了,可是电流还是不小。
大多数情况下,这种情况下电流不会很大,不插卡,一般也就不到4mA。但是不排除例外,最近的8825C1平台,含有trout情况下部分机器就会达到30-40MA。
排查到这里,主要就是关注外设啦,譬如外设未睡眠,漏电流,电流倒灌等等。
 
(6)外设的睡眠,很多设备AP睡眠时是不下电的,例如TP,这个时候我们就要在系统suspend时,对芯片做相应的动作。为了让系统最优,需要对外设进行分类,有些在灭屏就不用的,就在earlysuspend中处理,有些灭屏仍然需要工作的,就在suspend中来处理。

3.系统的LDO。
    SC8810/SC8825集成了低电压和低静态电流低压差稳压器(LDO)用于供电,这些内部集成的LDO便于电源管理。一些备用LDO设计的目的是为了供外部设备使用。所有的LDO都有自己的旁路(掉电)控制信号。
    Linux使用标准的regulator子系统来管理LDO,展讯平台也是基于regulator子系统实现了该部分代码。
    设备睡眠时关于LDO的状态。我们知道,有些LDO我们希望睡眠时关闭,相反有些LDO我们希望睡眠是打开。但是我们在写驱动时却不太关注这部分。因此,可能默认的配置影响了功耗。
这部分的例子,最常见于WIFI的调试。
在打开WIFI时,系统可以睡眠,WIFI当然不能睡眠,它还得唤醒系统。可是有时候,我们默认配置却不小心将其关闭了。最近在调试8825C1的GPS就遇到了这个问题。
 
8825 LDO睡眠设置,相关寄存器定义如下:

arch/arm/mach-sc8825/include/mach/regs_ana_glb.h
#define ANA_REG_GLB_LDO_SLP_CTRL0 SCI_ADDR(ANA_REGS_GLB_BASE, 0x030)
#define ANA_REG_GLB_LDO_SLP_CTRL1 SCI_ADDR(ANA_REGS_GLB_BASE, 0x034)
#define ANA_REG_GLB_LDO_SLP_CTRL2 SCI_ADDR(ANA_REGS_GLB_BASE, 0x038)
#define ANA_REG_GLB_LDO_SLP_CTRL3 SCI_ADDR(ANA_REGS_GLB_BASE, 0x03c)
命令做简单设置,初步判断是否问题根本原因:
shell@android:/ # lookat -s 0xc7f1 0x42000630
shell@android:/ # lookat -l 1 0x42000630

代码修改 /arch/arm/mach-sc8825/pm_sc8825.c
void pm_ana_ldo_config(void)
{
unsigned int val;

/*
* FIXME, should be more gental
*/
val = sci_adi_read(ANA_REG_GLB_LDO_SLP_CTRL0);
val = 0xc7f1;
sci_adi_write(ANA_REG_GLB_LDO_SLP_CTRL0, val, 0xffff);

val = sci_adi_read(ANA_REG_GLB_LDO_SLP_CTRL1);
val |= BIT_FSM_SLPPD_EN;
val |= BIT_DCDC_ARM_BP_EN;
sci_adi_write(ANA_REG_GLB_LDO_SLP_CTRL1, val, 0xffff);
/*
* set ARM_DCDC_ISONUM
* ISO_ON_NUM: (0xa << 8), ISO_OFF_NUM: (0x20)
*/
val = (0xa << 8) | (0x20);
sci_adi_write(ANA_REG_GLB_LDO_SLP_CTRL2, val, 0xffff);
/*
* set ARM_DCDC_DLY_NUM, DLY_NUM:0x2
*/
sci_adi_write(ANA_REG_GLB_LDO_SLP_CTRL3, 0x2, 0xffff);
}
我们可以简单的修改pm_ana_ldo_config的value来改变LDO_SLP_CTRLX
ref code:
arch/arm/mach-sc8825/include/mach/__regulator_map.h
arch/arm/mach-sc8825/include/mach/regs_ana_glb.h


当然有一种更为合理的办法是使用函数控制,所有关于LDO睡眠时下电或不下电的配置都可以使用这种方式。
REGULATOR_MODE_NORMAL    // 睡眠下电
REGULATOR_MODE_STANDBY   // 睡眠保持供电

以下以8825C1 GPS不能下电为例子,做设置
        regulator_gps = regulator_get(NULL, "vddcmmb1p2");
        ...
        err = regulator_set_voltage(regulator_wifi_bt, 1800000, 1800000);
        ...
        regulator_set_mode(regulator_gps, REGULATOR_MODE_STANDBY);
        regulator_enable(regulator_gps);


4.GPIO中断配置对于系统稳定的影响案例


如图所示状况,在外设未使用情况下如是断电状态,则此时外设给BB的中断信号是未知的,如果此时BB该管脚中断配置打开状态,这可能触发无效中断,造成系统状态错乱,严重可能引起死机。


解决方法1:


在不使用该外设的时候,将该管脚中断使能关闭,特别注意开机时的配置,建议在GPIO_CustomizeInit( )中配置完该中断后,即将该中断关闭,在使用该外设时再开中断,退出时关中断


解决方法2:


在Pin的初始配置表中对该中断脚配置FPD和SPD,以确保在外设不用的时候该管脚保持确定的低电平,防止不确定的电平误触发中断,并且防止漏电


建议:方法1和方法2的设置方法同时使用,这样最安全保险



5.GPIO中断配置对于系统稳定的影响案例

现象


系统收到中断,但在中断状态寄存器中无法找到具体中断源


影响


系统无法SLEEP或中断处理过于频繁造成死机


原因


SLEEP前后中断脚上电平不一致,进Sleep电平变为中断电平,唤醒后电平又恢复非中断电平,一般为SPU/SPD配置不合理造成


配置电平触发,但触发源脉冲过窄(可能是干扰引起),造成进入处理程序时触发电平已消失


解决方法


合理配置SPU/SPD,一般和FPU/FPD保持一致,以防止SLEEP前后的中断脚上的电平变化


增加触发脉冲宽度,如果触发源确实是窄脉冲,则建议使用边沿触发(但需注意边沿中断无法唤醒芯片Sleep),如是干扰则想办法消除干扰



6. Android GPIO 配置

可以参考arch/arm/mach-sc8825/board_sp8825XX/pinmap-board.h


例如:


{REG_PIN_GPIO139,             BITS_PIN_DS(1)|BITS_PIN_AF(0)|BIT_PIN_NUL|BIT_PIN_SLP_NUL|BIT_PIN_SLP_IE},




前面是要配置的pin脚名字。后面是对pin脚的具体配置




下面具体描述




BITS_PIN_DS(_x_)  该宏可以配置pin的驱动能力,分为四级0~3


BITS_PIN_AF(_x_)  该宏可以配置pin的四个功能,值为0~3,由参考芯片手册确定需要的功能 


      


BIT_PIN_WPU       正常运行模式下的弱上拉


BIT_PIN_WPD       正常运行模式下的弱下拉


BIT_PIN_NUL       正常运行模式下无上下拉




BIT_PIN_SLP_WPU   睡眠模式下的弱上拉


BIT_PIN_SLP_WPD   睡眠模式下的弱下拉


BIT_PIN_SLP_NUL   睡眠模式下无上下拉




BIT_PIN_SLP_IE    睡眠模式下的输入


BIT_PIN_SLP_OE    睡眠模式下的输出


BIT_PIN_SLP_Z     睡眠模式下的高阻


怎么配置gpio如上所述,找到gpio所对应的pin,然后对该pin进行配置。
 GPIO API使用的是LINUX的gpio lib里定义API,请参考linux/gpio.h,这个头文件也是你使用gpiolib API所必须包含的头文件。对常用API进行简单说明: 
int gpio_request(unsigned gpio, const char *label) 该API是使用GPIO必须的第一步, gpio是gpio number,gpio number为新片spec上定义的gpio number, label为该gpio的说明,例如backlight。 
void gpio_free(unsigned gpio) 使用完gpio后释放该gpio。 


int gpio_direction_input(unsigned gpio) 配置gpio为输入。 
int gpio_direction_output(unsigned gpio, int value) 配置gpio为输出,value为输出的电平,1为高,0为低 


int gpio_get_value(unsigned gpio) 判断GPIO输入的电平高低,两点需要注意: 1,只对输入GPIO,不能对输出GPIO的电平进行判断。 2,返回的非零值为高电平,0为低电平。 
void gpio_set_value(unsigned gpio, int value) 设置输出GPIO的电平高低, 1为高,0为低。不能对输入GPIO进行设置。其它高级用法请参考driver/gpio/gpiolib.c. 


如 mount上debugfs,可以cat gpio查看使用的gpio情况。 
#mount –t debugfs /d
#cat /d/gpio/

在用户空间设置GPIO电平
在kernel里配置完gpio后,可以通过如下步骤在sysfs接口里设置gpio电平: 
调用gpio_export,有两个参数,一个是gpio number, 一个是是否改变输入输出,一般设为false。 
进入/sys/class/gpio/gpio(gpio_number), 例如gpio42, 
在该目录下,可以看到有value选项,这时你可以echo 1 > value设置为高,echo 0 > value设置为低 
GPIO中断在使用gpio中断时,首先要包含#include <linux/irq.h>,<linux/gpio.h>,然后大致经过下列步骤: 
调用sprd_mfp_config配置pin为gpio 
gpio_request申请该gpio 
gpio_direction_input配置为输入 
gpio_to_irq为一个gpio分配中断,输入的参数是gpio number,返回的是分配的IRQ号,如果小于0,分配失败。 
  调用request_irq来申请中断。


FAQ案例

1.一个SC8825C项目待机电流偏大问题


待机电流为90mA左右(不插T卡,SIM卡),SW VER: W13.38;


从串口log可以看到,系统进入睡眠状态;


取下G SENSOR(BMA250),待机电流变成了10.9mA,但是不取G SENSOR时,G SENSOR是正常工作,I2C ADDR也是对的;


检查电路,发现按键未使用的信号给了G SENSOR做中断用;


底层代码默认KEY为2*3,所以在设计中即使没用到这么多键盘,也需要预留或软件配置成2*3(如果不行请改为0*0);


平台默认配置是 2*2 


#define CUSTOM_KEYPAD_ROWS          (SCI_ROW2) 


#define CUSTOM_KEYPAD_COLS          (SCI_COL2) 


#define ROWS        (2) 


#define COLS        (2) 


改为: 


#define CUSTOM_KEYPAD_ROWS          (0) 


2. FM后台播放待机电流偏大
不插T卡,进收音机播放,屏灭后测待机电流,大概50ma。
插上T卡,进收音机播放,屏灭后测待机电流,大概70ma。
测试发现插上T卡时FM后台播放的电流达到70ma,入库的要求是小于70ma。分析后初步确定问题为编写eng版本向T卡写log导致电流增大。
要禁止系统向T卡写log有三个办法:
(1)编译user版本
(2)在init.sp8810.3rdparty.rc中停止写log服务 
    service logs4android /system/bin/logwrapper /system/xbin/logs4android.sh   disabled   service logs4modem /system/bin/logwrapper /system/xbin/logs4modem.sh   disabled
(3)adb shell setprop logs4android.enable 0


3. BT不睡眠导致底电流偏大
老版本W13.20.5待机底电流1.8mA,移植到W13.25后底电流增大到2.2mA, 新版本上硬件工作正常,外围器件的驱动GPIO口等都已经移植
(1)对比W13.20和W13.25两个log,都有正常睡眠动作,睡眠前ldo等寄存器的值都一致,所以初步定位问题是有外设漏电的情况, 进一步需要软件上和硬件上去除基本外设,相应的外设的输出功能的管脚pinmap配置需要配成输出高阻。定位问题是蓝牙没有睡眠, 型号为BK3512
(2)追踪W13.20和W13.25两个log,发现在都不开启BT的情况下,W13.25的代码在唤醒时会调用BT的唤醒函数,如下:

01-01 00:14:03.994 <6>1[   31.878785] request_suspend_state: 
wakeup (3->0) at 31869681900 (2012-01-01 00:14:03.993701733 UTC)
01-01 00:14:04.003 <3>1[   31.882872] Kb_SetBackLightBrightness: 
Set KPLED_CTL : 0x1020 
01-01 00:14:04.003 <3>1[   31.882882] 
01-01 00:14:04.036 <4>1[   31.921336] sprd-gsensor: -- lis3dh_acc_enable -- !
01-01 00:14:04.041 <4>1[   31.926433] sprd-gsensor: -- lis3dh_acc_enable -- success!
01-01 00:14:04.093 <3>1[   31.978233] bluetooth_set_power blocked = 0


但是在睡眠的时候又没有调用bluetooth_set_power blocked = 1让BT睡眠,这种不对称导致BT不能正常睡眠

(3)对比样机和客户机器打开和关闭蓝牙android的log,发现有以下区别
客户机器关闭蓝牙:
D/BluetoothAdapterStateMachine(  257): BluetoothOn process message: 2
D/BluetoothAdapterStateMachine(  257): Bluetooth state 12 -> 13
D/BluetoothAdapterStateMachine(  257): Switching process message: 54
D/BluetoothAdapterStateMachine(  257): Bluetooth state 13 -> 10 客户机器打开蓝牙:D/BluetoothAdapterStateMachine(  257): HotOff process message: 1             D/BluetoothAdapterStateMachine(  257): Bluetooth state 10 -> 11
D/BluetoothAdapterStateMachine(  257): Switching process message: 54
D/BluetoothAdapterStateMachine(  257): Switching process message: 53
D/BluetoothAdapterStateMachine(  257): Bluetooth state 11 -> 12
样机关闭蓝牙:

D/BluetoothAdapterStateMachine(  262): BluetoothOn process message: 2             D/BluetoothAdapterStateMachine(  262): Bluetooth state 12 -> 13
D/BluetoothAdapterStateMachine(  262): Switching process message: 54
D/BluetoothAdapterStateMachine(  262): Bluetooth state 13 -> 10
D/BluetoothAdapterStateMachine(  262): HotOff process message: 102
D/BluetoothAdapterStateMachine(  262): Bluetooth state 10 -> 10 样机打开蓝牙:D/BluetoothAdapterStateMachine(  262): PowerOff process message: 1            D/BluetoothAdapterStateMachine(  262): Bluetooth state 10 -> 11
D/BluetoothAdapterStateMachine(  262): WarmUp process message: 101
D/BluetoothAdapterStateMachine(  262): WarmUp process message: 54
E/StateMachine(  262): BluetoothAdapterStateMachine - unhandledMessage: msg.what=54

D/BluetoothAdapterStateMachine(  262): WarmUp process message: 51
D/BluetoothAdapterStateMachine(  262): HotOff process message: 101
D/BluetoothAdapterStateMachine(  262): Switching process message: 54
D/BluetoothAdapterStateMachine(  262): Switching process message: 53
D/BluetoothAdapterStateMachine(  262): Bluetooth state 11 -> 12
上面代码反映了BT的状态机BluetoothAdapterStateMachine在BluetoothOn-Switching-WarmUp-HotOff-PowerOff五种状态之间转换的流程 对比样机发现客户机器缺少了PowerOff状态,而该状态对于BK3512这款BT来说才是真正进入低功耗状态,正因为这个原因导致客户机器睡眠时BT没有 完全关掉原因。

解决办法: 是否有PowerOff状态是由变量config_bluetooth_adapter_quick_switch决定的,该值定义在 device\sprd\xxx\overlay\frameworks\base\core\res\res\values\config.xml
总结: 对于不同的wifi,BluetoothAdapterStateMachine具有的状态不一样,例如BRCM的wifi只需要BluetoothOn-Switching-WarmUp-HotOff四种状态 而BK3512这款wifi就还需要PowerOff这种状态。