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