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