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