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