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