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