summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-05-14 15:10:52 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-05-17 20:17:25 +0000
commitdc37d4a1d5c8a4a8639d38a0f6291c98feeb1ecf (patch)
tree4dc8f825a7c910f7508a500749d500fb22e72603
parent5fd33410770fbc9b29432fe6ca81a763e6b47ec4 (diff)
downloadchrome-ec-dc37d4a1d5c8a4a8639d38a0f6291c98feeb1ecf.tar.gz
zinger: fast over-current protection
When the supply output is enabled, ensure that we detect quickly any over-current situation by setting an analog watchdog in continuous conversion mode. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=chrome-os-partner:28331 TEST=plug an electronic load to Zinger and see the OCP triggered quickly when we go above the current threshold. Change-Id: I7da50ef242addbd2f4f48f624494daa321ac22b2 Reviewed-on: https://chromium-review.googlesource.com/199924 Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r--board/zinger/hardware.c40
-rw-r--r--board/zinger/usb_pd_policy.c29
2 files changed, 67 insertions, 2 deletions
diff --git a/board/zinger/hardware.c b/board/zinger/hardware.c
index cf71c3ffad..0bafa48839 100644
--- a/board/zinger/hardware.c
+++ b/board/zinger/hardware.c
@@ -116,6 +116,10 @@ static void adc_init(void)
STM32_ADC_CFGR2 = 0;
/* Sampling time : 13.5 ADC clock cycles. */
STM32_ADC_SMPR = 2;
+ /* Disable interrupts */
+ STM32_ADC_IER = 0;
+ /* Analog watchdog IRQ */
+ task_enable_irq(STM32_IRQ_ADC_COMP);
}
static void uart_init(void)
@@ -171,7 +175,7 @@ int adc_read_channel(enum adc_channel ch)
/* Select channel to convert */
STM32_ADC_CHSELR = 1 << ch;
/* Clear flags */
- STM32_ADC_ISR = 0xe;
+ STM32_ADC_ISR = 0x8e;
/* Start conversion */
STM32_ADC_CR |= 1 << 2; /* ADSTART */
/* Wait for end of conversion */
@@ -183,6 +187,40 @@ int adc_read_channel(enum adc_channel ch)
return value;
}
+int adc_enable_watchdog(int ch, int high, int low)
+{
+ /* Set thresholds */
+ STM32_ADC_TR = ((high & 0xfff) << 16) | (low & 0xfff);
+ /* Select channel to convert */
+ STM32_ADC_CHSELR = 1 << ch;
+ /* Clear flags */
+ STM32_ADC_ISR = 0x8e;
+ /* Set Watchdog enable bit on a single channel / continuous mode */
+ STM32_ADC_CFGR1 = (ch << 26) | (1 << 23) | (1 << 22)
+ | (1 << 13) | (1 << 12);
+ /* Enable watchdog interrupt */
+ STM32_ADC_IER = 1 << 7;
+ /* Start continuous conversion */
+ STM32_ADC_CR |= 1 << 2; /* ADSTART */
+
+ return EC_SUCCESS;
+}
+
+int adc_disable_watchdog(void)
+{
+ /* Stop on-going conversion */
+ STM32_ADC_CR |= 1 << 4; /* ADSTP */
+ /* Wait for conversion to stop */
+ while (STM32_ADC_CR & (1 << 4))
+ ;
+ /* CONT=0 -> continuous mode off / Clear Watchdog enable */
+ STM32_ADC_CFGR1 = 1 << 12;
+ /* Disable interrupt */
+ STM32_ADC_IER = 0;
+
+ return EC_SUCCESS;
+}
+
/* ---- flash handling ---- */
/*
diff --git a/board/zinger/usb_pd_policy.c b/board/zinger/usb_pd_policy.c
index c55f33561c..a23328bc3a 100644
--- a/board/zinger/usb_pd_policy.c
+++ b/board/zinger/usb_pd_policy.c
@@ -9,6 +9,7 @@
#include "console.h"
#include "debug.h"
#include "hooks.h"
+#include "irq_handler.h"
#include "registers.h"
#include "sha1.h"
#include "timer.h"
@@ -59,6 +60,7 @@ static inline int output_is_enabled(void)
enum faults {
FAULT_OK = 0,
FAULT_OCP, /* Over-Current Protection */
+ FAULT_FAST_OCP, /* Over-Current Protection for interrupt context */
FAULT_OVP, /* Under or Over-Voltage Protection */
};
@@ -161,6 +163,9 @@ int pd_set_power_supply_ready(void)
return EC_ERROR_INVAL;
output_enable();
+ /* Over-current monitoring */
+ adc_enable_watchdog(ADC_CH_A_SENSE, MAX_CURRENT, 0);
+
return EC_SUCCESS; /* we are ready */
}
@@ -171,16 +176,28 @@ void pd_power_supply_reset(void)
volt_idx = 0;
set_output_voltage(VO_5V);
/* TODO transition delay */
+
+ /* Stop OCP monitoring to save power */
+ adc_disable_watchdog();
}
int pd_board_checks(void)
{
int vbus_volt, vbus_amp;
+ int watchdog_enabled = STM32_ADC_CFGR1 & (1 << 23);
+
+ if (watchdog_enabled)
+ /* if the watchdog is enabled, stop it to do other readings */
+ adc_disable_watchdog();
vbus_volt = adc_read_channel(ADC_CH_V_SENSE);
vbus_amp = adc_read_channel(ADC_CH_A_SENSE);
- if (vbus_amp > MAX_CURRENT) {
+ if (watchdog_enabled)
+ /* re-enable fast OCP */
+ adc_enable_watchdog(ADC_CH_A_SENSE, MAX_CURRENT, 0);
+
+ if ((fault == FAULT_FAST_OCP) || (vbus_amp > MAX_CURRENT)) {
debug_printf("OverCurrent : %d mA\n",
vbus_amp * VDDA_MV / CURR_GAIN * 1000 / R_SENSE / ADC_SCALE);
fault = FAULT_OCP;
@@ -208,6 +225,16 @@ int pd_board_checks(void)
}
+void IRQ_HANDLER(STM32_IRQ_ADC_COMP)(void)
+{
+ /* cut the power output */
+ pd_power_supply_reset();
+ /* Clear flags */
+ STM32_ADC_ISR = 0x8e;
+ /* record a special fault, the normal check will record the timeout */
+ fault = FAULT_FAST_OCP;
+}
+
/* ----------------- Vendor Defined Messages ------------------ */
int pd_custom_vdm(void *ctxt, int cnt, uint32_t *payload, uint32_t **rpayload)
{