diff options
author | Vic Yang <victoryang@chromium.org> | 2013-06-09 17:37:20 +0800 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-06-13 17:21:36 -0700 |
commit | 2a270f5978d974dba0e12f7ac74636a396ce0cde (patch) | |
tree | 69ff2e996bc12461dcdee9868eb75503b819af13 | |
parent | cc9b3464e26e112b2c220455a3938235f8553a2c (diff) | |
download | chrome-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.c | 102 |
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. |