summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2013-02-23 16:36:56 +0800
committerChromeBot <chrome-bot@google.com>2013-02-25 22:22:33 -0800
commit998c0344b55442376fe970c2183e800c9188dfb4 (patch)
treefc012710f2fad3c07b47f775e61444c9ac249b0f
parent9aba3baf15c02f252ba39f7817f94d74c89ec9ad (diff)
downloadchrome-ec-998c0344b55442376fe970c2183e800c9188dfb4.tar.gz
spring: a more aggressive current control approach
Currently we stop raising current input when a predefined limit is reached. To take advantage of high power charger, we now push the limit and detect over current shut off if any. This allows us to detect the actual current limit of the charger. BUG=chrome-os-partner:14319 TEST=Manual on Spring BRANCH=none Change-Id: I5aefd8c0ac02bd0ca9920e861a4fa62fc6e588e5 Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/43863 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/spring/usb_charging.c92
1 files changed, 89 insertions, 3 deletions
diff --git a/board/spring/usb_charging.c b/board/spring/usb_charging.c
index 7efc698062..a7f3e45728 100644
--- a/board/spring/usb_charging.c
+++ b/board/spring/usb_charging.c
@@ -40,7 +40,10 @@
/* PWM control loop parameters */
#define PWM_CTRL_BEGIN_OFFSET 30
-#define PWM_CTRL_STEP_DOWN 1
+#define PWM_CTRL_OC_MARGIN 15
+#define PWM_CTRL_OC_DETECT_TIME (800 * MSEC)
+#define PWM_CTRL_OC_BACK_OFF 3
+#define PWM_CTRL_STEP_DOWN 2
#define PWM_CTRL_STEP_UP 5
#define PWM_CTRL_VBUS_LOW 4500
#define PWM_CTRL_VBUS_HIGH 4700 /* Must be higher than 4.5V */
@@ -49,6 +52,24 @@ static int current_dev_type = TSU6721_TYPE_NONE;
static int nominal_pwm_duty;
static int current_pwm_duty;
+static enum {
+ LIMIT_NORMAL,
+ LIMIT_AGGRESSIVE,
+} current_limit_mode;
+
+/*
+ * Last time we see a power source removed. Also records the power source
+ * type and PWM duty cycle at that moment.
+ * Index: 0 = Unknown power source.
+ * 1 = Recognized power source.
+ */
+static timestamp_t power_removed_time[2];
+static uint32_t power_removed_type[2];
+static int power_removed_pwm_duty[2];
+
+/* PWM duty cycle limit based on over current event */
+static int over_current_pwm_duty;
+
static enum ilim_config current_ilim_config = ILIM_CONFIG_MANUAL_OFF;
static const int apple_charger_type[4] = {I_LIMIT_500MA,
@@ -180,6 +201,18 @@ void board_pwm_init_limit(void)
board_ilim_config(ILIM_CONFIG_MANUAL_ON);
}
+static int board_pwm_check_lower_bound(void)
+{
+ if (current_limit_mode == LIMIT_AGGRESSIVE)
+ return (current_pwm_duty > nominal_pwm_duty -
+ PWM_CTRL_OC_MARGIN &&
+ current_pwm_duty > over_current_pwm_duty &&
+ current_pwm_duty > 0);
+ else
+ return (current_pwm_duty > nominal_pwm_duty &&
+ current_pwm_duty > 0);
+}
+
static void board_pwm_tweak(void)
{
int vbus, current;
@@ -203,8 +236,7 @@ static void board_pwm_tweak(void)
current >= 0) {
board_pwm_duty_cycle(current_pwm_duty + PWM_CTRL_STEP_UP);
CPRINTF("[%T PWM duty up %d%%]\n", current_pwm_duty);
- } else if (vbus > PWM_CTRL_VBUS_HIGH &&
- current_pwm_duty > nominal_pwm_duty) {
+ } else if (vbus > PWM_CTRL_VBUS_HIGH && board_pwm_check_lower_bound()) {
board_pwm_duty_cycle(current_pwm_duty - PWM_CTRL_STEP_DOWN);
CPRINTF("[%T PWM duty down %d%%]\n", current_pwm_duty);
}
@@ -235,6 +267,36 @@ static void usb_device_change(int dev_type)
if (current_dev_type == dev_type)
return;
+ over_current_pwm_duty = 0;
+
+ /*
+ * When a power source is removed, record time, power source type,
+ * and PWM duty cycle. Then when we see a power source, compare type
+ * and calculate time difference to determine if we have just
+ * encountered an over current event.
+ */
+ if ((current_dev_type & TSU6721_TYPE_VBUS_DEBOUNCED) &&
+ (dev_type == TSU6721_TYPE_NONE)) {
+ int idx = !(current_dev_type == TSU6721_TYPE_VBUS_DEBOUNCED);
+ power_removed_time[idx] = get_time();
+ power_removed_type[idx] = current_dev_type;
+ /*
+ * Considering user may plug/unplug the charger too fast, we
+ * don't limit current to lower than nominal current limit.
+ */
+ power_removed_pwm_duty[idx] = MIN(current_pwm_duty,
+ nominal_pwm_duty);
+ } else if (dev_type & TSU6721_TYPE_VBUS_DEBOUNCED) {
+ int idx = !(dev_type == TSU6721_TYPE_VBUS_DEBOUNCED);
+ timestamp_t now = get_time();
+ now.val -= power_removed_time[idx].val;
+ if (power_removed_type[idx] == dev_type &&
+ now.val < PWM_CTRL_OC_DETECT_TIME) {
+ over_current_pwm_duty = power_removed_pwm_duty[idx] +
+ PWM_CTRL_OC_BACK_OFF;
+ }
+ }
+
/*
* Supply VBUS if needed. If we toggle power output, wait for a moment,
* and then update device type. To avoid race condition, check if power
@@ -377,3 +439,27 @@ static int command_batdebug(int argc, char **argv)
}
DECLARE_CONSOLE_COMMAND(batdebug, command_batdebug,
NULL, NULL, NULL);
+
+static int command_current_limit_mode(int argc, char **argv)
+{
+ if (1 == argc) {
+ if (current_limit_mode == LIMIT_NORMAL)
+ ccprintf("Normal mode\n");
+ else
+ ccprintf("Aggressive mode\n");
+ return EC_SUCCESS;
+ } else if (2 == argc) {
+ if (!strcasecmp(argv[1], "normal"))
+ current_limit_mode = LIMIT_NORMAL;
+ else if (!strcasecmp(argv[1], "aggressive"))
+ current_limit_mode = LIMIT_AGGRESSIVE;
+ else
+ return EC_ERROR_INVAL;
+ return EC_SUCCESS;
+ }
+ return EC_ERROR_INVAL;
+}
+DECLARE_CONSOLE_COMMAND(limitmode, command_current_limit_mode,
+ "[normal | aggressive]",
+ "Set current limit mode",
+ NULL);