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