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