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