xref: /rk3399_rockchip-uboot/drivers/power/charge_animation.c (revision 1b3009debef44d7904f509dd74d65ffcf15d23e3)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <asm/io.h>
8 #include <common.h>
9 #include <boot_rkimg.h>
10 #include <console.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <key.h>
14 #include <led.h>
15 #include <rtc.h>
16 #include <pwm.h>
17 #include <asm/arch/rockchip_smccc.h>
18 #include <asm/suspend.h>
19 #include <linux/input.h>
20 #include <power/charge_display.h>
21 #include <power/charge_animation.h>
22 #include <power/rockchip_pm.h>
23 #include <power/fuel_gauge.h>
24 #include <power/pmic.h>
25 #include <power/rk8xx_pmic.h>
26 #include <power/regulator.h>
27 #include <video_rockchip.h>
28 #ifdef CONFIG_IRQ
29 #include <irq-generic.h>
30 #include <rk_timer_irq.h>
31 #endif
32 
33 DECLARE_GLOBAL_DATA_PTR;
34 
35 #define IMAGE_SHOW_RESET			-1
36 #define FUEL_GAUGE_POLL_MS			1000
37 
38 #define LED_CHARGING_NAME			"battery_charging"
39 #define LED_CHARGING_FULL_NAME			"battery_full"
40 
41 struct charge_image {
42 	const char *name;
43 	int soc;
44 	int period;	/* ms */
45 };
46 
47 struct charge_animation_priv {
48 	struct udevice *pmic;
49 	struct udevice *fg;
50 	struct udevice *rtc;
51 #ifdef CONFIG_LED
52 	struct udevice *led_charging;
53 	struct udevice *led_full;
54 #endif
55 	const struct charge_image *image;
56 	int image_num;
57 
58 	int auto_wakeup_key_state;
59 	ulong auto_screen_off_timeout;
60 };
61 
62 /*
63  * IF you want to use your own charge images, please:
64  *
65  * 1. Update the following 'image[]' to point to your own images;
66  * 2. You must set the failed image as last one and soc = -1 !!!
67  */
68 static const struct charge_image image[] = {
69 	{ .name = "battery_0.bmp", .soc = 5, .period = 600 },
70 	{ .name = "battery_1.bmp", .soc = 20, .period = 600 },
71 	{ .name = "battery_2.bmp", .soc = 40, .period = 600 },
72 	{ .name = "battery_3.bmp", .soc = 60, .period = 600 },
73 	{ .name = "battery_4.bmp", .soc = 80, .period = 600 },
74 	{ .name = "battery_5.bmp", .soc = 100, .period = 600 },
75 	{ .name = "battery_fail.bmp", .soc = -1, .period = 1000 },
76 };
77 
78 static int charge_animation_ofdata_to_platdata(struct udevice *dev)
79 {
80 	struct charge_animation_pdata *pdata = dev_get_platdata(dev);
81 
82 	/* charge mode */
83 	pdata->uboot_charge =
84 		dev_read_u32_default(dev, "rockchip,uboot-charge-on", 0);
85 	pdata->android_charge =
86 		dev_read_u32_default(dev, "rockchip,android-charge-on", 0);
87 
88 	pdata->exit_charge_level =
89 		dev_read_u32_default(dev, "rockchip,uboot-exit-charge-level", 0);
90 	pdata->exit_charge_voltage =
91 		dev_read_u32_default(dev, "rockchip,uboot-exit-charge-voltage", 0);
92 
93 	pdata->low_power_voltage =
94 		dev_read_u32_default(dev, "rockchip,uboot-low-power-voltage", 0);
95 
96 	pdata->screen_on_voltage =
97 		dev_read_u32_default(dev, "rockchip,screen-on-voltage", 0);
98 	pdata->system_suspend =
99 		dev_read_u32_default(dev, "rockchip,system-suspend", 0);
100 
101 	pdata->auto_wakeup_interval =
102 		dev_read_u32_default(dev, "rockchip,auto-wakeup-interval", 0);
103 	pdata->auto_wakeup_screen_invert =
104 		dev_read_u32_default(dev, "rockchip,auto-wakeup-screen-invert", 0);
105 
106 	pdata->auto_off_screen_interval =
107 		dev_read_u32_default(dev, "rockchip,auto-off-screen-interval", 15);
108 
109 	if (pdata->screen_on_voltage > pdata->exit_charge_voltage)
110 		pdata->screen_on_voltage = pdata->exit_charge_voltage;
111 
112 	debug("mode: uboot=%d, android=%d; exit: soc=%d%%, voltage=%dmv;\n"
113 	      "lp_voltage=%d%%, screen_on=%dmv\n",
114 	      pdata->uboot_charge, pdata->android_charge,
115 	      pdata->exit_charge_level, pdata->exit_charge_voltage,
116 	      pdata->low_power_voltage, pdata->screen_on_voltage);
117 
118 	return 0;
119 }
120 
121 static int check_key_press(struct udevice *dev)
122 {
123 	struct charge_animation_pdata *pdata = dev_get_platdata(dev);
124 	struct charge_animation_priv *priv = dev_get_priv(dev);
125 	u32 state, rtc_state = 0;
126 
127 #ifdef CONFIG_DM_RTC
128 	if (priv->rtc)
129 		rtc_state = rtc_alarm_trigger(priv->rtc);
130 #endif
131 	if (rtc_state) {
132 		printf("rtc alarm trigger...\n");
133 		return KEY_PRESS_LONG_DOWN;
134 	}
135 
136 	state = key_read(KEY_POWER);
137 	if (state < 0)
138 		printf("read power key failed: %d\n", state);
139 	else if (state == KEY_PRESS_DOWN)
140 		printf("power key pressed...\n");
141 	else if (state == KEY_PRESS_LONG_DOWN)
142 		printf("power key long pressed...\n");
143 
144 	/* Fixup key state for following cases */
145 	if (pdata->auto_wakeup_interval) {
146 		if  (pdata->auto_wakeup_screen_invert) {
147 			if (priv->auto_wakeup_key_state == KEY_PRESS_DOWN) {
148 				/* Value is updated in timer interrupt */
149 				priv->auto_wakeup_key_state = KEY_PRESS_NONE;
150 				state = KEY_PRESS_DOWN;
151 			}
152 		}
153 	} else if (pdata->auto_off_screen_interval) {
154 		if (priv->auto_screen_off_timeout &&
155 		    get_timer(priv->auto_screen_off_timeout) >
156 		    pdata->auto_off_screen_interval * 1000) {	/* 1000ms */
157 			state = KEY_PRESS_DOWN;
158 			printf("Auto screen off\n");
159 		}
160 	}
161 
162 	return state;
163 }
164 
165 /*
166  * If not enable CONFIG_IRQ, cpu can't suspend to ATF or wfi, so that wakeup
167  * period timer is useless.
168  */
169 #ifndef CONFIG_IRQ
170 static int system_suspend_enter(struct charge_animation_pdata *pdata)
171 {
172 	return 0;
173 }
174 
175 static void autowakeup_timer_init(struct udevice *dev, uint32_t seconds) {}
176 static void autowakeup_timer_uninit(void) {}
177 
178 #else
179 static int system_suspend_enter(struct charge_animation_pdata *pdata)
180 {
181 	if (pdata->system_suspend && IS_ENABLED(CONFIG_ARM_SMCCC)) {
182 		printf("\nSystem suspend: ");
183 		putc('0');
184 		regulators_enable_state_mem(false);
185 		putc('1');
186 		local_irq_disable();
187 		putc('2');
188 		irqs_suspend();
189 		putc('3');
190 		device_suspend();
191 		putc('4');
192 		putc('\n');
193 
194 		/* Trap into ATF for low power mode */
195 		cpu_suspend(0, psci_system_suspend);
196 
197 		putc('\n');
198 		putc('4');
199 		device_resume();
200 		putc('3');
201 		irqs_resume();
202 		putc('2');
203 		local_irq_enable();
204 		putc('1');
205 		putc('\n');
206 	} else {
207 		printf("\nWfi\n");
208 		wfi();
209 	}
210 
211 	/*
212 	 * We must wait for key release event finish, otherwise
213 	 * we may read key state too early.
214 	 */
215 	mdelay(300);
216 
217 	return 0;
218 }
219 static void timer_irq_handler(int irq, void *data)
220 {
221 	struct udevice *dev = data;
222 	struct charge_animation_priv *priv = dev_get_priv(dev);
223 	static long long count;
224 
225 	writel(TIMER_CLR_INT, TIMER_BASE + TIMER_INTSTATUS);
226 
227 	priv->auto_wakeup_key_state = KEY_PRESS_DOWN;
228 	printf("auto wakeup count: %lld\n", ++count);
229 }
230 
231 static void autowakeup_timer_init(struct udevice *dev, uint32_t seconds)
232 {
233 	uint64_t period = 24000000ULL * seconds;
234 
235 	/* Disable before conifg */
236 	writel(0, TIMER_BASE + TIMER_CTRL);
237 
238 	/* Config */
239 	writel((uint32_t)period, TIMER_BASE + TIMER_LOAD_COUNT0);
240 	writel((uint32_t)(period >> 32), TIMER_BASE + TIMER_LOAD_COUNT1);
241 	writel(TIMER_CLR_INT, TIMER_BASE + TIMER_INTSTATUS);
242 	writel(TIMER_EN | TIMER_INT_EN, TIMER_BASE + TIMER_CTRL);
243 
244 	/* IRQ */
245 	irq_install_handler(TIMER_IRQ, timer_irq_handler, dev);
246 	irq_handler_enable(TIMER_IRQ);
247 }
248 
249 static void autowakeup_timer_uninit(void)
250 {
251 	irq_free_handler(TIMER_IRQ);
252 }
253 #endif
254 
255 #ifdef CONFIG_DRM_ROCKCHIP
256 static void charge_show_bmp(const char *name)
257 {
258 	rockchip_show_bmp(name);
259 }
260 
261 static void charge_show_logo(void)
262 {
263 	rockchip_show_logo();
264 }
265 #else
266 static void charge_show_bmp(const char *name) {}
267 static void charge_show_logo(void) {}
268 #endif
269 
270 #ifdef CONFIG_LED
271 static int leds_update(struct udevice *dev, int soc)
272 {
273 	struct charge_animation_priv *priv = dev_get_priv(dev);
274 	static int old_soc = -1;
275 	int ret, ledst;
276 
277 	if (old_soc == soc)
278 		return 0;
279 
280 	old_soc = soc;
281 	if (priv->led_charging) {
282 		ledst = (soc < 100) ? LEDST_ON : LEDST_OFF;
283 		ret = led_set_state(priv->led_charging, ledst);
284 		if (ret) {
285 			printf("set charging led %s failed, ret=%d\n",
286 			       (ledst == LEDST_ON) ? "ON" : "OFF", ret);
287 			return ret;
288 		}
289 	}
290 
291 	if (priv->led_full) {
292 		ledst = (soc == 100) ? LEDST_ON : LEDST_OFF;
293 		ret = led_set_state(priv->led_full, ledst);
294 		if (ret) {
295 			printf("set charging full led %s failed, ret=%d\n",
296 			       ledst == LEDST_ON ? "ON" : "OFF", ret);
297 			return ret;
298 		}
299 	}
300 
301 	return 0;
302 }
303 #else
304 static int leds_update(struct udevice *dev, int soc) { return 0; }
305 #endif
306 
307 static int charge_extrem_low_power(struct udevice *dev)
308 {
309 	struct charge_animation_pdata *pdata = dev_get_platdata(dev);
310 	struct charge_animation_priv *priv = dev_get_priv(dev);
311 	struct udevice *pmic = priv->pmic;
312 	struct udevice *fg = priv->fg;
313 	int voltage, soc, charging = 1;
314 	static int timer_initialized;
315 	int ret;
316 
317 	voltage = fuel_gauge_get_voltage(fg);
318 	if (voltage < 0)
319 		return -EINVAL;
320 
321 	while (voltage < pdata->low_power_voltage + 50) {
322 		/* Check charger online */
323 		charging = fuel_gauge_get_chrg_online(fg);
324 		if (charging <= 0) {
325 			printf("%s: Not charging, online=%d. Shutdown...\n",
326 			       __func__, charging);
327 			/* wait uart flush before shutdown */
328 			mdelay(5);
329 			/* PMIC shutdown */
330 			pmic_shutdown(pmic);
331 
332 			printf("Cpu should never reach here, shutdown failed !\n");
333 			continue;
334 		}
335 
336 		/* Enable auto wakeup */
337 		if (!timer_initialized) {
338 			timer_initialized = 1;
339 			autowakeup_timer_init(dev, 5);
340 		}
341 
342 		/*
343 		 * Just for fuel gauge to update something important,
344 		 * including charge current, coulometer or other.
345 		 */
346 		soc = fuel_gauge_get_soc(fg);
347 		if (soc < 0 || soc > 100) {
348 			printf("get soc failed: %d\n", soc);
349 			continue;
350 		}
351 
352 		/* Update led */
353 		ret = leds_update(dev, soc);
354 		if (ret)
355 			printf("update led failed: %d\n", ret);
356 
357 		printf("Extrem low power, force charging... threshold=%dmv, now=%dmv\n",
358 		       pdata->low_power_voltage, voltage);
359 
360 		/* System suspend */
361 		system_suspend_enter(pdata);
362 
363 		/* Update voltage */
364 		voltage = fuel_gauge_get_voltage(fg);
365 		if (voltage < 0) {
366 			printf("get voltage failed: %d\n", voltage);
367 			continue;
368 		}
369 	}
370 
371 	autowakeup_timer_uninit();
372 
373 	return 0;
374 }
375 
376 static int charge_animation_show(struct udevice *dev)
377 {
378 	struct charge_animation_pdata *pdata = dev_get_platdata(dev);
379 	struct charge_animation_priv *priv = dev_get_priv(dev);
380 	const struct charge_image *image = priv->image;
381 	struct udevice *pmic = priv->pmic;
382 	struct udevice *fg = priv->fg;
383 	const char *preboot = env_get("preboot");
384 	int image_num = priv->image_num;
385 	bool ever_lowpower_screen_off = false;
386 	bool screen_on = true;
387 	ulong show_start = 0, charge_start = 0, debug_start = 0;
388 	ulong delta;
389 	ulong ms = 0, sec = 0;
390 	int start_idx = 0, show_idx = -1, old_show_idx = IMAGE_SHOW_RESET;
391 	int soc, voltage, current, key_state;
392 	int i, charging = 1, ret;
393 	int boot_mode;
394 	int first_poll_fg = 1;
395 
396 /*
397  * Check sequence:
398  *
399  * 1. Extrem low power charge?
400  * 2. Preboot cmd?
401  * 3. Valid boot mode?
402  * 4. U-Boot charge enabled by dts config?
403  * 5. Screen off before charge?
404  * 6. Enter charge !
405  *
406  */
407 	if (!fuel_gauge_bat_is_exist(fg)) {
408 		printf("Exit charge: battery is not exist\n");
409 		return 0;
410 	}
411 
412 	/* Extrem low power charge */
413 	ret = charge_extrem_low_power(dev);
414 	if (ret < 0) {
415 		printf("extrem low power charge failed, ret=%d\n", ret);
416 		return ret;
417 	}
418 
419 	/* If there is preboot command, exit */
420 	if (preboot && !strstr(preboot, "dvfs")) {
421 		printf("Exit charge: due to preboot cmd '%s'\n", preboot);
422 		return 0;
423 	}
424 
425 	/* Not valid charge mode, exit */
426 #ifdef CONFIG_RKIMG_BOOTLOADER
427 	boot_mode = rockchip_get_boot_mode();
428 	if ((boot_mode != BOOT_MODE_CHARGING) &&
429 	    (boot_mode != BOOT_MODE_UNDEFINE)) {
430 		printf("Exit charge: due to boot mode\n");
431 		return 0;
432 	}
433 #endif
434 
435 	/* Not charger online, exit */
436 	charging = fuel_gauge_get_chrg_online(fg);
437 	if (charging <= 0) {
438 		printf("Exit charge: due to charger offline\n");
439 		return 0;
440 	}
441 
442 	/* Enter android charge, set property for kernel */
443 	if (pdata->android_charge) {
444 		env_update("bootargs", "androidboot.mode=charger");
445 		printf("Android charge mode\n");
446 	}
447 
448 	/* Not enable U-Boot charge, exit */
449 	if (!pdata->uboot_charge) {
450 		printf("Exit charge: due to not enable uboot charge\n");
451 		return 0;
452 	}
453 
454 	voltage = fuel_gauge_get_voltage(fg);
455 	if (voltage < 0) {
456 		printf("get voltage failed: %d\n", voltage);
457 		return -EINVAL;
458 	}
459 
460 	/* If low power, turn off screen */
461 	if (voltage <= pdata->screen_on_voltage + 50) {
462 		screen_on = false;
463 		ever_lowpower_screen_off = true;
464 		charge_show_bmp(NULL);
465 	}
466 
467 	/* Auto wakeup */
468 	if (pdata->auto_wakeup_interval) {
469 		printf("Auto wakeup: %dS\n", pdata->auto_wakeup_interval);
470 		autowakeup_timer_init(dev, pdata->auto_wakeup_interval);
471 	}
472 
473 /* Give a message warning when CONFIG_IRQ is not enabled */
474 #ifdef CONFIG_IRQ
475 	printf("Enter U-Boot charging mode\n");
476 #else
477 	printf("Enter U-Boot charging mode(without IRQ)\n");
478 #endif
479 
480 	charge_start = get_timer(0);
481 	delta = get_timer(0);
482 
483 	/* Charging ! */
484 	while (1) {
485 		/*
486 		 * At the most time, fuel gauge is usually a i2c device, we
487 		 * should avoid read/write all the time. We had better set
488 		 * poll seconds to update fuel gauge info.
489 		 */
490 		if (!first_poll_fg && get_timer(delta) < FUEL_GAUGE_POLL_MS)
491 			goto show_images;
492 
493 		delta = get_timer(0);
494 
495 		debug("step1 (%d)... \n", screen_on);
496 
497 		/*
498 		 * Most fuel gauge is I2C interface, it shouldn't be interrupted
499 		 * during tansfer. The power key event depends on interrupt, so
500 		 * so we should disable local irq when update fuel gauge.
501 		 */
502 		local_irq_disable();
503 
504 		/* Step1: Is charging now ? */
505 		charging = fuel_gauge_get_chrg_online(fg);
506 		if (charging <= 0) {
507 			printf("Not charging, online=%d. Shutdown...\n",
508 			       charging);
509 
510 			/* wait uart flush before shutdown */
511 			mdelay(5);
512 
513 			/* PMIC shutdown */
514 			pmic_shutdown(pmic);
515 
516 			printf("Cpu should never reach here, shutdown failed !\n");
517 			continue;
518 		}
519 
520 		debug("step2 (%d)... show_idx=%d\n", screen_on, show_idx);
521 
522 		/* Step2: get soc and voltage */
523 		soc = fuel_gauge_get_soc(fg);
524 		if (soc < 0 || soc > 100) {
525 			printf("get soc failed: %d\n", soc);
526 			continue;
527 		}
528 
529 		voltage = fuel_gauge_get_voltage(fg);
530 		if (voltage < 0) {
531 			printf("get voltage failed: %d\n", voltage);
532 			continue;
533 		}
534 
535 		current = fuel_gauge_get_current(fg);
536 		if (current == -ENOSYS) {
537 			printf("get current failed: %d\n", current);
538 			continue;
539 		}
540 		first_poll_fg = 0;
541 
542 		local_irq_enable();
543 
544 show_images:
545 		/*
546 		 * Just for debug, otherwise there will be nothing output which
547 		 * is not good to know what happen.
548 		 */
549 		if (!debug_start)
550 			debug_start = get_timer(0);
551 		if (get_timer(debug_start) > 20000) {
552 			debug_start = get_timer(0);
553 			printf("[%8ld]: soc=%d%%, vol=%dmv, c=%dma, online=%d, screen_on=%d\n",
554 			       get_timer(0)/1000, soc, voltage,
555 			       current, charging, screen_on);
556 		}
557 
558 		/* Update leds */
559 		ret = leds_update(dev, soc);
560 		if (ret)
561 			printf("update led failed: %d\n", ret);
562 
563 		/*
564 		 * If ever lowpower screen off, force screen_on=false, which
565 		 * means key event can't modify screen_on, only voltage higher
566 		 * then threshold can update screen_on=true;
567 		 */
568 		if (ever_lowpower_screen_off)
569 			screen_on = false;
570 
571 		/*
572 		 * Auto turn on screen when voltage higher than Vol screen on.
573 		 * 'ever_lowpower_screen_off' means enter while loop with
574 		 * screen off.
575 		 */
576 		if ((ever_lowpower_screen_off) &&
577 		    (voltage > pdata->screen_on_voltage)) {
578 			ever_lowpower_screen_off = false;
579 			screen_on = true;
580 			show_idx = IMAGE_SHOW_RESET;
581 		}
582 
583 		/*
584 		 * IMAGE_SHOW_RESET means show_idx show be update by start_idx.
585 		 * When short key pressed event trigged, we will set show_idx
586 		 * as IMAGE_SHOW_RESET which updates images index from start_idx
587 		 * that calculate by current soc.
588 		 */
589 		if (show_idx == IMAGE_SHOW_RESET) {
590 			for (i = 0; i < image_num - 2; i++) {
591 				/* Find out which image we start to show */
592 				if ((soc >= image[i].soc) &&
593 				    (soc < image[i + 1].soc)) {
594 					start_idx = i;
595 					break;
596 				}
597 
598 				if (soc >= 100) {
599 					start_idx = image_num - 2;
600 					break;
601 				}
602 			}
603 
604 			debug("%s: show_idx=%d, screen_on=%d\n",
605 			      __func__, show_idx, screen_on);
606 
607 			/* Mark start index and start time */
608 			show_idx = start_idx;
609 			show_start = get_timer(0);
610 		}
611 
612 		debug("step3 (%d)... show_idx=%d\n", screen_on, show_idx);
613 
614 		/* Step3: show images */
615 		if (screen_on) {
616 			/* Don't call 'charge_show_bmp' unless image changed */
617 			if (old_show_idx != show_idx) {
618 				old_show_idx = show_idx;
619 				debug("SHOW: %s\n", image[show_idx].name);
620 				charge_show_bmp(image[show_idx].name);
621 			}
622 			/* Re calculate timeout to off screen */
623 			if (priv->auto_screen_off_timeout == 0)
624 				priv->auto_screen_off_timeout = get_timer(0);
625 		} else {
626 			priv->auto_screen_off_timeout = 0;
627 
628 			system_suspend_enter(pdata);
629 		}
630 
631 		mdelay(5);
632 
633 		/* Every image shows period */
634 		if (get_timer(show_start) > image[show_idx].period) {
635 			show_start = get_timer(0);
636 			/* Update to next image */
637 			show_idx++;
638 			if (show_idx > (image_num - 2))
639 				show_idx = IMAGE_SHOW_RESET;
640 		}
641 
642 		debug("step4 (%d)... \n", screen_on);
643 
644 		/*
645 		 * Step4: check key event.
646 		 *
647 		 * Short key event: turn on/off screen;
648 		 * Long key event: show logo and boot system or still charging.
649 		 */
650 		key_state = check_key_press(dev);
651 		if (key_state == KEY_PRESS_DOWN) {
652 			old_show_idx = IMAGE_SHOW_RESET;
653 
654 			/* NULL means show nothing, ie. turn off screen */
655 			if (screen_on)
656 				charge_show_bmp(NULL);
657 
658 			/*
659 			 * Clear current image index, and show image
660 			 * from start_idx
661 			 */
662 			show_idx = IMAGE_SHOW_RESET;
663 
664 			/*
665 			 * We turn off screen by charge_show_bmp(NULL), so we
666 			 * should tell while loop to stop show images any more.
667 			 *
668 			 * If screen_on=false, means this short key pressed
669 			 * event turn on the screen and we need show images.
670 			 *
671 			 * If screen_on=true, means this short key pressed
672 			 * event turn off the screen and we never show images.
673 			 */
674 			if (screen_on)
675 				screen_on = false;
676 			else
677 				screen_on = true;
678 		} else if (key_state == KEY_PRESS_LONG_DOWN) {
679 			/* Only long pressed while screen off needs screen_on true */
680 			if (!screen_on)
681 				screen_on = true;
682 
683 			/* Is able to boot now ? */
684 			if (soc < pdata->exit_charge_level) {
685 				printf("soc=%d%%, threshold soc=%d%%\n",
686 				       soc, pdata->exit_charge_level);
687 				printf("Low power, unable to boot, charging...\n");
688 				show_idx = image_num - 1;
689 				continue;
690 			}
691 
692 			if (voltage < pdata->exit_charge_voltage) {
693 				printf("voltage=%dmv, threshold voltage=%dmv\n",
694 				       voltage, pdata->exit_charge_voltage);
695 				printf("Low power, unable to boot, charging...\n");
696 				show_idx = image_num - 1;
697 				continue;
698 			}
699 
700 			/* Success exit charging */
701 			printf("Exit charge animation...\n");
702 			charge_show_logo();
703 			break;
704 		} else {
705 			/* Do nothing */
706 		}
707 
708 		debug("step5 (%d)... \n", screen_on);
709 
710 		/* Step5: Exit by ctrl+c */
711 		if (ctrlc()) {
712 			if (voltage >= pdata->screen_on_voltage)
713 				charge_show_logo();
714 			printf("Exit charge, due to ctrl+c\n");
715 			break;
716 		}
717 	}
718 
719 	if (pdata->auto_wakeup_interval)
720 		autowakeup_timer_uninit();
721 
722 	ms = get_timer(charge_start);
723 	if (ms >= 1000) {
724 		sec = ms / 1000;
725 		ms = ms % 1000;
726 	}
727 
728 	printf("charging time total: %lu.%lus, soc=%d%%, vol=%dmv\n",
729 	       sec, ms, soc, voltage);
730 
731 	return 0;
732 }
733 
734 static const struct dm_charge_display_ops charge_animation_ops = {
735 	.show = charge_animation_show,
736 };
737 
738 static int charge_animation_probe(struct udevice *dev)
739 {
740 	struct charge_animation_priv *priv = dev_get_priv(dev);
741 	struct udevice *fg, *pmic, *rtc;
742 	int ret, soc;
743 
744 	/* Get PMIC: used for power off system  */
745 	ret = uclass_get_device(UCLASS_PMIC, 0, &pmic);
746 	if (ret) {
747 		if (ret == -ENODEV)
748 			printf("Can't find PMIC\n");
749 		else
750 			printf("Get UCLASS PMIC failed: %d\n", ret);
751 		return ret;
752 	}
753 	priv->pmic = pmic;
754 
755 	/* Get fuel gauge: used for charging */
756 	ret = uclass_get_device(UCLASS_FG, 0, &fg);
757 	if (ret) {
758 		if (ret == -ENODEV)
759 			debug("Can't find FG\n");
760 		else
761 			debug("Get UCLASS FG failed: %d\n", ret);
762 		return ret;
763 	}
764 	priv->fg = fg;
765 
766 	/* Get rtc: used for power on */
767 	ret = uclass_get_device(UCLASS_RTC, 0, &rtc);
768 	if (ret) {
769 		if (ret == -ENODEV)
770 			debug("Can't find RTC\n");
771 		else
772 			debug("Get UCLASS RTC failed: %d\n", ret);
773 	}
774 	priv->rtc = rtc;
775 
776 	/* Get PWRKEY: used for wakeup and turn off/on LCD */
777 	if (key_read(KEY_POWER) == KEY_NOT_EXIST) {
778 		debug("Can't find power key\n");
779 		return -EINVAL;
780 	}
781 
782 	/* Initialize charge current */
783 	soc = fuel_gauge_get_soc(fg);
784 	if (soc < 0 || soc > 100) {
785 		debug("get soc failed: %d\n", soc);
786 		return -EINVAL;
787 	}
788 
789 	/* Get leds */
790 #ifdef CONFIG_LED
791 	ret = led_get_by_label(LED_CHARGING_NAME, &priv->led_charging);
792 	if (!ret)
793 		printf("Found Charging LED\n");
794 	ret = led_get_by_label(LED_CHARGING_FULL_NAME, &priv->led_full);
795 	if (!ret)
796 		printf("Found Charging-Full LED\n");
797 #endif
798 
799 	/* Get charge images */
800 	priv->image = image;
801 	priv->image_num = ARRAY_SIZE(image);
802 
803 	printf("Enable charge animation display\n");
804 
805 	return 0;
806 }
807 
808 static const struct udevice_id charge_animation_ids[] = {
809 	{ .compatible = "rockchip,uboot-charge" },
810 	{ },
811 };
812 
813 U_BOOT_DRIVER(charge_animation) = {
814 	.name = "charge-animation",
815 	.id = UCLASS_CHARGE_DISPLAY,
816 	.probe = charge_animation_probe,
817 	.of_match = charge_animation_ids,
818 	.ops = &charge_animation_ops,
819 	.ofdata_to_platdata = charge_animation_ofdata_to_platdata,
820 	.platdata_auto_alloc_size = sizeof(struct charge_animation_pdata),
821 	.priv_auto_alloc_size = sizeof(struct charge_animation_priv),
822 };
823