展讯7731C_M Android6.0 充电指示灯实现(一)------关机充电实现【转】
本文转载自:https://blog.csdn.net/m0_37870649/article/details/80566131
前言:
在手机充电中常常使用充电指示灯来观察手机充电状态,比如说将手机插上USB线充电时指示灯会亮,如果拔出USB,指示灯会灭,在充电时候通常我们设置电池电量0~90%时,指示灯为红色,电量为90%~100%时候,显示为绿色。当然充电又分为开机充电和
关机充电,本文着重从关机充电模式讲解guide-led的实现机制
一、关机充电下,指示灯实现整体流程框架
在关机下,插入USB充电,系统会上电启动内核,并且加载相关的服务(Linux 用户空间进程),其中就有关机充电服务/sytem/bin/charge,其中服务端的启动定义在开机初始化话文件init.rc中,如下:
- service charge /bin/charge
- user root
- oneshot
其中charge程序由vendor/sprd/open-source/apps/charge/charge.c实现。
实现流程框架图如下:
该图可以分为两个部分,Linux user和kernel 层两个部分,charge 执行从创建charge线程开始到调用kernel set_brightness完成
对guide-led的控制。
二、关机充电下,指示灯实现具体流程
1. 电池充电主程序入口
文件:vendor/sprd/open-source/apps/charge/charge.c
- int
- main(int argc, char **argv) {
- .....
- ret = pthread_create(&t_1, NULL, charge_thread, NULL);
- if(ret){
- LOGE("thread:charge_thread creat failed\n");
- return -1;
- }
- LOGD("all thread start\n");
- pthread_join(t_1, NULL);
- .....
- LOGD("charge app exit\n");
- return EXIT_SUCCESS;
- }
在主程序中,创建charge_thread用来检测电池状态,然后根据充电电量的变化来控制充电指示灯
2. 充电线程的定义
文件:vendor/sprd/open-source/apps/charge/ui.c
- #define WakeFileName "/sys/power/wait_for_fb_wake"
- void *charge_thread(void *cookie)
- {
- .....
- for (;!is_exit;) {
- fd = open(WakeFileName, O_RDONLY, 0);
- if (fd < 0) {
- LOGD("Couldn't open file /sys/power/wait_for_fb_wake\n");
- return NULL;
- }
- do {
- err = read(fd, &buf, 1);
- LOGD("return from WakeFileName err: %d errno: %s\n", err, strerror(errno));
- } while (err < 0 && errno == EINTR);
- close(fd);
- bat_level = battery_capacity();
- update_progress_locked(bat_level);
- usleep(500000);
- }
- ......
- usleep(200);
- return NULL;
- }
改线程中有一个循环体,其中battery_capacity用来获取电池容量,
将电池容量不断的传入update_progress_locked方法中
3.update_progress_locked方法的实现
- static void update_progress_locked(int level)
- {
- ......
- draw_progress_locked(level); // Draw only the progress bar
- }
在update_progress_locked中,又调用draw_progress_locked方法
4.draw_process_locked方法的实现
- #define LED_GREEN 1
- #define LED_RED 2
- #define LED_BLUE 3
- static void draw_progress_locked(int level)
- {
- .....
- if(level > 100)
- level = 100; //处理电池电量的上限
- else if (level < 0)//处理电池电量的下限
- level = 0;
- if(level < 90){
- if(led_flag!= LED_RED){
- led_on(LED_RED);
- led_flag = LED_RED; //如果电池电量低于90亮绿灯
- }
- }else{
- if(led_flag!= LED_GREEN){ //如果电池电量90~100 亮红灯
- led_on(LED_GREEN); //调用亮灯函数
- led_flag = LED_GREEN;
- }
- }
- .....
- }
5. 亮灯函数led_on的实现
文件:vendor/sprd/open-source/apps/charge/backlight.c
- void led_on(int color)
- {
- if(color == 1){
- eng_led_green_test(max_green_led/2);
- eng_led_red_test(0);
- eng_led_blue_test(0);
- }else if(color == 2){
- eng_led_red_test(max_red_led/2);
- eng_led_green_test(0);
- eng_led_blue_test(0);
- }else if(color == 3){
- eng_led_blue_test(0);
- eng_led_red_test(max_green_led/2);
- eng_led_green_test(max_red_led/2);
- }else
- SPRD_DBG("%s: color is %d invalid\n",__func__,color);
- }
在亮灯函数led_on 中, 通过传入的参数clor 来区分不能颜色灯,这里以绿灯为例
6. 亮绿灯函数eng_led_green_test的实现
- static int eng_led_green_test(int brightness)
- {
- int fd;
- int ret;
- char buffer[8];
- fd = open(LED_GREEN_DEV, O_RDWR); //打开绿灯设备节点
- if(fd < 0) {
- SPRD_DBG("%s: open %s fail",__func__, LED_GREEN_DEV);
- return -1;
- }
- memset(buffer, 0, sizeof(buffer));
- sprintf(buffer, "%d", brightness);
- ret = write(fd, buffer, strlen(buffer)); //向节点中写入数据brightness值
- close(fd);
- return 0;
- }
亮绿灯函数eng_led_green_test的实现非常容易,就是向指定的节点中写入数据brightness值,而brightness值的范围为0~255 ,这个值直接决定了pwm输入的占空比,进而影响灯的亮度。查看设备节点定义如下:
#define LED_GREEN_DEV "/sys/class/leds/green/brightness"
#define LED_RED_DEV "/sys/class/leds/red/brightness"
#define LED_BLUE_DEV "/sys/class/leds/blue/brightness"
上面的节点分别对应为红,绿,蓝三色灯对应的控制节点
==========linux driver kernel 部分==========
也就是说当我们调用write接口后,应用层点灯过程就已经结束了,接下来write会通过Linux VFS调用底层的xxx_write函数,
由于这里定义为/sys 目录下的设备模型节点,所以对应写函数应该为 xxx_store_xxx才对。
7.驱动层的led_on写函数实现
文件:kernel/drivers/leds/leds-sprd-bltc-rgb.c
- static ssize_t store_on_off(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
- {
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- unsigned long state;
- ssize_t ret = -EINVAL;
- ret = kstrtoul(buf, 10, &state);
- PRINT_INFO("onoff_state_value:%1ld\n",state);
- onoff_value = state;
- led_cdev->flags = ONOFF;
- sprd_leds_bltc_rgb_set(led_cdev,state);
- return size;
- }
在上述的写函数中又调用sprd_leds_bltc_rgb_set函数,并且将brightness值传入
8.sprd_leds_bltc_rgb_set的实现
- static void sprd_leds_bltc_rgb_set(struct led_classdev *bltc_rgb_cdev,enum led_brightness value)
- {
- struct sprd_leds_bltc_rgb *brgb;
- unsigned long flags;
- brgb = to_sprd_bltc_rgb(bltc_rgb_cdev);
- spin_lock_irqsave(&brgb->value_lock, flags);
- brgb->leds_flag = bltc_rgb_cdev->flags;
- brgb->value = value;
- spin_unlock_irqrestore(&brgb->value_lock, flags);
- if(1 == brgb->suspend) {
- PRINT_WARN("Do NOT change brightness in suspend mode\n");
- return;
- }
- if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R]) == 0 || \
- strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G]) == 0 || \
- strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B]) == 0)
- sprd_leds_rgb_work(brgb);
- else
- sprd_leds_bltc_work(brgb);
- }
在上述的写函数中又调用sprd_leds_bltc_work函数
9.sprd_leds_bltc_work的实现
- static void sprd_leds_rgb_work(struct sprd_leds_bltc_rgb *brgb)
- {
- unsigned long flags;
- mutex_lock(&brgb->mutex);
- spin_lock_irqsave(&brgb->value_lock, flags);
- if (brgb->value == LED_OFF) {
- spin_unlock_irqrestore(&brgb->value_lock, flags);
- sprd_leds_bltc_rgb_set_brightness(brgb);
- goto out;
- }
- spin_unlock_irqrestore(&brgb->value_lock, flags);
- sprd_leds_bltc_rgb_enable(brgb);
- PRINT_INFO("sprd_leds_bltc_rgb_work_for rgb!\n");
- out:
- mutex_unlock(&brgb->mutex);
- }
紧接着又调用sprd_leds_bltc_rgb_enable接口
10.sprd_leds_bltc_rgb_enable的实现
- static void sprd_leds_bltc_rgb_enable(struct sprd_leds_bltc_rgb *brgb)
- {
- sprd_bltc_rgb_init(brgb);
- if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R]) == 0) {
- sci_adi_set(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<0)|(0x1<<1));
- brgb->bltc_addr = brgb->sprd_bltc_base_addr + BLTC_R_PRESCL + BLTC_DUTY_OFFSET;
- sprd_leds_bltc_rgb_set_brightness(brgb);
- }
- if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G]) == 0) {
- sci_adi_set(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<4)|(0x1<<5));
- brgb->bltc_addr = brgb->sprd_bltc_base_addr + BLTC_G_PRESCL + BLTC_DUTY_OFFSET;
- sprd_leds_bltc_rgb_set_brightness(brgb);
- }
- if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B]) == 0) {
- sci_adi_set(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<8)|(0x1<<9));
- brgb->bltc_addr = brgb->sprd_bltc_base_addr + BLTC_B_PRESCL + BLTC_DUTY_OFFSET;
- sprd_leds_bltc_rgb_set_brightness(brgb);
- }
- .....
- PRINT_INFO("sprd_leds_bltc_rgb_enable\n");
- brgb->enable = 1;
- }
紧接着又调用sprd_leds_bltc_rgb_set_brightness
11.sprd_leds_bltc_rgb_set_brightness的实现
- static void sprd_leds_bltc_rgb_set_brightness(struct sprd_leds_bltc_rgb *brgb)
- {
- unsigned long brightness = brgb->value;
- unsigned long pwm_duty;
- pwm_duty = brightness;
- if(pwm_duty > 255)
- pwm_duty = 255;
- sci_adi_write(brgb->bltc_addr, (pwm_duty<<8)|PWM_MOD_COUNTER,0xffff);
- PRINT_INFO("reg:0x%1LX set_val:0x%08X brightness:%ld brightness_level:%ld(0~15)\n", \
- brgb->bltc_addr, sprd_leds_bltc_rgb_read(brgb->bltc_addr),brightness, pwm_duty);
- }
这里使用最关键的一步使用 sci_adi_write 将ISINK 寄存器赋值,直接调整亮度
三、总结
PS:本文侧重关机充电,当然也牵扯到部分Kernel 部分,至于kernel部分详细实现后面开机充电会详述说明。
展讯7731C_M Android6.0 充电指示灯实现(一)------关机充电实现【转】的更多相关文章
- 关于android各种双卡手机获取imei,imsi的处理(mtk,展讯,高通等)
目前国内对于双卡智能手机的需求还是很大的,各种复杂的业务会涉及到双卡模块:而android标准的api又不提供对双卡的支持.导致国内双卡模块标准混乱,各个厂商各玩各的.目前我知道的双卡解决方案就有:m ...
- Android app 在线更新那点事儿(适配Android6.0、7.0、8.0)
一.前言 app在线更新是一个比较常见需求,新版本发布时,用户进入我们的app,就会弹出更新提示框,第一时间更新新版本app.在线更新分为以下几个步骤: 1, 通过接口获取线上版本号,versionC ...
- 展讯sprd_battery.c 充电驱动
sprd_battery.c 是充电驱动,这个是充电功能的核心内容,电量显示策略.温度检测策略.充电保护机制等功能在这里实现,功能实现与硬件细节剥离,调用通用接口实现逻辑控制: 1 sprdbat_p ...
- Android6.0运行时权限管理
自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装 ...
- android6.0的坑
虽然现在android已经出了7.0了.但是大部分人用的应该还是5.0和6.0的. 其中对于开发者来说,变化比较大的应该是6.0之前和6.0之后的版本. 因为以6.0为分界线多了一个比较坑的东西:权限 ...
- Android6.0动态获取权限
Android6.0采用新的权限模型,只有在需要权限的时候,才告知用户是否授权,是在runtime时候授权,而不是在原来安装的时候 ,同时默认情况下每次在运行时打开页面时候,需要先检查是否有所需要的权 ...
- 编译可在Nexus5上运行的CyanogenMod13.0 ROM(基于Android6.0)
编译可在Nexus5上运行的CyanogenMod13.0 ROM (基于Android6.0) 作者:寻禹@阿里聚安全 前言 下文中无特殊说明时CM代表CyanogenMod的缩写. 下文中说的“设 ...
- Android开发学习之路-Android6.0运行时权限
在Android6.0以后开始,对于部分敏感的“危险”权限,需要在应用运行时向用户申请,只有用户允许的情况下这个权限才会被授予给应用.这对于用户来说,无疑是一个提升安全性的做法.那么对于开发者,应该怎 ...
- Android6.0动态权限申请
goggle在Android6.0要求部分权限需要动态申请,直接下载AndroidManifest.xml中无效 6.0权限的基本知识,以下是需要单独申请的权限,共分为9组, 每组只要有一个权限申请成 ...
随机推荐
- Javascript-数据类型转换 、 运算符和表达式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- laravel架构
1.Laravel 5.1 中的异常处理器和HTTP异常处理实例教程 http://laravelacademy.org/post/1867.html 2.laravel 集成sentry,sentr ...
- shadow一键安装
https://blog.csdn.net/qq_4278923/article/details/80909686
- finally语句块
finally语句块是搭配着try语句块出现的,也就说必须有try语句块才会有finally语句块,但是并不是try语句块都会搭配有finally语句块出现,我们常见的更多是try...catch.. ...
- RootConfig类
package com.ssm.yjblogs.config; import java.util.Properties; import javax.sql.DataSource; import org ...
- arc 092D Two Sequences
题意: 给出两个长度N相同的整数序列A和B,有N^2种方式从A中选择一个数Ai,从B中选择一个数Bj,让两个数相加,求这N^2个数的XOR,即异或. 思路: 暴力的求显然是会超时的,因为是异或,就考虑 ...
- 【Redis学习之四】Redis数据类型 string
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 redis-2.8.18 一.redis客户端基础命令1.帮 ...
- Python: 字典dict: 相同点
问题:怎么样在两个字典中找相同点 answer: eg1: 下面2个字典 a={'x':1,'y':2,'z':3}, b={'w':10,'x':11,'y':2}, 1)找相同点: a.ke ...
- doc&Alt+/ 快捷键设置&ThreadLocal Fameset与Frame区别
Alt+/不管用原因:新版本中MyEclipse的Alt+/是别的快捷键,Ctrl+Space是提示标签快捷键,而Ctrl+Space与输入法切换冲突不能用.MyEclipse设置Alt+/快捷键 1 ...
- 关于nginx配置虚拟主机
前提:我的虚拟主机的外网ip为111.231.226.228(是云服务器哈) 本地测试环境为windows7(修改本地的hosts文件) 步骤:(安装nginx可以看看我文章“linux ng ...