samsung: misc: new feature: common interactive charger
authorPrzemyslaw Marczak <p.marczak@samsung.com>
Fri, 21 Mar 2014 15:15:50 +0000 (16:15 +0100)
committerPrzemyslaw Marczak <p.marczak@samsung.com>
Wed, 17 Sep 2014 14:28:43 +0000 (16:28 +0200)
This change adds common interactive charger feature with
display support.

New config: CONFIG_INTERACTIVE_CHARGER

New functions:
- battery() - which takes one of commands parameter:
    BOOT_CHECK: check battery present, low power mode;
check battery charge level, draw battery screen
    STATE:      display battery screen with current state of charge
this is for command line use
    CHARGE:     start interactive charger for every battery charge level
this is also for command line use

- interactive_charger() - loop function for charge the battery and do:
  - update of battery screen,
  - update charge animation,
  - check for exit condition (if charge level >= 20%)
  - clear screen after 10 seconds animation
  - draw battery on clean screen if any key pressed

There are few constants defined for this feature:
- CHARGE_TRESHOLD_BOOT:         20 (20 percent of charge)
- CHARGE_DISPLAY_TIMEOUT_SEC:   10 (time for animation display)
- CONNECT_CHARGER_TIMEOUT_SEC:  5 (time for connect charger animation)
- CHARGE_PWR_KEY_RESET_TIMEOUT: 3 (time for PWR key press to reset device)

Battery charge level cases:
 - 0-20 % - don't allow to boot and then:
    - enable charger if connected and start charge animation
      or if no charger:
    - display 5 sec charger animation and turn off the device

- > 20 %  - don't display battery screen and boot device

Charge mode can be break by keys VOLUP + VOLDOWN. If charge level > 20%
then device can be enabled by pressing PWR key for a time defined in
CHARGE_PWR_KEY_RESET_TIMEOUT.

Change-Id: I15066a4b86c89f1f0124b072a0aeb7246b29b279
Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
board/samsung/common/misc.c
include/samsung/misc.h

index 43753e8..eeb131e 100644 (file)
@@ -93,7 +93,14 @@ void set_board_info(void)
 }
 #endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */
 
-#ifdef CONFIG_LCD_MENU
+#if defined(CONFIG_LCD_MENU) || defined(CONFIG_INTERACTIVE_CHARGER)
+void keys_init(void)
+{
+       /* Set direction to input */
+       gpio_direction_input(KEY_VOL_UP_GPIO);
+       gpio_direction_input(KEY_VOL_DOWN_GPIO);
+}
+
 static int power_key_pressed(u32 reg)
 {
        struct pmic *pmic;
@@ -155,7 +162,9 @@ int check_keys(void)
 
        return keys;
 }
+#endif /* CONFIG_LCD_MENU || CONFIG_INTERACTIVE_CHARGER */
 
+#ifdef CONFIG_LCD_MENU
 /*
  * 0 BOOT_MODE_INFO
  * 1 BOOT_MODE_THOR
@@ -391,10 +400,266 @@ static void download_menu(void)
        lcd_clear();
 }
 
+#ifdef CONFIG_INTERACTIVE_CHARGER
+static int interactive_charger(int command)
+{
+       int display_timeout_ms = 1000 * CHARGE_DISPLAY_TIMEOUT_SEC;
+       int display_time_ms = 0;
+       int animation_step_ms = 500;
+       int no_charger_anim_timeout_ms = NO_CHARGER_ANIM_TIMEOUT_SEC * 1000;
+       int power_key_timeout_ms = CHARGE_PWR_KEY_RESET_TIMEOUT * 1000;
+       int power_key_time_ms = 0;
+       int keys_exit_timeout_ms = CHARGE_KEYS_EXIT_TIMEOUT * 1000;
+       int keys_exit_time_ms = 0;
+       unsigned int soc_boot = CHARGE_TRESHOLD_BOOT;
+       unsigned int soc = 0;
+       int clear_screen = 0;
+       int chrg = 0;
+       int keys;
+       int i;
+
+       /* Enable charger */
+       if (charger_enable()) {
+               puts("Can't enable charger");
+               return CMD_RET_FAILURE;
+       }
+
+       draw_charge_screen();
+
+       /* Clear PWR button Rising edge interrupt status flag */
+       power_key_pressed(KEY_PWR_INTERRUPT_REG);
+
+       puts("Starting interactive charger (Ctrl+C to break).\n");
+       puts("This mode can be also finished by keys: VOLUP + VOLDOWN.\n");
+
+       while (1) {
+               /* Check state of charge */
+               if (battery_state(&soc)) {
+                       puts("Fuel Gauge Error\n");
+                       lcd_clear();
+                       return CMD_RET_FAILURE;
+               }
+
+               if (display_time_ms <= display_timeout_ms) {
+                       draw_battery_state(soc);
+                       draw_charge_animation();
+
+                       mdelay(animation_step_ms);
+                       display_time_ms += animation_step_ms;
+                       clear_screen = 1;
+               } else {
+                       /* Clear screen only once */
+                       if (clear_screen) {
+                               lcd_clear();
+                               clear_screen = 0;
+                       }
+
+                       /* Check key if lcd is clear */
+                       keys = check_keys();
+                       if (keys) {
+                               display_time_ms = 0;
+                               draw_battery_screen();
+                               draw_battery_state(soc);
+                               draw_charge_screen();
+                               printf("Key pressed. Battery SOC: %.2d %%.\n",
+                                      soc);
+                       }
+               }
+
+               /* Check exit conditions */
+               while (check_keys() == CHARGE_KEYS_EXIT) {
+                       /* 50 ms delay in check_keys() */
+                       keys_exit_time_ms += 50;
+                       if (keys_exit_time_ms >= keys_exit_timeout_ms)
+                               break;
+               }
+
+               if (ctrlc() || keys_exit_time_ms >= keys_exit_timeout_ms) {
+                       puts("Charge mode: aborted by user.\n");
+                       lcd_clear();
+                       return CMD_RET_SUCCESS;
+               }
+
+               keys_exit_time_ms = 0;
+
+               /* Turn off if no charger */
+               chrg = charger_type();
+               if (!chrg) {
+                       puts("Charger disconnected\n");
+                       draw_battery_screen();
+                       draw_battery_state(soc);
+
+                       for (i = 0; i < no_charger_anim_timeout_ms; i += 600) {
+                               mdelay(700);
+                               draw_connect_charger_animation();
+
+                               if (ctrlc())
+                                       return CMD_RET_SUCCESS;
+
+                               chrg = charger_type();
+                               if (chrg) {
+                                       display_time_ms = 0;
+                                       draw_battery_screen();
+                                       draw_battery_state(soc);
+                                       draw_charge_screen();
+                                       puts("Charger connected\n");
+                                       break;
+                               }
+                       }
+
+                       if (!chrg) {
+                               if (command == CMD_BATTERY_BOOT_CHECK) {
+                                       puts("Power OFF.");
+                                       board_poweroff();
+                               } else {
+                                       puts("Please connect charger.\n");
+                                       return CMD_RET_SUCCESS;
+                               }
+                       }
+               }
+
+               /* Check boot ability with 5% of reserve */
+               if (soc >= soc_boot) {
+                       while (power_key_pressed(KEY_PWR_STATUS_REG)) {
+                               mdelay(100);
+                               power_key_time_ms += 100;
+                               /* Check for pwr key press */
+                               if (power_key_time_ms >= power_key_timeout_ms)
+                                       run_command("reset", 0);
+                       }
+               }
+
+               power_key_time_ms = 0;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static int battery(int command)
+{
+       unsigned soc;
+       unsigned soc_boot = CHARGE_TRESHOLD_BOOT;
+       int no_charger_timeout = NO_CHARGER_TIMEOUT_SEC;
+       int no_charger_anim_timeout = NO_CHARGER_ANIM_TIMEOUT_SEC;
+       int chrg = 0;
+       int keys = 0;
+       char *pwr_mode_info = "Warning!\n"
+                             "Battery charge level was too low and\n"
+                             "device is now in LOW POWER mode.\n"
+                             "This mode is not recommended for boot system!\n";
+
+       if (!battery_present()) {
+               puts("Battery not present.\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (battery_state(&soc)) {
+               puts("Fuel Gauge Error\n");
+               return CMD_RET_FAILURE;
+       }
+
+       printf("Battery SOC: %.2d %%.\n", soc);
+
+       switch (command) {
+       case CMD_BATTERY_BOOT_CHECK:
+               /*
+                * If (soc > soc_boot) then don't waste
+                * a time for draw battery screen.
+               */
+               if (soc >= soc_boot)
+                       return CMD_RET_SUCCESS;
+
+               /* Set low power mode only if do boot check */
+               board_low_power_mode();
+               puts("Battery SOC (< 20%) is too low for boot.\n");
+               break;
+       case CMD_BATTERY_STATE:
+               lcd_clear();
+               draw_battery_screen();
+               draw_battery_state(soc);
+
+               /* Wait some time before clear battery screen */
+               mdelay(2000);
+               lcd_clear();
+               return CMD_RET_SUCCESS;
+       case CMD_BATTERY_CHARGE:
+               lcd_clear();
+               break;
+       default:
+               return CMD_RET_SUCCESS;
+       }
+
+       draw_battery_screen();
+       draw_battery_state(soc);
+
+       do {
+               /* Check charger */
+               chrg = charger_type();
+               if (chrg) {
+                       printf("CHARGER TYPE: %d\n", chrg);
+                       draw_battery_screen();
+                       draw_battery_state(soc);
+                       break;
+               }
+
+               if (no_charger_anim_timeout > 0)
+                       draw_connect_charger_animation();
+
+               mdelay(800);
+
+               /* Check exit conditions */
+               keys = check_keys();
+               if (keys) {
+                       no_charger_anim_timeout = NO_CHARGER_ANIM_TIMEOUT_SEC;
+                       draw_battery_screen();
+                       draw_battery_state(soc);
+               }
+
+               if (keys == CHARGE_KEYS_EXIT || ctrlc()) {
+                       puts("Charge mode aborted by user.\n");
+                       goto warning;
+               }
+
+               no_charger_anim_timeout--;
+               if (!no_charger_anim_timeout)
+                       lcd_clear();
+
+       } while (no_charger_timeout--);
+
+       /* there is no charger and soc (%) is too low - POWER OFF */
+       if (!chrg) {
+               puts("No charger connected!\n");
+
+               if (command == CMD_BATTERY_BOOT_CHECK) {
+                       puts("Power OFF.");
+                       board_poweroff();
+               } else {
+                       puts("Please connect charger.\n");
+                       return CMD_RET_SUCCESS;
+               }
+       }
+
+       /* Charger connected - enable charge mode */
+       if (interactive_charger(command))
+               printf("Charge failed\n");
+
+warning:
+       /* Charge mode aborted or failed */
+       if (command == CMD_BATTERY_BOOT_CHECK)
+               puts(pwr_mode_info);
+
+       return CMD_RET_SUCCESS;
+}
+#endif
+
 void check_boot_mode(void)
 {
        int pwr_key;
 
+#ifdef CONFIG_INTERACTIVE_CHARGER
+       battery(CMD_BATTERY_BOOT_CHECK);
+#endif
+#ifdef CONFIG_LCD_MENU
        pwr_key = power_key_pressed(KEY_PWR_STATUS_REG);
        if (!pwr_key)
                return;
@@ -406,13 +671,7 @@ void check_boot_mode(void)
                download_menu();
        else if (key_pressed(KEY_VOLUMEDOWN))
                mode_leave_menu(BOOT_MODE_THOR);
-}
-
-void keys_init(void)
-{
-       /* Set direction to input */
-       gpio_direction_input(KEY_VOL_UP_GPIO);
-       gpio_direction_input(KEY_VOL_DOWN_GPIO);
+#endif
 }
 #endif /* CONFIG_LCD_MENU */
 
@@ -444,6 +703,8 @@ void draw_logo(void)
                printf("Warning: image height is bigger than display height\n");
        }
 
+       lcd_clear();
+
        bmp_display(addr, x, y);
 }
 #endif /* CONFIG_CMD_BMP */
index fe2d2bd..cfa9688 100644 (file)
@@ -11,6 +11,13 @@ u32 get_board_rev(void);
 void set_board_info(void);
 #endif
 
+#if defined(CONFIG_LCD_MENU) || defined(CONFIG_INTERACTIVE_CHARGER)
+void keys_init(void);
+int check_keys(void);
+int key_pressed(int key);
+void check_boot_mode(void);
+#endif /* CONFIG_LCD_MENU || CONFIG_INTERACTIVE_CHARGER */
+
 #ifdef CONFIG_LCD_MENU
 enum {
        BOOT_MODE_INFO,
@@ -21,13 +28,32 @@ enum {
        BOOT_MODE_ENV,
        BOOT_MODE_EXIT,
 };
-
-void keys_init(void);
-int check_keys(void);
-int key_pressed(int key);
-void check_boot_mode(void);
 #endif /* CONFIG_LCD_MENU */
 
+#ifdef CONFIG_INTERACTIVE_CHARGER
+enum {
+       CMD_BATTERY_BOOT_CHECK,
+       CMD_BATTERY_STATE,
+       CMD_BATTERY_CHARGE,
+};
+
+#define CHARGE_TRESHOLD_BOOT                   20
+#define CHARGE_DISPLAY_TIMEOUT_SEC             10
+#define NO_CHARGER_ANIM_TIMEOUT_SEC            10
+#define NO_CHARGER_TIMEOUT_SEC                 30
+#define CHARGE_PWR_KEY_RESET_TIMEOUT           3
+#define CHARGE_KEYS_EXIT_TIMEOUT               3
+
+#define CHARGE_KEYS_EXIT               (KEY_VOLUMEDOWN + KEY_VOLUMEUP)
+
+/* Should be implemented by board */
+int charger_enable(void);
+int charger_type(void);
+int battery_present(void);
+int battery_state(unsigned int *soc);
+void board_low_power_mode(void);
+#endif /* CONFIG_INTERACTIVE_CHARGER */
+
 #ifdef CONFIG_CMD_BMP
 void draw_logo(void);
 #endif