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