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