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