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