charge animation 充电管理u-boot(rk817)详解

问题:

        最近遇到个问题,android11 rk3566 的系统,产品是个平板,系统正常一直处于耗电的状态,系统会正常挂掉(这里指的是电池的电量不足以带动负载继续正常工作),就是我们所说的系统强制关机了(物理关机),但系统关机完了之后,又会自动的重启,然后重启到一半之后,又会挂掉,一直在这循环,一直把电池的电量一直耗着不足以自动启动时,就不会开机了。

注意:这种情况是系统是由电池供电,不插入适配器的情况。

分析:

        系统挂掉的原因肯定是由于电池的电量,已经不足以带动系统负载正常工作,就是我们所说的低电量自动关机(物理关机),而有会自动重启的原因是,当系统关机后,电池目前的状态就是一个空载的状态,而我的使用的电池有个诟病,也有可能是我所使用的电池太挫了的原因吧,电池空载后它的电池的电压会升高 0.2-0.3V 左右而系统中会去判断这个电压值,此时系统感觉这电池好像有行了!!!又可以支持系统开机了,然后又自动开机了,发现开到一半发现电池带不动了,然后就挂掉了。。。。好家伙这不是坑机嘛这!!当然这里的自动开机后续会讲到,在代码中也有相关的判断。我目前的系统需要实现的是关机充电,以及不能够让它插入适配器的时候自动开机,以及解决上面的问题。

关机充电以及相关的开机处理都在u-boot 阶段,而涉及到的文件有:

u-boot/drivers/power/charge_animation.c //重要,负责管理整个充电过程,它会获取电量、充电类型、按键事件,发起低功耗休眠等。

u-boot/include/power/charge_animation.h

u-boot/drivers/power/fuel_gauge/fg_rk817.c

u-boot/drivers/power/fuel_gauge/fuel_gauge_uclass.c

u-boot/drivers/power/pmic/rk8xx.c

重要代码,结构体分析:

        该结构体是用于充电管理的相关的值,具体的作用,都注释的比较清楚。

struct charge_animation_pdata {
	int android_charge;	/* android charge, 1: enable, 0: disable */
	int uboot_charge;	/* u-boot charge, 1: enable, 0: disable */

	int auto_exit_charge;	/* energy enough auto exit uboot charging*/
	int exit_charge_voltage;/* lowest voltage allowed to exit charging */
	int exit_charge_level;  /* lowest soc level allowed to exit charging */
	int low_power_voltage;	/* below this voltage, force system into charge mode anyway */
	int screen_on_voltage;	/* lowest voltage allowed to turn on screen */

	int system_suspend;	/* enter ATF system suspend, 1: enable, 0: disable */
	int auto_wakeup_interval;/* timeout seconds to auto wakeup system */
	int auto_wakeup_screen_invert;/* auto wakeup system, 1: enable, 0: disable */
	int auto_off_screen_interval;/* timeout seconds to auto turn off screen */
};

 dts配置文件解析:

扫描二维码关注公众号,回复: 15081451 查看本文章
charge-animation {
	compatible = "rockchip,uboot-charge";
	status = "okay";
	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 = <3650>;// U-Boot充电时,允许开机的最低电压
	rockchip,screen-on-voltage = <3400>; // U-Boot充电时,允许点亮屏幕的最低电
	rockchip,uboot-low-power-voltage = <3350>; // U-Boot无条件强制进入充电模式的最低
	rockchip,system-suspend = <1>; // 是否灭屏时进入trust低功耗待机(要压电压ATF支持)
	rockchip,auto-off-screen-interval = <20>; // 自动灭屏超时,单位秒,默认15s
	rockchip,auto-wakeup-interval = <10>; // 休眠自动唤醒时间,单位秒。如果值为0或没// 有这个属性,则禁止休眠自动唤醒,一般用于 压力测试使用
	rockchip,auto-wakeup-screen-invert = <1>;
	};	
	

注意:这些都需要根据你自己的环境进行配置,具体可根据万用表测试,然后再配置成相应的值。

charge_animation.c 中所中的操作函数都是在fg_rk817.c 实现的如下:

 static struct dm_fuel_gauge_ops fg_ops = { //charge_animatio.c 中的一些回调函数都是都是调用的fg_rk817中的函数实现。
	.bat_is_exist = rk817_bat_bat_is_exist,
	.get_soc = rk817_bat_update_get_soc,
	.get_voltage = rk817_bat_update_get_voltage,
	.get_current = rk817_bat_update_get_current,
	.get_chrg_online = rk817_bat_update_get_chrg_online,
};

整个uboot管理充电过程的实现函数主要是charge_animation_show() 函数,它是比较重要的一个函数,下面我们来分析它的过程。

        

charge_animation_show();
 	|--fuel_gauge_bat_is_exist();->rk817_bat_bat_is_exist
	   |--rk817_bat_get_battery_voltage(battery); //读取pmic中的寄存器值获取battery的电量。
	|--charge_extrem_low_power(dev); //该函数主要是检测电池低电量(无法满足系统工作的电量)的,且无供电电源时,关闭PMIC 下电。下面会讲一下该函数。
	   |--fuel_gauge_get_voltage(fg);
	      |--rk817_bat_update_get_voltage();	
	      |--rk817_bat_get_battery_voltage();
	     |--fg_charger_get_chrg_online(dev); // --->>>/* PMIC shutdown */ pmic_shutdown(pmic);static int rk8xx_shutdown(struct udevice *dev)
		|--rk817_bat_update_get_chrg_online();
		   |--rk817_bat_dwc_otg_check_dpdm(battery);	//检测充电类型	
	   |--autowakeup_timer_init(dev,5);	///* Enable auto wakeup */
	   |--fuel_gauge_update_get_soc(fg);-->static int rk817_bat_update_get_soc(struct udevice *dev)//该函数设置充电电流,以及外接的充电类,rk817_bat_smooth_charge(struct rk817_battery_device *battery)(每隔5S检测一次,保证是否在平稳的充电)
	   |--eds_update(dev, soc);
	   |--system_suspend_enter(dev);/* System suspend */
	   |--fuel_gauge_get_voltage(fg);  //更新电压	|--rk817_bat_update_get_voltage();
	|--rockchip_get_boot_mode();//检测充电模式是否有效。
	|--fg_charger_get_chrg_online(dev);--->rk817_bat_update_get_chrg_online();rk817_bat_dwc_otg_check_dpdm(battery);//获取充电头类型
	/* Not charger online and low power, shutdown */
			soc = fuel_gauge_update_get_soc(fg);
		voltage = fuel_gauge_get_voltage(fg);
		if (soc < pdata->exit_charge_level) {
			printf("soc(%d%%) < exit_charge_level(%d%%)\n",
			       soc, pdata->exit_charge_level);
			exit_charge = true;
		}
		if (voltage < pdata->exit_charge_voltage) {
			printf("voltage(%d) < exit_charge_voltage(%d)\n",
			       voltage, pdata->exit_charge_voltage);
			exit_charge = true;
		}
		if (exit_charge) {
			printf("Not charging and low power, Shutdown...\n");
			show_idx = IMAGE_LOWPOWER_IDX(image_num);
			charge_show_bmp(image[show_idx].name);
			mdelay(1000);
			pmic_shutdown(pmic);
		}
	}
	//以下是判断:
	|--pdata->android_charge // Enter android charge, set property for kernel */
	|--if (!pdata->uboot_charge)///* Not enable U-Boot charge, exit */
	|--fuel_gauge_get_voltage(fg);
	|--if (voltage <= pdata->screen_on_voltage + 50)//charge_show_bmp(NULL); 
	|-----!!!!!!/* Charging ! */  while (1) 开始充电 //获取电量状态等驱动中利用的是定时器轮询的方式来获取,避免通过i2c来一直读取寄存器的值。在此期间是禁止中断的,而是通过power key产生事件中断。
	|--local_irq_disable();	
	接下来就是充电5个步骤。
	|--第一步:检测是否现在充电。
	|--charging = fg_charger_get_chrg_online(dev);//如果充电器在此过程中拔出,则会调用rockchip_eink_show_charge_logo(),并关闭PMIC。
	|--第二步:获取系统的电量与电池的电压,以及电流。判断目前的电压是否可以退出uboot阶段的充电(pdata->auto_exit_charge)。判断此时电量是否足以打开屏幕。
	|--fuel_gauge_update_get_soc(fg);	
	|--fuel_gauge_get_voltage(fg);
	|--fuel_gauge_get_current(fg);
	|--下面的一部分就是处理关机充电时,亮屏以及充电图标状态显示的处理。当系统充电到100时则退出充电状态,以引导android 系统。
	。。。。。。
	|--第三步:主要是显示充电图标的处理。这部分我们不重点关注。
	|--第四步:检查按键事件。检测power key :short key event:亮灭屏。长按键:显示logo 图标,引导系统开机继续保持充电状态。       
	|--key_state = check_key_press(dev);//key_state == KEY_PRESS_DOWN /key_state == KEY_PRESS_LONG_DOWN
	|--第五步:主要是检测 ctrl+c 的处理。 

charge_extrem_low_power()函数主要是为了检测当前电池的电量值,以及是否插入适配器对电池充电。如果电池的电量小于我们设置的最低电量值的话,且无适配器插入,就会关闭pmic。以保证上面所出现的一直反复重启的情况出现。

        

static int charge_extrem_low_power(struct udevice *dev)
{
	struct charge_animation_pdata *pdata = dev_get_platdata(dev);
	struct charge_animation_priv *priv = dev_get_priv(dev);
	struct udevice *pmic = priv->pmic;
	struct udevice *fg = priv->fg;
	int voltage, soc, charging = 1;
	static int timer_initialized;
	int ret;

	voltage = fuel_gauge_get_voltage(fg);//获取当前电池电量值
	if (voltage < 0)
		return -EINVAL;
	while (voltage < pdata->low_power_voltage + 50) {
		/* Check charger online */
		charging = fg_charger_get_chrg_online(dev);//判断是否插入输入源,及适配器。返回输入源类型
		if (charging <= 0) {
			printf("%s: Not charging, online=%d. Shutdown...\n",
			       __func__, charging);
			/* wait uart flush before shutdown */
			mdelay(5);
			/* PMIC shutdown */
			pmic_shutdown(pmic);//关闭pmic.

			printf("Cpu should never reach here, shutdown failed !\n");
			continue;
		}

		/* Enable auto wakeup */
		if (!timer_initialized) {
			timer_initialized = 1;
			autowakeup_timer_init(dev, 5);
		}

		/*
		 * Just for fuel gauge to update something important,
		 * including charge current, coulometer or other.
		 */
		soc = fuel_gauge_update_get_soc(fg); //获取系统的电量值。
		if (soc < 0 || soc > 100) {
			printf("get soc failed: %d\n", soc);
			continue;
		}

		/* Update led */
		ret = leds_update(dev, soc);
		if (ret)
			printf("update led failed: %d\n", ret);

		printf("Extrem low power, force charging... threshold=%dmv, now=%dmv\n",
		       pdata->low_power_voltage, voltage);

		/* System suspend */
		system_suspend_enter(dev);

		/* Update voltage */
		voltage = fuel_gauge_get_voltage(fg);
		if (voltage < 0) {
			printf("get voltage failed: %d\n", voltage);
			continue;
		}

		if (ctrlc()) {
			printf("Extrem low charge: exit by ctrl+c\n");
			break;
		}
	}

	autowakeup_timer_uninit();

	return 0;
}

所以基本上我们上面出现的问题就比较清楚了,剩下的只需要我们去配置好相关的参数就行了。

        而我目前的板子没有关机充电图标,因为我的显示屏是通过mipi dsi  转LVDS 的,是通过GM8775C转换芯片的,所以我需要在uboot 中也需要将该芯片初始化成功。

猜你喜欢

转载自blog.csdn.net/qq_48709036/article/details/124406521