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

举报
小麦大叔 发表于 2021/12/29 23:10:05 2021/12/29
【摘要】 system:Android 8.1 platform:RK3326/PX30 uboot kernel Android 8.1 关机充电动画(一)模式选择 Android 8.1 关机充电动画(二...

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";
	};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

代码分析

可以定位到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
  • 5
  • 6

分别是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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

可以看到这里有两种情况

  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_BOOTLOADER
	boot_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_IRQ
	printf("Enter U-Boot charging mode\n");
#else
	printf("Enter U-Boot charging mode(without IRQ)\n");
#endif

	charge_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;
			else
				screen_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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352

文章来源: great.blog.csdn.net,作者:小麦大叔,版权归原作者所有,如需转载,请联系作者。

原文链接:great.blog.csdn.net/article/details/89192015

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。