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