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 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 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 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 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 181 static void pmics_suspend(void) 182 { 183 pmics_ops(true); 184 } 185 186 static void pmics_resume(void) 187 { 188 pmics_ops(false); 189 } 190 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 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) 294 static int system_suspend_enter(struct udevice *dev) 295 { 296 return 0; 297 } 298 299 static void autowakeup_timer_init(struct udevice *dev, uint32_t seconds) {} 300 static void autowakeup_timer_uninit(void) {} 301 302 #else 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 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 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 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 408 static void charge_show_bmp(const char *name) 409 { 410 rockchip_show_bmp(name); 411 } 412 413 static void charge_show_logo(void) 414 { 415 rockchip_show_logo(); 416 } 417 #else 418 static void charge_show_bmp(const char *name) {} 419 static void charge_show_logo(void) {} 420 #endif 421 422 #ifdef CONFIG_LED 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 456 static int leds_update(struct udevice *dev, int soc) { return 0; } 457 #endif 458 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 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 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 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 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 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