[MTK] LED 客制化
文摘 MediaTek 2020-04-20 阅读:11099LED 客制化:
主要分为以下章节:
- 驱动测试:检测驱动是否正常
- 相关文件:介绍相关文件
- LED驱动异常检测步骤:针对上层调用下层失败,但是adb可以控制led的情况
- 闪烁改为呼吸灯模式:将闪烁配置成呼吸灯
- PCHG_LED配置更改:切换硬件控制PCHG_LED为软件控制。
一.驱动检测:
1)MT6370/MT6371上的LED
进入对应led的文件中进行(sys/class/leds/ 下面会有对应led结点的文件夹)
闪烁测试需要4步:
1.echo pwm_mode > trigger
这时会生成pwm_dim_freq、pwm_duty两个文件(生成文件是软件实现)
2.echo 3 > pwm_dim_freq
3.echo 5 > pwm_duty
4.echo 5 > brightness
驱动正常就可以看到闪烁,下面同理
设置常亮测试:
echo cc_mode > trigger
echo 5 > brightness //要是不亮,写255试试,一般内部是分为0-6级,输入多了按最高算 0是设置灭
呼吸灯测试:
echo breath_mode > trigger
echo 14 > toff
echo 11 > tr1
echo 5 > brightness
可以看到进行呼吸灯
如果均成功,说明驱动可以正常驱动MT6370文件
2)平台PMIC测试:
1.点亮测试:
echo 255 > brightness
echo 0 >brightness
2.闪烁测试:
1.echo timer > trigger
2.
echo 500 > delay_on
echo 500 > delay_off
---------------------------------------
二.LED驱动框架相关操作接口:
1.开机
Android通过hal层接口,来完成对led驱动的控制。(lights.c)
然后通过底层驱动来完成整个下层的控制。(PMIC上面的LED :mtk_leds.c和mtk_leds_drv.c/MT6370/71上面的LED:mt6370_pmu_rgbled.c)
2.关机充电(KPOC)
上层调用接口:/vendor/mediatek/proprietary/external/charger/lights.cpp
然后调用的到驱动和开机的驱动一致。
---------------------------------------
三.LED驱动异常检测步骤:
1.命名检查:
因为HAL层(KPOC和正常开机)里面有用字符串来描述文件结点的位置,而且名字都是red/green/blue。所以,在一开始就要将Led ISINK的名字规范好,红灯的ISINK改名为red,绿灯改名为green以此类推。(具体可以查看hal层里面对路径定义的字符串,使用本平台上面的PMIC是定义名字对的,只是要看清楚ISINK是否与颜色匹配)
举例字符串:"/sys/class/leds/red/brightness";
这里以使用mt6370.dtsi结点为例(请以您使用的版本为准)
rgbled {
compatible = "mediatek,mt6370_pmu_rgbled";//版本不同,名字不同,以实际为准。
interrupt-names = "isink4_short", "isink3_short",
"isink2_short", "isink1_short",
"isink4_open", "isink3_open",
"isink2_open", "isink1_open";
/* name cnt must be 4 */
mt,led_name = "mt6370_pmu_led1", "mt6370_pmu_led2",
"mt6370_pmu_led3", "mt6370_pmu_led4";
/* trigger cnt must be 4, mode can be selected as */
/* cc_mode -> const current mode */
/* pwm_mode -> pwm dimming mode */
/* breath_mode -> as the name */
mt,led_default_trigger = "cc_mode", "cc_mode", "cc_mode", "none";
};
其中标红字的就是您的led名字。请确认红字连接的LED灯(一般led1-4分别对应着ISINK1-4),并将红字改为对应的LED名字,若没有使用的,可以不用更改。
注意:必须是red blue green 。如下:
Led1-3 分别对应red green blue灯,而led4没有使用。
mt,led_name = "red", "green", "blue", "mt6370_pmu_led4";
补充:若是MT6370/71 的ISINK4(可以配置为硬件点亮)引脚想配置为硬件点亮,则不需要修改其名字。否则会被配置为软件点亮。
2.检测HAL层。(开机异常检查lights.c,关机检查lights.cpp)
1)文件有效性判断
不同版本,的hal中的lights.c中,有些会分别去检测led的文件是否存在,并且是检测3色灯结点同时存在,若是只定义了2个结点,少了其中某一个,都会导致上层与下层的通信中断,也就会出现adb可控led,而上层不可控led的情况:
else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
set_light = set_light_notifications;
if (access(RED_LED_FILE, F_OK) < 0) //判断RED文件是否存在
return -errno;
if (access(GREEN_LED_FILE, F_OK) < 0) //判断GREEN文件是否存在
return -errno;
if (access(BLUE_LED_FILE, F_OK) < 0) //判断BLUE文件是否存在
return -errno;
}
处理方法:
将没定义的文件检测去掉,或者全部去掉。
2)将PMIC框架修改为MT6370框架:
此步仅针对使用MT6370上LED的,PMIC上面的不需要修改此步骤。
因为默认的lights.c是针对PMIC上面的LED的,所以在使用MT6370上面的LED的时候,请在lights.c中做如下更改,以绿灯为例(其他灯同理):
(1)添加对应闪烁灯结点路径:
/MT6370 LED/
char const*const GREEN_PWM_DUTY = "/sys/class/leds/green/pwm_duty";
char const*const GREEN_PWM_DIM_FREQ = "/sys/class/leds/green/pwm_dim_freq";
(2)修改对应的blink_xx().
static int blink_green(int level, int onMS, int offMS)
{
static int preStatus = 0; // 0: off, 1: blink, 2: no blink
int nowStatus;
int i = 0;
if (level == 0)
nowStatus = 0;
else if (onMS && offMS)
nowStatus = 1;
else
nowStatus = 2;
if (preStatus == nowStatus)
return -1;
#ifdef LIGHTS_DBG_ON
ALOGD("blink_green, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
#endif
if (nowStatus == 0) {
write_int(GREEN_LED_FILE, 0);
}
else if (nowStatus == 1) {
ALOGD("MTK:blink green\n");
write_str(GREEN_TRIGGER_FILE, "pwm_mode");
while (((access(GREEN_PWM_DUTY, F_OK) == -1) || (access(GREEN_PWM_DIM_FREQ, R_OK|W_OK) == -1)) && i<10) {
ALOGD("GREEN_PWM_DUTY/FREQ doesn't exist or cannot write!!\n");
led_wait_delay(5);//sleep 5ms for wait kernel LED class create led node of fs
i++;
}
write_int(GREEN_PWM_DUTY, 5);
write_int(GREEN_PWM_DIM_FREQ, 3);
write_int(GREEN_LED_FILE, 0); // default full brightness
write_int(GREEN_LED_FILE, 255); // default full brightness
}
else {//常亮
ALOGD("MTK:set green brightness!!\n");
write_str(GREEN_TRIGGER_FILE, "cc_mode");
write_int(GREEN_LED_FILE, 255); // default full brightness
}
preStatus = nowStatus;
return 0;
}
同理红灯定义:
char const*const RED_PWM_DUTY = "/sys/class/leds/red/pwm_duty";
char const*const RED_PWM_DIM_FREQ = "/sys/class/leds/red/pwm_dim_freq";
修改函数为:blink_red()
写结点的结构与green一致,只是将里面所写的文件替换为red。
如:
GREEN_LED_FILE => RED_LED_FILE
GREEN_TRIGGER_FILE => RED_TRIGGER_FILE
同理绿灯。
3.修改ueventd.mtxxx.rc 文件权限
该步需要修改1.2之后重新编译才能进行修改。若是1.2修改之后,上层可以访问下层了,则可以不进行该修改。
在之前1.2检测都没问题,而上层仍旧无法访问下层的时候。基本可以判定为上层通过hal层访问结点时,权限不够。这时候需要增加对对应结点的控制权限。(若是没有该问题,可以先忽略)
修改(是Android上层调用权限相关的文件)如ueventd.mt6765.ufs.rc (mt6765平台)
在对应文件里面添加文件权限修改。
如果是使用PMIC上面的LED,则添加/检测对应led灯路径的生成文件:
真实路径 delay_on 0664 system system
真实路径 delay_off 0664 system system
如果是使用MT6370上面的LED,则添加/检测对应led灯路径的生成文件:
真实路径 pwm_duty 0664 system system
真实路径 pwm_dim_freq 0664 system system
真实路径填写,以PMIC的框架为例:
使用ADB进行如下测试:
cd sys/class/leds/red
echo timer > trigger //如果是平台PMIC写 echo pwm_mode > trigger
ls -l (l为L的小写)
(需要1.2修改后重新编译后,根据实际路径进行更改)
您可以看到如下情况:
(PMIC查看delay_on/delay_on结点;MT6370的查看pwm_duty/pwm_dim_freq结点)
后面的 ->箭头后面才是真的物理地址也就是真实地址。如果没有->箭头的,当前路径为真实地址。->后面的前面省略的..一般是sys/,具体还请您用ADB到对应目录下面去寻找看。
需要对RED BLUE 灯所使用的三色灯添加:(注意修改该文件时,要切换成c/c++的阅读状态,不要添加在被注释的地方,有个地方是书写错误/* 改为/即可)
每个灯2条,所以使用3个灯就添加6条。每条对应其真实路径。
若还是不行,还请判断是不是上层无法写brightnesss结点或trigger结点。然后在.rc文件里面,再添加brightness和trigger结点的权限:
真实路径 brightnes 0664 system system
真实路径 trigger 0664 system system
补充:无法写结点在kernel log里面会出现提示(brightness的情况需要另寻判断log):
XX doesn't exist or cannot write!!
---------------------------------------
四.闪烁改为呼吸灯模式
1.闪烁模式改为呼吸灯模式:(需要确保通过之前的三检测,能让上层正常控制LED)
1)PMIC的LED:
平台上本身就定义了呼吸函数:
(以o1.mp1,MT6739平台为例)
修改文件:mtk_leds.c(参考路径:/kernel-4.4/drivers/misc/mediatek/leds/mt6739/mtk_leds.c)
1.注意,需要将如下函数的#if 0改为1,让其可以编译进去。
led_switch_breath_pmic()
2.将mt_mt65xx_blink_set()中的
mt_led_blink_pmic(led_data->cust.data,&nled_tmp_setting);
改为:
led_switch_breath_pmic(led_data->cust.data,&nled_tmp_setting,1);
虽然这样可以让闪烁变成呼吸灯。但是无法控制时间,不论怎么样的闪烁时间配置,都是采用该同一种功率的呼吸。
具体呼吸灯的配置更改:
datasheet里面可以搜:breath 看其每个参数对应的图。
然后根据led_switch_breath_pmic函数里面,配置的寄存器,查看对应datasheet的寄存器地址,就可以知道可以配什么值。
2)MT6370/71上面的LED:
因为没有专门为呼吸灯设计的框架,所以这种修改,及时上层设置不同的闪烁时间,到这里也只能用固定的参数进行呼吸灯设置,这个参数修改在lights.c对应的blink_xx里面配置。
在lights.c里面,以绿灯为例添加,(规则同三种的lights.c修改一样):
char const*const GREEN_BREATH_TOFF = "/sys/class/leds/green/ toff ";
char const*const GREEN_BREATH_TR1 = "/sys/class/leds/green/ tr1";
修改blink_green:
static int blink_green(int level, int onMS, int offMS)
{
static int preStatus = 0; // 0: off, 1: blink, 2: no blink
int nowStatus;
int i = 0;
if (level == 0)
nowStatus = 0;
else if (onMS && offMS)
nowStatus = 1;
else
nowStatus = 2;
if (preStatus == nowStatus)
return -1;
#ifdef LIGHTS_DBG_ON
ALOGD("blink_green, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
#endif
if (nowStatus == 0) {
write_int(GREEN_LED_FILE, 0);
}
else if (nowStatus == 1) {
ALOGD("MTK:blink green\n");
write_str(GREEN_TRIGGER_FILE, " breath_mode ");
while (((access(GREEN_BREATH_TOFF, F_OK) == -1) || (access(GREEN_BREATH_TR1, R_OK|W_OK) == -1)) && i<10) {
ALOGD("GREEN_BREATH_TR1/TR1 doesn't exist or cannot write!!\n");
led_wait_delay(5);//sleep 5ms for wait kernel LED class create led delay_off/delay_on node of fs
i++;
}
write_int(GREEN_BREATH_TOFF, 14);
write_int(GREEN_BREATH_TR1, 11);
write_int(GREEN_LED_FILE, 0); // default full brightness
write_int(GREEN_LED_FILE, 255); // default full brightness
}
else
{//常亮
ALOGD("MTK:set green brightness!!\n");
write_str(GREEN_TRIGGER_FILE, "cc_mode");
write_int(GREEN_LED_FILE, 255); // default full brightness
}
preStatus = nowStatus;
return 0;
}
之后按照三种的检测,看是否要修改.rc文件。
同理修改red 或者blue。
因为breath 的呼吸参数不只一个,这里只是用toff和tr1来进行,更多参数可以手操adb,写breath_mode > trigger后,看生成什么文件
然后在对应blink_xx函数的如下位置中,根据逻辑,添加读写顺序。
else if (nowStatus == 1) {
}
write_int :向结点写数值
write_str :向结点写字符串
五:PCHG_LED配置更改
不论是PMIC还是MT6370/71上面,都有一个可以通过硬件或者通过软件控制的ISINK引脚。若没有更改过配置,默认为硬件点亮。
1)PMIC的PCHG_LED
切换为软件控制LED:
除了按照三章节的修改检测之外。
需要自己在需要切换的位置,自己添加代码去写PCHG_LED的切换寄存器。
2)MT6370/71
不需要特殊的修改,因为代码逻辑配置,当配置PCHG_LED为对应green/red/blue的时候,MT6370/71的驱动已经可以自己切换从硬件到软件控制LED的功能。
切换时间是在上层第一次调用到该LED时,驱动代码里面会自动切换为软件控制。