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 33 struct charge_image { 34 const char *name; 35 int soc; 36 int period; /* ms */ 37 }; 38 39 struct charge_animation_priv { 40 struct udevice *pmic; 41 struct udevice *fg; 42 const struct charge_image *image; 43 int image_num; 44 45 int auto_wakeup_key_state; 46 ulong auto_screen_off_timeout; 47 }; 48 49 /* 50 * IF you want to use your own charge images, please: 51 * 52 * 1. Update the following 'image[]' to point to your own images; 53 * 2. You must set the failed image as last one and soc = -1 !!! 54 */ 55 static const struct charge_image image[] = { 56 { .name = "battery_0.bmp", .soc = 5, .period = 600 }, 57 { .name = "battery_1.bmp", .soc = 20, .period = 600 }, 58 { .name = "battery_2.bmp", .soc = 40, .period = 600 }, 59 { .name = "battery_3.bmp", .soc = 60, .period = 600 }, 60 { .name = "battery_4.bmp", .soc = 80, .period = 600 }, 61 { .name = "battery_5.bmp", .soc = 100, .period = 600 }, 62 { .name = "battery_fail.bmp", .soc = -1, .period = 1000 }, 63 }; 64 65 static int charge_animation_ofdata_to_platdata(struct udevice *dev) 66 { 67 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 68 69 /* charge mode */ 70 pdata->uboot_charge = 71 dev_read_u32_default(dev, "rockchip,uboot-charge-on", 0); 72 pdata->android_charge = 73 dev_read_u32_default(dev, "rockchip,android-charge-on", 0); 74 75 pdata->exit_charge_level = 76 dev_read_u32_default(dev, "rockchip,uboot-exit-charge-level", 0); 77 pdata->exit_charge_voltage = 78 dev_read_u32_default(dev, "rockchip,uboot-exit-charge-voltage", 0); 79 80 pdata->low_power_voltage = 81 dev_read_u32_default(dev, "rockchip,uboot-low-power-voltage", 0); 82 83 pdata->screen_on_voltage = 84 dev_read_u32_default(dev, "rockchip,screen-on-voltage", 0); 85 pdata->system_suspend = 86 dev_read_u32_default(dev, "rockchip,system-suspend", 0); 87 88 pdata->auto_wakeup_interval = 89 dev_read_u32_default(dev, "rockchip,auto-wakeup-interval", 0); 90 pdata->auto_wakeup_screen_invert = 91 dev_read_u32_default(dev, "rockchip,auto-wakeup-screen-invert", 0); 92 93 pdata->auto_off_screen_interval = 94 dev_read_u32_default(dev, "rockchip,auto-off-screen-interval", 15); 95 96 if (pdata->screen_on_voltage > pdata->exit_charge_voltage) 97 pdata->screen_on_voltage = pdata->exit_charge_voltage; 98 99 debug("mode: uboot=%d, android=%d; exit: soc=%d%%, voltage=%dmv;\n" 100 "lp_voltage=%d%%, screen_on=%dmv\n", 101 pdata->uboot_charge, pdata->android_charge, 102 pdata->exit_charge_level, pdata->exit_charge_voltage, 103 pdata->low_power_voltage, pdata->screen_on_voltage); 104 105 return 0; 106 } 107 108 static int check_key_press(struct udevice *dev) 109 { 110 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 111 struct charge_animation_priv *priv = dev_get_priv(dev); 112 u32 state; 113 114 state = platform_key_read(KEY_POWER); 115 if (state < 0) 116 printf("read power key failed: %d\n", state); 117 118 /* Fixup key state for following cases */ 119 if (pdata->auto_wakeup_interval) { 120 if (pdata->auto_wakeup_screen_invert) { 121 if (priv->auto_wakeup_key_state == KEY_PRESS_DOWN) { 122 /* Value is updated in timer interrupt */ 123 priv->auto_wakeup_key_state = KEY_PRESS_NONE; 124 state = KEY_PRESS_DOWN; 125 } 126 } 127 } else if (pdata->auto_off_screen_interval) { 128 if (get_timer(priv->auto_screen_off_timeout) > 129 pdata->auto_off_screen_interval * 1000) { /* 1000ms */ 130 state = KEY_PRESS_DOWN; 131 printf("Auto screen off\n"); 132 } 133 } 134 135 return state; 136 } 137 138 static int system_suspend_enter(struct charge_animation_pdata *pdata) 139 { 140 /* 141 * TODO: enter low power mode: 142 * 3. auto turn off screen when timout; 143 * 4. power key wakeup; 144 * 5. timer period wakeup for pmic fg 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 ms = 0, sec = 0; 309 int start_idx = 0, show_idx = -1; 310 int soc, voltage, current, key_state; 311 int i, charging = 1, ret; 312 int boot_mode; 313 314 /* 315 * Check sequence: 316 * 317 * 1. Extrem low power charge? 318 * 2. Preboot cmd? 319 * 3. Valid boot mode? 320 * 4. U-Boot charge enabled by dts config? 321 * 5. Screen off before charge? 322 * 6. Enter charge ! 323 * 324 */ 325 /* Extrem low power charge */ 326 ret = charge_extrem_low_power(dev); 327 if (ret < 0) { 328 printf("extrem low power charge failed, ret=%d\n", ret); 329 return ret; 330 } 331 332 /* If there is preboot command, exit */ 333 if (preboot) { 334 debug("preboot: %s\n", preboot); 335 return 0; 336 } 337 338 /* Not valid charge mode, exit */ 339 #ifdef CONFIG_RKIMG_BOOTLOADER 340 boot_mode = rockchip_get_boot_mode(); 341 if ((boot_mode != BOOT_MODE_CHARGING) && 342 (boot_mode != BOOT_MODE_UNDEFINE)) { 343 debug("exit charge, due to boot mode: %d\n", boot_mode); 344 return 0; 345 } 346 #endif 347 348 /* Not charger online, exit */ 349 charging = fuel_gauge_get_chrg_online(fg); 350 if (charging <= 0) 351 return 0; 352 353 /* Enter android charge, set property for kernel */ 354 if (pdata->android_charge) { 355 env_update("bootargs", "androidboot.mode=charger"); 356 printf("Android charge mode\n"); 357 } 358 359 /* Not enable U-Boot charge, exit */ 360 if (!pdata->uboot_charge) 361 return 0; 362 363 voltage = fuel_gauge_get_voltage(fg); 364 if (voltage < 0) { 365 printf("get voltage failed: %d\n", voltage); 366 return -EINVAL; 367 } 368 369 /* If low power, turn off screen */ 370 if (voltage <= pdata->screen_on_voltage + 50) { 371 screen_on = false; 372 ever_lowpower_screen_off = true; 373 charge_show_bmp(NULL); 374 } 375 376 /* Auto wakeup */ 377 if (pdata->auto_wakeup_interval) { 378 printf("Auto wakeup: %dS\n", pdata->auto_wakeup_interval); 379 autowakeup_timer_init(dev, pdata->auto_wakeup_interval); 380 } 381 382 printf("Enter U-Boot charging mode\n"); 383 384 charge_start = get_timer(0); 385 386 /* Charging ! */ 387 while (1) { 388 debug("step1 (%d)... \n", screen_on); 389 390 /* Step1: Is charging now ? */ 391 charging = fuel_gauge_get_chrg_online(fg); 392 if (charging <= 0) { 393 printf("Not charging, online=%d. Shutdown...\n", 394 charging); 395 396 /* wait uart flush before shutdown */ 397 mdelay(5); 398 399 /* PMIC shutdown */ 400 pmic_shutdown(pmic); 401 402 printf("Cpu should never reach here, shutdown failed !\n"); 403 continue; 404 } 405 406 debug("step2 (%d)... show_idx=%d\n", screen_on, show_idx); 407 408 /* Step2: get soc and voltage */ 409 soc = fuel_gauge_get_soc(fg); 410 if (soc < 0 || soc > 100) { 411 printf("get soc failed: %d\n", soc); 412 continue; 413 } 414 415 voltage = fuel_gauge_get_voltage(fg); 416 if (voltage < 0) { 417 printf("get voltage failed: %d\n", voltage); 418 continue; 419 } 420 421 current = fuel_gauge_get_current(fg); 422 if (current == -ENOSYS) { 423 printf("get current failed: %d\n", current); 424 continue; 425 } 426 427 /* 428 * Just for debug, otherwise there will be nothing output which 429 * is not good to know what happen. 430 */ 431 if (!debug_start) 432 debug_start = get_timer(0); 433 if (get_timer(debug_start) > 20000) { 434 debug_start = get_timer(0); 435 printf("[%8ld]: soc=%d%%, vol=%dmv, c=%dma, online=%d, screen_on=%d\n", 436 get_timer(0)/1000, soc, voltage, 437 current, charging, screen_on); 438 } 439 440 /* 441 * If ever lowpower screen off, force screen_on=false, which 442 * means key event can't modify screen_on, only voltage higher 443 * then threshold can update screen_on=true; 444 */ 445 if (ever_lowpower_screen_off) 446 screen_on = false; 447 448 /* 449 * Auto turn on screen when voltage higher than Vol screen on. 450 * 'ever_lowpower_screen_off' means enter while loop with 451 * screen off. 452 */ 453 if ((ever_lowpower_screen_off) && 454 (voltage > pdata->screen_on_voltage)) { 455 ever_lowpower_screen_off = false; 456 screen_on = true; 457 show_idx = IMAGE_SHOW_RESET; 458 } 459 460 /* 461 * IMAGE_SHOW_RESET means show_idx show be update by start_idx. 462 * When short key pressed event trigged, we will set show_idx 463 * as IMAGE_SHOW_RESET which updates images index from start_idx 464 * that calculate by current soc. 465 */ 466 if (show_idx == IMAGE_SHOW_RESET) { 467 for (i = 0; i < image_num - 2; i++) { 468 /* Find out which image we start to show */ 469 if ((soc >= image[i].soc) && 470 (soc < image[i + 1].soc)) { 471 start_idx = i; 472 break; 473 } 474 475 if (soc >= 100) { 476 start_idx = image_num - 2; 477 break; 478 } 479 } 480 481 debug("%s: show_idx=%d, screen_on=%d\n", 482 __func__, show_idx, screen_on); 483 484 /* Mark start index and start time */ 485 show_idx = start_idx; 486 show_start = get_timer(0); 487 } 488 489 debug("step3 (%d)... show_idx=%d\n", screen_on, show_idx); 490 491 /* Step3: show images */ 492 if (screen_on) { 493 debug("SHOW: %s\n", image[show_idx].name); 494 charge_show_bmp(image[show_idx].name); 495 496 /* Re calculate timeout to off screen */ 497 if (priv->auto_screen_off_timeout == 0) 498 priv->auto_screen_off_timeout = get_timer(0); 499 } else { 500 priv->auto_screen_off_timeout = 0; 501 502 system_suspend_enter(pdata); 503 } 504 505 mdelay(5); 506 507 /* Every image shows period */ 508 if (get_timer(show_start) > image[show_idx].period) { 509 show_start = get_timer(0); 510 /* Update to next image */ 511 show_idx++; 512 if (show_idx > (image_num - 2)) 513 show_idx = IMAGE_SHOW_RESET; 514 } 515 516 debug("step4 (%d)... \n", screen_on); 517 518 /* 519 * Step4: check key event. 520 * 521 * Short key event: turn on/off screen; 522 * Long key event: show logo and boot system or still charging. 523 */ 524 key_state = check_key_press(dev); 525 if (key_state == KEY_PRESS_DOWN) { 526 /* NULL means show nothing, ie. turn off screen */ 527 if (screen_on) 528 charge_show_bmp(NULL); 529 530 /* 531 * Clear current image index, and show image 532 * from start_idx 533 */ 534 show_idx = IMAGE_SHOW_RESET; 535 536 /* 537 * We turn off screen by charge_show_bmp(NULL), so we 538 * should tell while loop to stop show images any more. 539 * 540 * If screen_on=false, means this short key pressed 541 * event turn on the screen and we need show images. 542 * 543 * If screen_on=true, means this short key pressed 544 * event turn off the screen and we never show images. 545 */ 546 if (screen_on) 547 screen_on = false; 548 else 549 screen_on = true; 550 } else if (key_state == KEY_PRESS_LONG_DOWN) { 551 /* Only long pressed while screen off needs screen_on true */ 552 if (!screen_on) 553 screen_on = true; 554 555 /* Is able to boot now ? */ 556 if (soc < pdata->exit_charge_level) { 557 printf("soc=%d%%, threshold soc=%d%%\n", 558 soc, pdata->exit_charge_level); 559 printf("Low power, unable to boot, charging...\n"); 560 show_idx = image_num - 1; 561 continue; 562 } 563 564 if (voltage < pdata->exit_charge_voltage) { 565 printf("voltage=%dmv, threshold voltage=%dmv\n", 566 voltage, pdata->exit_charge_voltage); 567 printf("Low power, unable to boot, charging...\n"); 568 show_idx = image_num - 1; 569 continue; 570 } 571 572 /* Success exit charging */ 573 printf("Exit charge animation...\n"); 574 charge_show_logo(); 575 break; 576 } else { 577 /* Do nothing */ 578 } 579 580 debug("step5 (%d)... \n", screen_on); 581 582 /* Step5: Exit by ctrl+c */ 583 if (ctrlc()) { 584 if (voltage >= pdata->screen_on_voltage) 585 charge_show_logo(); 586 printf("Exit charge, due to ctrl+c\n"); 587 break; 588 } 589 } 590 591 if (pdata->auto_wakeup_interval) 592 autowakeup_timer_uninit(); 593 594 ms = get_timer(charge_start); 595 if (ms >= 1000) { 596 sec = ms / 1000; 597 ms = ms % 1000; 598 } 599 600 printf("charging time total: %lu.%lus, soc=%d%%, vol=%dmv\n", 601 sec, ms, soc, voltage); 602 603 return 0; 604 } 605 606 static const struct dm_charge_display_ops charge_animation_ops = { 607 .show = charge_animation_show, 608 }; 609 610 static int charge_animation_probe(struct udevice *dev) 611 { 612 struct charge_animation_priv *priv = dev_get_priv(dev); 613 struct udevice *fg, *pmic; 614 int ret, soc; 615 616 /* Get PMIC: used for power off system */ 617 ret = uclass_get_device(UCLASS_PMIC, 0, &pmic); 618 if (ret) { 619 printf("Get UCLASS PMIC failed: %d\n", ret); 620 return ret; 621 } 622 priv->pmic = pmic; 623 624 /* Get fuel gauge: used for charging */ 625 ret = uclass_get_device(UCLASS_FG, 0, &fg); 626 if (ret) { 627 printf("Get UCLASS FG failed: %d\n", ret); 628 return ret; 629 } 630 priv->fg = fg; 631 632 /* Get PWRKEY: used for wakeup and turn off/on LCD */ 633 ret = platform_key_read(KEY_POWER); 634 if (ret == KEY_NOT_EXIST) { 635 printf("Can't find power key\n"); 636 return -EINVAL; 637 } 638 639 /* Initialize charge current */ 640 soc = fuel_gauge_get_soc(fg); 641 if (soc < 0 || soc > 100) { 642 printf("get soc failed: %d\n", soc); 643 return -EINVAL; 644 } 645 646 /* Get charge images */ 647 priv->image = image; 648 priv->image_num = ARRAY_SIZE(image); 649 650 printf("Enable charge animation display\n"); 651 652 return 0; 653 } 654 655 static const struct udevice_id charge_animation_ids[] = { 656 { .compatible = "rockchip,uboot-charge" }, 657 { }, 658 }; 659 660 U_BOOT_DRIVER(charge_animation) = { 661 .name = "charge-animation", 662 .id = UCLASS_CHARGE_DISPLAY, 663 .probe = charge_animation_probe, 664 .of_match = charge_animation_ids, 665 .ops = &charge_animation_ops, 666 .ofdata_to_platdata = charge_animation_ofdata_to_platdata, 667 .platdata_auto_alloc_size = sizeof(struct charge_animation_pdata), 668 .priv_auto_alloc_size = sizeof(struct charge_animation_priv), 669 }; 670