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