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