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