summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-04-30 17:19:22 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-05-05 18:35:37 +0000
commitb0d1d116556244732752c9c3653560047dd5b28a (patch)
tree094e17138838f6724a98131e554fafe4bf65f3cd
parentd1921632fc8926fa5a566ba14bfe718881fd8bea (diff)
downloadchrome-ec-b0d1d116556244732752c9c3653560047dd5b28a.tar.gz
zinger: implement fault protection
Detect over-current and over-voltage and trigger a fault. The over-current threshold is 10% over 3A (3.3A). Only currently implement the slow protection, the fast interrupt-based one will be done later. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=chrome-os-partner:28331 TEST=with Zinger connected to an electronic load, adjust the current to 3.35A and see the output voltage cut. Change-Id: I0e848192392fd73f0839d4bcb806528b2a6b9122 Reviewed-on: https://chromium-review.googlesource.com/197947 Commit-Queue: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r--board/firefly/usb_pd_policy.c4
-rw-r--r--board/fruitpie/usb_pd_policy.c3
-rw-r--r--board/zinger/usb_pd_policy.c109
-rw-r--r--common/usb_pd_protocol.c13
-rw-r--r--include/usb_pd.h3
5 files changed, 120 insertions, 12 deletions
diff --git a/board/firefly/usb_pd_policy.c b/board/firefly/usb_pd_policy.c
index 4a6d9da103..d00ac47916 100644
--- a/board/firefly/usb_pd_policy.c
+++ b/board/firefly/usb_pd_policy.c
@@ -85,7 +85,7 @@ void pd_power_supply_reset(void)
{
}
-void pd_board_checks(void)
+int pd_board_checks(void)
{
static int blinking;
int vbus;
@@ -122,4 +122,6 @@ void pd_board_checks(void)
gpio_set_level(GPIO_LED_PP5000, led5);
gpio_set_level(GPIO_LED_PP12000, led12);
gpio_set_level(GPIO_LED_PP20000, led20);
+
+ return EC_SUCCESS;
}
diff --git a/board/fruitpie/usb_pd_policy.c b/board/fruitpie/usb_pd_policy.c
index c756dcc7bd..001dafd28f 100644
--- a/board/fruitpie/usb_pd_policy.c
+++ b/board/fruitpie/usb_pd_policy.c
@@ -113,6 +113,7 @@ void pd_power_supply_reset(void)
{
}
-void pd_board_checks(void)
+int pd_board_checks(void)
{
+ return EC_SUCCESS;
}
diff --git a/board/zinger/usb_pd_policy.c b/board/zinger/usb_pd_policy.c
index b506c15aec..de5794771d 100644
--- a/board/zinger/usb_pd_policy.c
+++ b/board/zinger/usb_pd_policy.c
@@ -3,12 +3,14 @@
* found in the LICENSE file.
*/
+#include "adc.h"
#include "board.h"
#include "common.h"
#include "console.h"
#include "debug.h"
#include "hooks.h"
#include "registers.h"
+#include "timer.h"
#include "util.h"
#include "usb_pd.h"
@@ -44,6 +46,50 @@ static inline void output_disable(void)
STM32_GPIO_BSRR(GPIO_F) = GPIO_SET(0);
}
+static inline int output_is_enabled(void)
+{
+ /* GPF0 = FET driver shutdown */
+ return !(STM32_GPIO_IDR(GPIO_F) & 1);
+}
+
+/* ----- fault conditions ----- */
+
+enum faults {
+ FAULT_OK = 0,
+ FAULT_OCP, /* Over-Current Protection */
+ FAULT_OVP, /* Under or Over-Voltage Protection */
+};
+
+/* current fault condition */
+static enum faults fault;
+/* expiration date of the last fault condition */
+static timestamp_t fault_deadline;
+
+/* ADC in 12-bit mode */
+#define ADC_SCALE (1 << 12)
+/* ADC power supply : VDDA = 3.3V */
+#define VDDA_MV 3300
+/* Current sense resistor : 5 milliOhm */
+#define R_SENSE 5
+/* VBUS voltage is measured through 10k / 100k voltage divider = /11 */
+#define VOLT_DIV ((10+110)/10)
+/* The current sensing op-amp has a x101 gain */
+#define CURR_GAIN 101
+/* convert VBUS voltage in raw ADC value */
+#define VBUS_MV(mv) ((mv)*ADC_SCALE/VOLT_DIV/VDDA_MV)
+/* convert VBUS current in raw ADC value */
+#define VBUS_MA(ma) ((ma)*ADC_SCALE*R_SENSE/1000*CURR_GAIN/VDDA_MV)
+
+/* Max current : 10% over 3A = 3.3A */
+#define MAX_CURRENT VBUS_MA(3300)
+/* reset over-current after 1 second */
+#define OCP_TIMEOUT SECOND
+
+/* Under-voltage limit is 0.8x Vnom */
+#define UVP_MV(mv) VBUS_MV((mv) * 8 / 10)
+/* Over-voltage limit is 1.2x Vnom */
+#define OVP_MV(mv) VBUS_MV((mv) * 12 / 10)
+
/* ----------------------- USB Power delivery policy ---------------------- */
/* Power Delivery Objects */
@@ -56,13 +102,20 @@ const uint32_t pd_src_pdo[] = {
const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo);
/* PDO voltages (should match the table above) */
-static enum volt voltages[ARRAY_SIZE(pd_src_pdo)] = {
- VO_5V,
- VO_5V,
- VO_12V,
- VO_20V,
+static const struct {
+ enum volt select; /* GPIO configuration to select the voltage */
+ int uvp; /* under-voltage limit in mV */
+ int ovp; /* over-voltage limit in mV */
+} voltages[ARRAY_SIZE(pd_src_pdo)] = {
+ {VO_5V, UVP_MV(5000), OVP_MV(5000)},
+ {VO_5V, UVP_MV(5000), OVP_MV(5000)},
+ {VO_12V, UVP_MV(12000), OVP_MV(12000)},
+ {VO_20V, UVP_MV(20000), OVP_MV(20000)},
};
+/* currently selected PDO entry */
+static int volt_idx;
+
int pd_request_voltage(uint32_t rdo)
{
int op_ma = rdo & 0x3FF;
@@ -71,6 +124,11 @@ int pd_request_voltage(uint32_t rdo)
uint32_t pdo;
uint32_t pdo_ma;
+
+ /* fault condition not cleared : reject transitions */
+ if (fault != FAULT_OK)
+ return EC_ERROR_INVAL;
+
if (!idx || idx > pd_src_pdo_cnt)
return EC_ERROR_INVAL; /* Invalid index */
@@ -88,13 +146,18 @@ int pd_request_voltage(uint32_t rdo)
output_disable();
/* TODO discharge ? */
- set_output_voltage(voltages[idx-1]);
+ volt_idx = idx - 1;
+ set_output_voltage(voltages[volt_idx].select);
return EC_SUCCESS;
}
int pd_set_power_supply_ready(void)
{
+ /* fault condition not cleared : do not turn on power */
+ if (fault != FAULT_OK)
+ return EC_ERROR_INVAL;
+
output_enable();
return EC_SUCCESS; /* we are ready */
}
@@ -103,10 +166,42 @@ void pd_power_supply_reset(void)
{
output_disable();
/* TODO discharge ? */
+ volt_idx = 0;
set_output_voltage(VO_5V);
/* TODO transition delay */
}
-void pd_board_checks(void)
+int pd_board_checks(void)
{
+ int vbus_volt, vbus_amp;
+
+ vbus_volt = adc_read_channel(ADC_CH_V_SENSE);
+ vbus_amp = adc_read_channel(ADC_CH_A_SENSE);
+
+ if (vbus_amp > MAX_CURRENT) {
+ debug_printf("OverCurrent : %d mA\n",
+ vbus_amp * VDDA_MV / CURR_GAIN * 1000 / R_SENSE / ADC_SCALE);
+ fault = FAULT_OCP;
+ /* reset over-current after 1 second */
+ fault_deadline.val = get_time().val + OCP_TIMEOUT;
+ return EC_ERROR_INVAL;
+ }
+ if (output_is_enabled() && (vbus_volt > voltages[volt_idx].ovp)) {
+ debug_printf("OverVoltage : %d mV\n",
+ vbus_volt * VDDA_MV * VOLT_DIV / ADC_SCALE);
+ /* TODO(crosbug.com/p/28331) discharge */
+ fault = FAULT_OVP;
+ /* no timeout */
+ fault_deadline.val = get_time().val;
+ return EC_ERROR_INVAL;
+ }
+
+ /* everything is good *and* the error condition has expired */
+ if ((fault != FAULT_OK) && (get_time().val > fault_deadline.val)) {
+ fault = FAULT_OK;
+ debug_printf("Reset fault\n");
+ }
+
+ return EC_SUCCESS;
+
}
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 442cccce2d..eee328f046 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -641,7 +641,13 @@ void pd_task(void)
/* monitor for incoming packet */
pd_rx_enable_monitoring();
/* Verify board specific health status : current, voltages... */
- pd_board_checks();
+ res = pd_board_checks();
+ if (res != EC_SUCCESS) {
+ /* cut the power */
+ execute_hard_reset();
+ /* notify the other side of the issue */
+ /* send_hard_reset(ctxt); */
+ }
/* wait for next event/packet or timeout expiration */
task_wait_event(timeout);
/* incoming packet ? */
@@ -667,6 +673,8 @@ void pd_task(void)
(cc2_volt < PD_SRC_VNC)) {
pd_polarity = !(cc1_volt < PD_SRC_VNC);
pd_select_polarity(pd_polarity);
+ /* Enable VBUS */
+ pd_set_power_supply_ready();
pd_task_state = PD_STATE_SRC_DISCOVERY;
}
timeout = 10*MSEC;
@@ -705,7 +713,8 @@ void pd_task(void)
/* Verify that the sink is alive */
res = send_control(ctxt, PD_CTRL_PING);
if (res < 0) {
- /* The sink died ... TODO */
+ /* The sink died ... */
+ pd_power_supply_reset();
pd_task_state = PD_STATE_SRC_DISCOVERY;
timeout = PD_T_SEND_SOURCE_CAP;
} else { /* schedule next keep-alive */
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 84d98dff9b..659fc5cd54 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -153,8 +153,9 @@ void pd_request_source_voltage(int mv);
/*
* Verify board specific health status : current, voltages...
*
+ * @return EC_SUCCESS if the board is good, <0 else.
*/
-void pd_board_checks(void);
+int pd_board_checks(void);
/* Power Data Objects for the source and the sink */
extern const uint32_t pd_src_pdo[];