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