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