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