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