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