summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2013-06-09 17:37:20 +0800
committerChromeBot <chrome-bot@google.com>2013-06-13 17:21:36 -0700
commit2a270f5978d974dba0e12f7ac74636a396ce0cde (patch)
tree69ff2e996bc12461dcdee9868eb75503b819af13
parentcc9b3464e26e112b2c220455a3938235f8553a2c (diff)
downloadchrome-ec-2a270f5978d974dba0e12f7ac74636a396ce0cde.tar.gz
Incorporate CABLE_DET circuit change
Now that when ID_MUX=1, DP_SNS can be connected to either ID_OUT or CABLE_DET, we need to handle the case where a video dongle is not reflected by DP_SNS going low. This is done by leaving ID_MUX=1 for USB host and monitor its detachment by sensing VBUS. As for unpowered dongle, we just ignore it when it's not recognized. Note that due to the polarity of CABLE_DET, we now sense dongle detachement by DP_SNS < 0.25V. To support older boards with ID_OUT connected, we also disconnect video dongle on system suspend and shutdown. BUG=chrome-os-partner:19911 TEST=Powered/unpowered video dongle detected correctly. TEST=Add a console command to simulate CABLE_DET being high. With that, check battery charges with powered video dongle. Check nothing happens with unpowered video dongle. TEST=Check video dongle considered disconnected when OTG dongle plugged in or system shutdown. BRANCH=spring Change-Id: If7b530b67c98c85017ca663d43c5148f0eb9163c Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/58070 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--common/extpower_usb.c102
1 files changed, 81 insertions, 21 deletions
diff --git a/common/extpower_usb.c b/common/extpower_usb.c
index 17ad401001..51068452e6 100644
--- a/common/extpower_usb.c
+++ b/common/extpower_usb.c
@@ -46,7 +46,7 @@ enum ilim_config {
#define TOAD_DEVICE_TYPE (TSU6721_TYPE_UART | TSU6721_TYPE_AUDIO3)
/* Voltage threshold of D+ for video */
-#define VIDEO_ID_THRESHOLD 1335
+#define VIDEO_ID_THRESHOLD 250
/*
* Mapping from PWM duty to current:
@@ -97,6 +97,7 @@ static int user_pwm_duty = -1;
static int pwm_fast_mode;
static int pending_tsu6721_reset;
+static int restore_id_mux;
static enum {
LIMIT_NORMAL,
@@ -106,6 +107,7 @@ static enum {
static enum {
ADC_WATCH_NONE,
ADC_WATCH_TOAD,
+ ADC_WATCH_USB,
} current_watchdog = ADC_WATCH_NONE;
struct {
@@ -284,12 +286,24 @@ static int probe_video(int device_type)
gpio_set_level(GPIO_ID_MUX, 1);
msleep(DELAY_ID_MUX_MS);
- if (adc_read_channel(ADC_CH_USB_DP_SNS) > VIDEO_ID_THRESHOLD) {
- /* Actually an USB host */
- gpio_set_level(GPIO_ID_MUX, 0);
- msleep(DELAY_ID_MUX_MS);
- tsu6721_enable_interrupts();
- return device_type;
+ if (adc_read_channel(ADC_CH_USB_DP_SNS) < VIDEO_ID_THRESHOLD) {
+ if (device_type & TSU6721_TYPE_VBUS_DEBOUNCED) {
+ /*
+ * Either USB host or video dongle.
+ * Leave ID_MUX high so we see the change on
+ * DP_SNS if any.
+ *
+ * ADC watchdog is responsible for sensing a
+ * detach event and switch back ID_MUX.
+ */
+ return device_type;
+ } else {
+ /* Unhandled unpowered video dongle. Ignore it. */
+ gpio_set_level(GPIO_ID_MUX, 0);
+ msleep(DELAY_ID_MUX_MS);
+ tsu6721_enable_interrupts();
+ return TSU6721_TYPE_NONE;
+ }
} else {
/* Not USB host but video */
device_type = video_dev_type(device_type);
@@ -369,15 +383,27 @@ static void pwm_nominal_duty_cycle(int percent)
pwm_fast_mode = 1;
}
-static void adc_watch_toad(void)
+static void adc_watch_vbus(int high, int low)
{
- /* Watch VBUS and interrupt if voltage goes under 3V. */
- adc_enable_watchdog(STM32_AIN(5), 4095, 1800);
+ adc_enable_watchdog(STM32_AIN(5), high, low);
task_clear_pending_irq(STM32_IRQ_ADC_1);
task_enable_irq(STM32_IRQ_ADC_1);
+}
+
+static void adc_watch_toad(void)
+{
+ /* Watch VBUS and interrupt if voltage goes under 3V. */
+ adc_watch_vbus(4095, 1800);
current_watchdog = ADC_WATCH_TOAD;
}
+static void adc_watch_usb(void)
+{
+ /* Watch VBUS and interrupt if voltage goes under 3V. */
+ adc_watch_vbus(4095, 1800);
+ current_watchdog = ADC_WATCH_USB;
+}
+
static int usb_has_power_input(int dev_type)
{
if (dev_type & TSU6721_TYPE_JIG_UART_ON)
@@ -534,12 +560,15 @@ static void usb_device_change(int dev_type)
if ((dev_type & TOAD_DEVICE_TYPE) &&
(dev_type & TSU6721_TYPE_VBUS_DEBOUNCED))
adc_watch_toad();
+ else if (dev_type & TSU6721_TYPE_USB_HOST)
+ adc_watch_usb();
- usb_log_dev_type(dev_type);
-
- keyboard_send_battery_key();
+ if (dev_type != current_dev_type) {
+ usb_log_dev_type(dev_type);
+ keyboard_send_battery_key();
+ current_dev_type = dev_type;
+ }
- current_dev_type = dev_type;
if (dev_type)
disable_sleep(SLEEP_MASK_USB_PWR);
else
@@ -584,6 +613,12 @@ void extpower_charge_update(int force_update)
{
int int_val = 0;
+ if (restore_id_mux) {
+ gpio_set_level(GPIO_ID_MUX, 0);
+ msleep(DELAY_ID_MUX_MS);
+ restore_id_mux = 0;
+ }
+
if (pending_tsu6721_reset) {
current_watchdog = ADC_WATCH_NONE;
adc_disable_watchdog();
@@ -634,10 +669,17 @@ void extpower_interrupt(enum gpio_signal signal)
static void adc_watchdog_interrupt(void)
{
- if (current_watchdog == ADC_WATCH_TOAD) {
+ switch (current_watchdog) {
+ case ADC_WATCH_USB:
+ restore_id_mux = 1;
+ /* Fall through */
+ case ADC_WATCH_TOAD:
pending_tsu6721_reset = 1;
task_disable_irq(STM32_IRQ_ADC_1);
task_wake(TASK_ID_CHARGER);
+ break;
+ default:
+ break;
}
}
DECLARE_IRQ(STM32_IRQ_ADC_1, adc_watchdog_interrupt, 2);
@@ -695,6 +737,18 @@ static void pwm_tweak(void)
}
DECLARE_HOOK(HOOK_SECOND, pwm_tweak, HOOK_PRIO_DEFAULT);
+static void usb_detach_video(void)
+{
+ if (!(current_dev_type & TSU6721_TYPE_JIG_UART_ON))
+ return;
+ set_video_power(0);
+ restore_id_mux = 1;
+ pending_tsu6721_reset = 1;
+ task_wake(TASK_ID_CHARGER);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, usb_detach_video, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, usb_detach_video, HOOK_PRIO_DEFAULT);
+
static void usb_monitor_detach(void)
{
int vbus;
@@ -702,12 +756,8 @@ static void usb_monitor_detach(void)
if (!(current_dev_type & TSU6721_TYPE_JIG_UART_ON))
return;
- if (adc_read_channel(ADC_CH_USB_DP_SNS) > VIDEO_ID_THRESHOLD) {
- set_video_power(0);
- gpio_set_level(GPIO_ID_MUX, 0);
- msleep(DELAY_ID_MUX_MS);
- tsu6721_enable_interrupts();
- usb_device_change(TSU6721_TYPE_NONE);
+ if (adc_read_channel(ADC_CH_USB_DP_SNS) < VIDEO_ID_THRESHOLD) {
+ usb_detach_video();
return;
}
@@ -726,6 +776,16 @@ static void usb_monitor_detach(void)
}
DECLARE_HOOK(HOOK_SECOND, usb_monitor_detach, HOOK_PRIO_DEFAULT);
+static void usb_monitor_cable_det(void)
+{
+ if (!(current_dev_type & TSU6721_TYPE_USB_HOST))
+ return;
+
+ if (adc_read_channel(ADC_CH_USB_DP_SNS) < VIDEO_ID_THRESHOLD)
+ adc_watchdog_interrupt();
+}
+DECLARE_HOOK(HOOK_SECOND, usb_monitor_cable_det, HOOK_PRIO_DEFAULT);
+
/*****************************************************************************/
/*
* Console commands for debugging.