1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <boot_rkimg.h> 9 #include <console.h> 10 #include <dm.h> 11 #include <errno.h> 12 #include <key.h> 13 #include <pwm.h> 14 #include <irq-generic.h> 15 #include <asm/arch/rockchip_smccc.h> 16 #include <asm/suspend.h> 17 #include <linux/input.h> 18 #include <power/charge_display.h> 19 #include <power/fuel_gauge.h> 20 #include <power/pmic.h> 21 #include <power/rk8xx_pmic.h> 22 #include <power/regulator.h> 23 #include <video_rockchip.h> 24 25 DECLARE_GLOBAL_DATA_PTR; 26 27 #define IMAGE_SHOW_RESET -1 28 29 struct charge_image { 30 const char *name; 31 int soc; 32 int period; /* ms */ 33 }; 34 35 struct charge_animation_priv { 36 struct udevice *pmic; 37 struct udevice *fg; 38 struct udevice *pwrkey; 39 const struct charge_image *image; 40 int image_num; 41 }; 42 43 struct charge_animation_pdata { 44 int screen_on_voltage_threshold; 45 int power_on_voltage_threshold; 46 int power_on_soc_threshold; 47 bool suspend_to_sram; 48 bool auto_start_kernel; 49 }; 50 51 static int charge_animation_get_power_on_soc(struct udevice *dev) 52 { 53 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 54 55 if (!pdata) 56 return -ENOSYS; 57 58 return pdata->power_on_soc_threshold; 59 } 60 61 static int charge_animation_get_power_on_voltage(struct udevice *dev) 62 { 63 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 64 65 if (!pdata) 66 return -ENOSYS; 67 68 return pdata->power_on_voltage_threshold; 69 } 70 71 static int charge_animation_get_screen_on_voltage(struct udevice *dev) 72 { 73 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 74 75 if (!pdata) 76 return -ENOSYS; 77 78 return pdata->screen_on_voltage_threshold; 79 } 80 81 static int charge_animation_set_power_on_soc(struct udevice *dev, int val) 82 { 83 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 84 85 if (!pdata) 86 return -ENOSYS; 87 88 pdata->power_on_soc_threshold = val; 89 90 return 0; 91 } 92 93 static int charge_animation_set_power_on_voltage(struct udevice *dev, int val) 94 { 95 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 96 97 if (!pdata) 98 return -ENOSYS; 99 100 pdata->power_on_voltage_threshold = val; 101 102 return 0; 103 } 104 105 static int charge_animation_set_screen_on_voltage(struct udevice *dev, int val) 106 { 107 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 108 109 if (!pdata) 110 return -ENOSYS; 111 112 pdata->screen_on_voltage_threshold = val; 113 114 return 0; 115 } 116 117 /* 118 * IF you want to use your own charge images, please: 119 * 120 * 1. Update the following 'image[]' to point to your own images; 121 * 2. You must set the failed image as last one and soc = -1 !!! 122 */ 123 static const struct charge_image image[] = { 124 { .name = "battery_0.bmp", .soc = 5, .period = 600 }, 125 { .name = "battery_1.bmp", .soc = 20, .period = 600 }, 126 { .name = "battery_2.bmp", .soc = 40, .period = 600 }, 127 { .name = "battery_3.bmp", .soc = 60, .period = 600 }, 128 { .name = "battery_4.bmp", .soc = 80, .period = 600 }, 129 { .name = "battery_5.bmp", .soc = 100, .period = 600 }, 130 { .name = "battery_fail.bmp", .soc = -1, .period = 1000 }, 131 }; 132 133 static int charge_animation_ofdata_to_platdata(struct udevice *dev) 134 { 135 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 136 137 if (dev_read_bool(dev, "charge,suspend-to-sram")) 138 pdata->suspend_to_sram = true; 139 else 140 pdata->suspend_to_sram = false; 141 142 if (dev_read_bool(dev, "charge,auto-start-kernel")) 143 pdata->auto_start_kernel = true; 144 else 145 pdata->auto_start_kernel = false; 146 147 pdata->power_on_soc_threshold = 148 dev_read_u32_default(dev, "power-on-soc-threshold", 0); 149 pdata->power_on_voltage_threshold = 150 dev_read_u32_default(dev, "power-on-voltage-threshold", 0); 151 pdata->screen_on_voltage_threshold = 152 dev_read_u32_default(dev, "screen-on-voltage-threshold", 0); 153 154 if (pdata->screen_on_voltage_threshold > 155 pdata->power_on_voltage_threshold) 156 pdata->screen_on_voltage_threshold = 157 pdata->power_on_voltage_threshold; 158 159 debug("threshold soc=%d%%, voltage=%dmv, screen_on=%dmv, suspend=%d\n", 160 pdata->power_on_soc_threshold, pdata->power_on_voltage_threshold, 161 pdata->screen_on_voltage_threshold, pdata->suspend_to_sram); 162 163 return 0; 164 } 165 166 static int check_key_press(struct udevice *dev) 167 { 168 u32 state; 169 170 state = key_read(dev); 171 if (state < 0) 172 printf("read power key failed: %d\n", state); 173 174 if (state == KEY_PRESS_LONG_DOWN) 175 printf("power key long pressed...\n"); 176 else if (state == KEY_PRESS_DOWN) 177 printf("power key short pressed...\n"); 178 179 return state; 180 } 181 182 static int system_suspend_enter(void) 183 { 184 /* 185 * TODO: enter low power mode: 186 * 3. auto turn off screen when timout; 187 * 4. power key wakeup; 188 * 5. timer period wakeup for pmic fg ? 189 */ 190 if (IS_ENABLED(CONFIG_ARM_SMCCC)) { 191 printf("\nSystem suspend: "); 192 putc('1'); 193 local_irq_disable(); 194 putc('2'); 195 irqs_suspend(); 196 putc('3'); 197 putc('\n'); 198 199 /* Trap into ATF for low power mode */ 200 cpu_suspend(0, psci_system_suspend); 201 202 putc('\n'); 203 putc('3'); 204 irqs_resume(); 205 putc('2'); 206 local_irq_enable(); 207 putc('1'); 208 putc('\n'); 209 210 /* 211 * We must wait for key release event finish, otherwise 212 * we may read key state too early. 213 */ 214 mdelay(300); 215 } else { 216 printf("\nWfi\n"); 217 wfi(); 218 } 219 220 return 0; 221 } 222 223 static int charge_animation_show(struct udevice *dev) 224 { 225 struct charge_animation_pdata *pdata = dev_get_platdata(dev); 226 struct charge_animation_priv *priv = dev_get_priv(dev); 227 const struct charge_image *image = priv->image; 228 struct udevice *pwrkey = priv->pwrkey; 229 struct udevice *pmic = priv->pmic; 230 struct udevice *fg = priv->fg; 231 const char *preboot = env_get("preboot"); 232 int image_num = priv->image_num; 233 bool ever_lowpower_screen_off = false; 234 bool screen_on = true; 235 ulong show_start = 0, charge_start = 0, debug_start = 0; 236 ulong ms = 0, sec = 0; 237 int start_idx = 0, show_idx = -1; 238 int soc, voltage, key_state; 239 int i, charging = 1; 240 int boot_mode; 241 242 /* If there is preboot command, exit */ 243 if (preboot) { 244 debug("preboot: %s\n", preboot); 245 return 0; 246 } 247 248 #ifdef CONFIG_RKIMG_BOOTLOADER 249 boot_mode = rockchip_get_boot_mode(); 250 if ((boot_mode != BOOT_MODE_CHARGING) && 251 (boot_mode != BOOT_MODE_UNDEFINE)) { 252 debug("exit charge, due to boot mode: %d\n", boot_mode); 253 return 0; 254 } 255 #endif 256 257 /* Not charger online, exit */ 258 charging = fuel_gauge_get_chrg_online(fg); 259 if (charging <= 0) 260 return 0; 261 262 voltage = fuel_gauge_get_voltage(fg); 263 if (voltage < 0) { 264 printf("get voltage failed: %d\n", voltage); 265 return -EINVAL; 266 } 267 268 /* If low power, turn off screen */ 269 if (voltage <= pdata->screen_on_voltage_threshold + 50) { 270 screen_on = false; 271 ever_lowpower_screen_off = true; 272 rockchip_show_bmp(NULL); 273 } 274 275 charge_start = get_timer(0); 276 277 /* Charging ! */ 278 while (1) { 279 debug("step1 (%d)... \n", screen_on); 280 281 /* Step1: Is charging now ? */ 282 charging = fuel_gauge_get_chrg_online(fg); 283 if (charging <= 0) { 284 printf("Not charging, online=%d. Shutdown...\n", 285 charging); 286 287 /* wait uart flush before shutdown */ 288 mdelay(500); 289 290 /* PMIC shutdown */ 291 pmic_shutdown(pmic); 292 293 printf("Cpu should never reach here, shutdown failed !\n"); 294 continue; 295 } 296 297 debug("step2 (%d)... show_idx=%d\n", screen_on, show_idx); 298 299 /* Step2: get soc and voltage */ 300 soc = fuel_gauge_get_soc(fg); 301 if (soc < 0 || soc > 100) { 302 printf("get soc failed: %d\n", soc); 303 continue; 304 } 305 306 voltage = fuel_gauge_get_voltage(fg); 307 if (voltage < 0) { 308 printf("get voltage failed: %d\n", voltage); 309 continue; 310 } 311 312 /* 313 * Just for debug, otherwise there will be nothing output which 314 * is not good to know what happen. 315 */ 316 if (!debug_start) 317 debug_start = get_timer(0); 318 if (get_timer(debug_start) > 20000) { 319 debug_start = get_timer(0); 320 printf("soc=%d, vol=%d, online=%d, screen_on=%d, show_idx=%d, ever_off=%d\n", 321 soc, voltage, charging, screen_on, show_idx, 322 ever_lowpower_screen_off); 323 } 324 325 /* 326 * If ever lowpower screen off, force screen on false, which 327 * means key event can't modify screen_on, only voltage higher 328 * then threshold can update screen_on=true; 329 */ 330 if (ever_lowpower_screen_off) 331 screen_on = false; 332 333 /* 334 * Auto turn on screen when voltage higher than Vol screen on. 335 * 'ever_lowpower_screen_off' means enter while loop with 336 * screen off. 337 */ 338 if ((ever_lowpower_screen_off) && 339 (voltage > pdata->screen_on_voltage_threshold)) { 340 ever_lowpower_screen_off = false; 341 screen_on = true; 342 show_idx = IMAGE_SHOW_RESET; 343 } 344 345 /* 346 * IMAGE_SHOW_RESET means show_idx show be update by start_idx. 347 * When short key pressed event trigged, we will set show_idx 348 * as IMAGE_SHOW_RESET which updates images index from start_idx 349 * that calculate by current soc. 350 */ 351 if (show_idx == IMAGE_SHOW_RESET) { 352 for (i = 0; i < image_num - 2; i++) { 353 /* Find out which image we start to show */ 354 if ((soc >= image[i].soc) && 355 (soc < image[i + 1].soc)) { 356 start_idx = i; 357 break; 358 } 359 360 if (soc >= 100) { 361 start_idx = image_num - 2; 362 break; 363 } 364 } 365 366 debug("%s: show_idx=%d, screen_on=%d\n", 367 __func__, show_idx, screen_on); 368 369 /* Mark start index and start time */ 370 show_idx = start_idx; 371 show_start = get_timer(0); 372 } 373 374 debug("step3 (%d)... show_idx=%d\n", screen_on, show_idx); 375 376 /* Step3: show images */ 377 if (screen_on) { 378 debug("SHOW: %s\n", image[show_idx].name); 379 rockchip_show_bmp(image[show_idx].name); 380 } else { 381 system_suspend_enter(); 382 } 383 384 mdelay(5); 385 386 /* Every image shows period */ 387 if (get_timer(show_start) > image[show_idx].period) { 388 show_start = get_timer(0); 389 /* Update to next image */ 390 show_idx++; 391 if (show_idx > (image_num - 2)) 392 show_idx = IMAGE_SHOW_RESET; 393 } 394 395 debug("step4 (%d)... \n", screen_on); 396 397 /* 398 * Step4: check key event. 399 * 400 * Short key event: turn on/off screen; 401 * Long key event: show logo and boot system or still charging. 402 */ 403 key_state = check_key_press(pwrkey); 404 if (key_state == KEY_PRESS_DOWN) { 405 /* NULL means show nothing, ie. turn off screen */ 406 if (screen_on) 407 rockchip_show_bmp(NULL); 408 409 /* 410 * Clear current image index, and show image 411 * from start_idx 412 */ 413 show_idx = IMAGE_SHOW_RESET; 414 415 /* 416 * We turn off screen by rockchip_show_bmp(NULL), so we 417 * should tell while loop to stop show images any more. 418 * 419 * If screen_on=false, means this short key pressed 420 * event turn on the screen and we need show images. 421 * 422 * If screen_on=true, means this short key pressed 423 * event turn off the screen and we never show images. 424 */ 425 if (screen_on) 426 screen_on = false; 427 else 428 screen_on = true; 429 } else if (key_state == KEY_PRESS_LONG_DOWN) { 430 /* Only long pressed while screen off needs screen_on true */ 431 if (!screen_on) 432 screen_on = true; 433 434 /* Is able to boot now ? */ 435 if (soc < pdata->power_on_soc_threshold) { 436 printf("soc=%d%%, threshold soc=%d%%\n", 437 soc, pdata->power_on_soc_threshold); 438 printf("Low power, unable to boot, charging...\n"); 439 show_idx = image_num - 1; 440 continue; 441 } 442 443 if (voltage < pdata->power_on_voltage_threshold) { 444 printf("voltage=%dmv, threshold voltage=%dmv\n", 445 voltage, pdata->power_on_voltage_threshold); 446 printf("Low power, unable to boot, charging...\n"); 447 show_idx = image_num - 1; 448 continue; 449 } 450 451 /* Success exit charging */ 452 printf("Exit charge animation...\n"); 453 rockchip_show_logo(); 454 break; 455 } else { 456 /* Do nothing */ 457 } 458 459 debug("step5 (%d)... \n", screen_on); 460 461 /* 462 * Step5: Check auto start kernel 463 */ 464 if (pdata->auto_start_kernel) { 465 if ((voltage >= pdata->power_on_voltage_threshold) && 466 (soc >= pdata->power_on_soc_threshold)) { 467 printf("Auto start, exit charge animation..\n"); 468 rockchip_show_logo(); 469 break; 470 } 471 } 472 473 /* Step6: Exit by ctrl+c */ 474 if (ctrlc()) { 475 if (voltage >= pdata->screen_on_voltage_threshold) 476 rockchip_show_logo(); 477 printf("Exit charge, due to ctrl+c\n"); 478 break; 479 } 480 } 481 482 ms = get_timer(charge_start); 483 if (ms >= 1000) { 484 sec = ms / 1000; 485 ms = ms % 1000; 486 } 487 488 printf("charging time total: %lu.%lus, soc=%d%%, vol=%dmv\n", 489 sec, ms, soc, voltage); 490 491 return 0; 492 } 493 494 static const struct dm_charge_display_ops charge_animation_ops = { 495 .get_power_on_soc = charge_animation_get_power_on_soc, 496 .get_power_on_voltage = charge_animation_get_power_on_voltage, 497 .get_screen_on_voltage = charge_animation_get_screen_on_voltage, 498 .set_power_on_soc = charge_animation_set_power_on_soc, 499 .set_power_on_voltage = charge_animation_set_power_on_voltage, 500 .set_screen_on_voltage = charge_animation_set_screen_on_voltage, 501 .show = charge_animation_show, 502 }; 503 504 static int charge_animation_probe(struct udevice *dev) 505 { 506 struct charge_animation_priv *priv = dev_get_priv(dev); 507 struct udevice *pwrkey, *fg, *pmic; 508 int ret; 509 510 /* Get PMIC */ 511 ret = uclass_get_device(UCLASS_PMIC, 0, &pmic); 512 if (ret) { 513 printf("Get UCLASS PMIC failed: %d\n", ret); 514 return ret; 515 } 516 priv->pmic = pmic; 517 518 /* Get power key */ 519 for (uclass_first_device(UCLASS_KEY, &pwrkey); 520 pwrkey; 521 uclass_next_device(&pwrkey)) { 522 if (key_type(pwrkey) == KEY_POWER) { 523 priv->pwrkey = pwrkey; 524 break; 525 } 526 } 527 if (!priv->pwrkey) { 528 printf("Can't find any power key\n"); 529 return -ENOSYS; 530 } 531 532 /* Get fuel gauge */ 533 ret = uclass_get_device(UCLASS_FG, 0, &fg); 534 if (ret) { 535 printf("Get UCLASS FG failed: %d\n", ret); 536 return ret; 537 } 538 priv->fg = fg; 539 540 /* Get image */ 541 priv->image = image; 542 priv->image_num = ARRAY_SIZE(image); 543 544 printf("Enable charge animation display\n"); 545 546 return 0; 547 } 548 549 static const struct udevice_id charge_animation_ids[] = { 550 { .compatible = "charge-animation" }, 551 { }, 552 }; 553 554 U_BOOT_DRIVER(charge_animation) = { 555 .name = "charge-animation", 556 .id = UCLASS_CHARGE_DISPLAY, 557 .probe = charge_animation_probe, 558 .of_match = charge_animation_ids, 559 .ops = &charge_animation_ops, 560 .ofdata_to_platdata = charge_animation_ofdata_to_platdata, 561 .platdata_auto_alloc_size = sizeof(struct charge_animation_pdata), 562 .priv_auto_alloc_size = sizeof(struct charge_animation_priv), 563 }; 564