system:Android 8.1
platform:RK3326/PX30
uboot
kernel


Android 8.1 关机充电动画(一)模式选择
Android 8.1 关机充电动画(二)Uboot模式
Android 8.1 关机充电动画(三)Android模式


文章目录

    • 前言
    • 配置
    • 代码分析
    • 总结
    • 附录

前言

关机充电的动画可以在u-boot或者Androidcharger模式工作,这是两个相互独立的部分,RK平台上需要在设备树进行配置。顾名思义u-boot下的charger模式,系统仍然运行在loader下,并未启动内核。
Androidcharger模式下,在引导程序运行期间会传递参数给内核,则会启动内核并加载内核模块,同时安卓系统也不会启动,系统最终只工作charger模式。这里简单记录一下,在uboot中都做了哪些工作,根据什么条件选择工作的模式。

配置

设备树要增加节点charge-animation,这个rk的文档里有相应的说明,在配置下面设备树的配置中,我已经加上了注释,对照这个看就行,不过所有属性只适用u-boot下的关机充电,而不适用用Android下的关机充电,这个具体会在后面加以说明。

这里暂时把已经启动内核之后再进入charger的模式称作Android下的关机充电,可能有些不妥,但是先这样区分吧

具体的配置如下;
rockchip,uboot-charge-on = <0>; ,rockchip,android-charge-on = <1>; 这两个属性用于选择后续的程序会进入到哪一种模式工作,后面在代码中会加以区分。

charge-animation {compatible = "rockchip,uboot-charge";rockchip,uboot-charge-on = <0>; // 是否在U-Boot进行充电rockchip,android-charge-on = <1>; // 是否在Android进行充电rockchip,uboot-exit-charge-level = <5>; // U-Boot充电时,允许开机的最低电量rockchip,uboot-exit-charge-voltage = <3600>; // U-Boot充电时,允许开机的最低电压rockchip,screen-on-voltage = <3400>; // U-Boot充电时,允许点亮屏幕的最低电压rockchip,uboot-low-power-voltage = <3350>; // U-Boot无条件强制进入充电模式的最低电压rockchip,system-suspend = <0>; // 灭屏时进入trust进行低功耗待机rockchip,auto-off-screen-interval = <10>;// 亮屏超时后自动灭屏,单位秒。(如果没有这个属性,则默认15s)rockchip,auto-wakeup-interval = <0>; // 休眠自动唤醒时间,单位秒。(如果值为0或没有这个属性,则禁止休眠自动唤醒)rockchip,auto-wakeup-screen-invert = <0>; // 休眠自动唤醒的时候,是否让屏幕产生亮/灭效果status = "okay";};

代码分析

可以定位到u-boot/drivers/power/charge_animation.c,目前只分析一下函数static int charge_animation_show(struct udevice *dev),具体代码见最后的附录
这个函数会在启动内核之前进行一个简单的检测;

 1. Extrem low power charge? 2. Preboot cmd? 3. Valid boot mode? 4. U-Boot charge enabled by dts config? 5. Screen off before charge? 6. Enter charge !

分别是1 检测低电量2 检测启动命令3 检测启动模式4 检测设备树配置,这四项检测如果不符合会直接return,然后无法成功进入6 Enter charge的状态。具体的可以在代码里面慢慢看,至于第五点,不太清楚了。这里先把第四点的部分相关的代码抠出来,如下:

/* charge mode */pdata->uboot_charge =dev_read_u32_default(dev, "rockchip,uboot-charge-on", 0);pdata->android_charge =dev_read_u32_default(dev, "rockchip,android-charge-on", 0);/* Enter android charge, set property for kernel */if (pdata->android_charge) {env_update("bootargs", "androidboot.mode=charger");}/* Not enable U-Boot charge, exit */if (!pdata->uboot_charge) {debug("exit charge, due to not enable uboot charge\n");return 0;}

可以看到这里有两种情况

  1. uboot_charge如果在设备树里配置为开启,则无法进入Android 关机充电模式了,然后最终程序会进入到while(1)不断循环显示充电动画,检测到相应事件动作之后才会退出充电进入系统,或者掉电关机;
  2. android_charge在设备树中设置开启,并且 uboot_charge设置为关闭的情况下,会设置内核的启动参数env_update("bootargs", "androidboot.mode=charger"),之后uboot会启动内核,并传参数给内核,告诉他,要进入Android关机充电的模式

总结

这里篇幅较短,主要分析了在u-bootcharge_animation_show的部分工作流程即如何选择最终充电的模式,下面会简单介绍uboot下关机充电Android下关机充电的动画定制。

附录

代码可能已经更新请参考u-boot/drivers/power/charge_animation.c

static int charge_animation_show(struct udevice *dev){struct charge_animation_pdata *pdata = dev_get_platdata(dev);struct charge_animation_priv *priv = dev_get_priv(dev);const struct charge_image *image = priv->image;struct udevice *pmic = priv->pmic;struct udevice *fg = priv->fg;const char *preboot = env_get("preboot");int image_num = priv->image_num;bool ever_lowpower_screen_off = false;bool screen_on = true;ulong show_start = 0, charge_start = 0, debug_start = 0;ulong delta;ulong ms = 0, sec = 0;int start_idx = 0, show_idx = -1, old_show_idx = IMAGE_SHOW_RESET;int soc, voltage, current, key_state;int i, charging = 1, ret;int boot_mode;int first_poll_fg = 1;/* * Check sequence: * * 1. Extrem low power charge? * 2. Preboot cmd? * 3. Valid boot mode? * 4. U-Boot charge enabled by dts config? * 5. Screen off before charge? * 6. Enter charge ! * */if (!fuel_gauge_bat_is_exist(fg)) {printf("Exit charge: battery is not exist\n");return 0;}/* Extrem low power charge */ret = charge_extrem_low_power(dev);if (ret < 0) {printf("extrem low power charge failed, ret=%d\n", ret);return ret;}/* If there is preboot command, exit */if (preboot && !strstr(preboot, "dvfs")) {printf("Exit charge: due to preboot cmd '%s'\n", preboot);return 0;}/* Not valid charge mode, exit */#ifdef CONFIG_RKIMG_BOOTLOADERboot_mode = rockchip_get_boot_mode();if ((boot_mode != BOOT_MODE_CHARGING) &&    (boot_mode != BOOT_MODE_UNDEFINE)) {printf("Exit charge: due to boot mode\n");return 0;}#endif/* Not charger online, exit */charging = fuel_gauge_get_chrg_online(fg);if (charging <= 0) {printf("Exit charge: due to charger offline\n");return 0;}/* Enter android charge, set property for kernel */if (pdata->android_charge) {env_update("bootargs", "androidboot.mode=charger");printf("Android charge mode\n");}/* Not enable U-Boot charge, exit */if (!pdata->uboot_charge) {printf("Exit charge: due to not enable uboot charge\n");return 0;}voltage = fuel_gauge_get_voltage(fg);if (voltage < 0) {printf("get voltage failed: %d\n", voltage);return -EINVAL;}/* If low power, turn off screen */if (voltage <= pdata->screen_on_voltage + 50) {screen_on = false;ever_lowpower_screen_off = true;charge_show_bmp(NULL);}/* Auto wakeup */if (pdata->auto_wakeup_interval) {printf("Auto wakeup: %dS\n", pdata->auto_wakeup_interval);autowakeup_timer_init(dev, pdata->auto_wakeup_interval);}/* Give a message warning when CONFIG_IRQ is not enabled */#ifdef CONFIG_IRQprintf("Enter U-Boot charging mode\n");#elseprintf("Enter U-Boot charging mode(without IRQ)\n");#endifcharge_start = get_timer(0);delta = get_timer(0);/* Charging ! */while (1) {/* * At the most time, fuel gauge is usually a i2c device, we * should avoid read/write all the time. We had better set * poll seconds to update fuel gauge info. */if (!first_poll_fg && get_timer(delta) < FUEL_GAUGE_POLL_MS)goto show_images;delta = get_timer(0);debug("step1 (%d)... \n", screen_on);/* * Most fuel gauge is I2C interface, it shouldn't be interrupted * during tansfer. The power key event depends on interrupt, so * so we should disable local irq when update fuel gauge. */local_irq_disable();/* Step1: Is charging now ? */charging = fuel_gauge_get_chrg_online(fg);if (charging <= 0) {printf("Not charging, online=%d. Shutdown...\n",       charging);/* wait uart flush before shutdown */mdelay(5);/* PMIC shutdown */pmic_shutdown(pmic);printf("Cpu should never reach here, shutdown failed !\n");continue;}debug("step2 (%d)... show_idx=%d\n", screen_on, show_idx);/* Step2: get soc and voltage */soc = fuel_gauge_get_soc(fg);if (soc < 0 || soc > 100) {printf("get soc failed: %d\n", soc);continue;}voltage = fuel_gauge_get_voltage(fg);if (voltage < 0) {printf("get voltage failed: %d\n", voltage);continue;}current = fuel_gauge_get_current(fg);if (current == -ENOSYS) {printf("get current failed: %d\n", current);continue;}first_poll_fg = 0;local_irq_enable();show_images:/* * Just for debug, otherwise there will be nothing output which * is not good to know what happen. */if (!debug_start)debug_start = get_timer(0);if (get_timer(debug_start) > 20000) {debug_start = get_timer(0);printf("[%8ld]: soc=%d%%, vol=%dmv, c=%dma, online=%d, screen_on=%d\n",       get_timer(0)/1000, soc, voltage,       current, charging, screen_on);}/* * If ever lowpower screen off, force screen_on=false, which * means key event can't modify screen_on, only voltage higher * then threshold can update screen_on=true; */if (ever_lowpower_screen_off)screen_on = false;/* * Auto turn on screen when voltage higher than Vol screen on. * 'ever_lowpower_screen_off' means enter while loop with * screen off. */if ((ever_lowpower_screen_off) &&    (voltage > pdata->screen_on_voltage)) {ever_lowpower_screen_off = false;screen_on = true;show_idx = IMAGE_SHOW_RESET;}/* * IMAGE_SHOW_RESET means show_idx show be update by start_idx. * When short key pressed event trigged, we will set show_idx * as IMAGE_SHOW_RESET which updates images index from start_idx * that calculate by current soc. */if (show_idx == IMAGE_SHOW_RESET) {for (i = 0; i < image_num - 2; i++) {/* Find out which image we start to show */if ((soc >= image[i].soc) &&    (soc < image[i + 1].soc)) {start_idx = i;break;}if (soc >= 100) {start_idx = image_num - 2;break;}}debug("%s: show_idx=%d, screen_on=%d\n",      __func__, show_idx, screen_on);/* Mark start index and start time */show_idx = start_idx;show_start = get_timer(0);}debug("step3 (%d)... show_idx=%d\n", screen_on, show_idx);/* Step3: show images */if (screen_on) {/* Don't call 'charge_show_bmp' unless image changed */if (old_show_idx != show_idx) {old_show_idx = show_idx;debug("SHOW: %s\n", image[show_idx].name);charge_show_bmp(image[show_idx].name);}/* Re calculate timeout to off screen */if (priv->auto_screen_off_timeout == 0)priv->auto_screen_off_timeout = get_timer(0);} else {priv->auto_screen_off_timeout = 0;system_suspend_enter(pdata);}mdelay(5);/* Every image shows period */if (get_timer(show_start) > image[show_idx].period) {show_start = get_timer(0);/* Update to next image */show_idx++;if (show_idx > (image_num - 2))show_idx = IMAGE_SHOW_RESET;}debug("step4 (%d)... \n", screen_on);/* * Step4: check key event. * * Short key event: turn on/off screen; * Long key event: show logo and boot system or still charging. */key_state = check_key_press(dev);if (key_state == KEY_PRESS_DOWN) {old_show_idx = IMAGE_SHOW_RESET;/* NULL means show nothing, ie. turn off screen */if (screen_on)charge_show_bmp(NULL);/* * Clear current image index, and show image * from start_idx */show_idx = IMAGE_SHOW_RESET;/* * We turn off screen by charge_show_bmp(NULL), so we * should tell while loop to stop show images any more. * * If screen_on=false, means this short key pressed * event turn on the screen and we need show images. * * If screen_on=true, means this short key pressed * event turn off the screen and we never show images. */if (screen_on)screen_on = false;elsescreen_on = true;} else if (key_state == KEY_PRESS_LONG_DOWN) {/* Only long pressed while screen off needs screen_on true */if (!screen_on)screen_on = true;/* Is able to boot now ? */if (soc < pdata->exit_charge_level) {printf("soc=%d%%, threshold soc=%d%%\n",       soc, pdata->exit_charge_level);printf("Low power, unable to boot, charging...\n");show_idx = image_num - 1;continue;}if (voltage < pdata->exit_charge_voltage) {printf("voltage=%dmv, threshold voltage=%dmv\n",       voltage, pdata->exit_charge_voltage);printf("Low power, unable to boot, charging...\n");show_idx = image_num - 1;continue;}/* Success exit charging */printf("Exit charge animation...\n");charge_show_logo();break;} else {/* Do nothing */}debug("step5 (%d)... \n", screen_on);/* Step5: Exit by ctrl+c */if (ctrlc()) {if (voltage >= pdata->screen_on_voltage)charge_show_logo();printf("Exit charge, due to ctrl+c\n");break;}}if (pdata->auto_wakeup_interval)autowakeup_timer_uninit();ms = get_timer(charge_start);if (ms >= 1000) {sec = ms / 1000;ms = ms % 1000;}printf("charging time total: %lu.%lus, soc=%d%%, vol=%dmv\n",       sec, ms, soc, voltage);return 0;}

更多相关文章

  1. Android原生代码调用H5 Web网页中的Javascript函数方法
  2. 直播代码Android怎么实现定时任务及闹钟?
  3. Android架构模式之AAC
  4. Android | 代码混淆到底做了什么?
  5. Android中Activity启动模式学习笔记
  6. Capacitor实现WebView中访问的自定义Android代码

随机推荐

  1. 解析xml数据
  2. Android中泛型使用实例
  3. ScrollView和EditText 滑动冲突的解决办
  4. listView点击事件
  5. android 端生成随机验证码 实现
  6. android下截屏
  7. Android(安卓)EditText 银行卡四位空一格
  8. RecyclerView指定布局管理器
  9. Android敏感词过滤工具类
  10. Android手势操作(二)