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