From 7de52688be2f1b06a2cbd61da0f86b5b0c489b7e Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Mon, 29 Apr 2013 18:53:42 +0800 Subject: Monitor video detachment with ADC watchdog This eliminates a per-second hook and removes a duplicated ADC read per second. Also, TSU6721 is now reset after every detachment. This way, we don't suffer from TSU6721 dirty state (most commonly seen after OTG dongle detached.) BUG=chrome-os-partner:17928 TEST=1. Test plugging/unplugging video dongle. 2. Test Toad cable mode switching. 3. Test charging with 200K charger. BRANCH=spring Change-Id: Ic035b7332e07ca385d766c735ce39efd31e46034 Signed-off-by: Vic Yang Reviewed-on: https://gerrit.chromium.org/gerrit/49578 Reviewed-by: Vincent Palatin --- common/extpower_usb.c | 113 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/common/extpower_usb.c b/common/extpower_usb.c index 98200542e0..895406861f 100644 --- a/common/extpower_usb.c +++ b/common/extpower_usb.c @@ -86,7 +86,8 @@ static int nominal_pwm_duty; static int current_pwm_duty; static int user_pwm_duty = -1; -static int pending_tsu6721_reset; +static int pending_toad_redetect; +static int pending_video_detach; static enum { LIMIT_NORMAL, @@ -96,6 +97,7 @@ static enum { static enum { ADC_WATCH_NONE, ADC_WATCH_TOAD, + ADC_WATCH_VIDEO, } current_watchdog = ADC_WATCH_NONE; struct { @@ -331,6 +333,34 @@ static void adc_watch_toad(void) current_watchdog = ADC_WATCH_TOAD; } +static void adc_watch_video(void) +{ + int retry_count = 10; + + /* + * Let DP_SNS voltage settle so that we don't trigger watchdog + * unintentionally. + */ + while (retry_count-- && + adc_read_channel(ADC_CH_USB_DP_SNS) > VIDEO_ID_THRESHOLD) + msleep(20); + + /* DP_SNS kept high. Assuming dongle detached already. */ + if (retry_count <= 0) { + pending_video_detach = 1; + return; + } + + /* + * Watch DP_SNS and interrupt if voltage goes above + * VIDEO_ID_THRESHOLD + */ + adc_enable_watchdog(STM32_AIN(2), VIDEO_ID_THRESHOLD * 4096 / 3300, 0); + task_clear_pending_irq(STM32_IRQ_ADC_1); + task_enable_irq(STM32_IRQ_ADC_1); + current_watchdog = ADC_WATCH_VIDEO; +} + static int usb_has_power_input(int dev_type) { if (dev_type & TSU6721_TYPE_JIG_UART_ON) @@ -457,7 +487,6 @@ static void usb_log_dev_type(int dev_type) static void usb_device_change(int dev_type) { - if (current_dev_type == dev_type) return; @@ -483,6 +512,8 @@ 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_JIG_UART_ON) + adc_watch_video(); usb_log_dev_type(dev_type); @@ -532,15 +563,33 @@ void extpower_charge_init(void) void extpower_charge_update(int force_update) { int int_val = 0; + int want_reset = 0; - if (pending_tsu6721_reset) { + if (pending_video_detach || pending_toad_redetect) { current_watchdog = ADC_WATCH_NONE; adc_disable_watchdog(); + want_reset = 1; + } + + if (pending_video_detach) { + set_video_power(0); + gpio_set_level(GPIO_ID_MUX, 0); + msleep(DELAY_ID_MUX_MS); + tsu6721_enable_interrupts(); + } + + pending_video_detach = 0; + pending_toad_redetect = 0; + + if (!want_reset) { + int_val = tsu6721_get_interrupts(); + want_reset = (int_val & TSU6721_INT_DETACH); + } + + if (want_reset) { tsu6721_reset(); force_update = 1; - pending_tsu6721_reset = 0; - } else - int_val = tsu6721_get_interrupts(); + } if (int_val & TSU6721_INT_DETACH) usb_device_change(TSU6721_TYPE_NONE); @@ -583,11 +632,12 @@ void extpower_interrupt(enum gpio_signal signal) static void adc_watchdog_interrupt(void) { - if (current_watchdog == ADC_WATCH_TOAD) { - pending_tsu6721_reset = 1; - task_disable_irq(STM32_IRQ_ADC_1); - task_wake(TASK_ID_CHARGER); - } + if (current_watchdog == ADC_WATCH_TOAD) + pending_toad_redetect = 1; + else if (current_watchdog == ADC_WATCH_VIDEO) + pending_video_detach = 1; + task_disable_irq(STM32_IRQ_ADC_1); + task_wake(TASK_ID_CHARGER); } DECLARE_IRQ(STM32_IRQ_ADC_1, adc_watchdog_interrupt, 2); @@ -603,7 +653,7 @@ static void usb_boost_pwr_off_hook(void) } DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, usb_boost_pwr_off_hook, HOOK_PRIO_DEFAULT); -static void pwm_tweak(void) +static void power_tweak(void) { int vbus, current; @@ -611,6 +661,15 @@ static void pwm_tweak(void) return; vbus = adc_read_channel(ADC_CH_USB_VBUS_SNS); + + /* Check video power input change */ + if (current_dev_type & TSU6721_TYPE_JIG_UART_ON) { + if (get_video_power() && vbus > 4000) + set_video_power(0); + else if (!get_video_power() && vbus <= 4000) + set_video_power(1); + } + if (battery_current(¤t)) return; @@ -637,35 +696,7 @@ static void pwm_tweak(void) CPRINTF("[%T PWM duty down %d%%]\n", current_pwm_duty); } } -DECLARE_HOOK(HOOK_SECOND, pwm_tweak, HOOK_PRIO_DEFAULT); - -/* - * TODO(victoryang): Get rid of polling loop when ADC watchdog is ready. - * See crosbug.com/p/18171 - */ -static void usb_monitor_detach(void) -{ - int vbus; - - 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); - } - - /* Check if there is external power */ - vbus = adc_read_channel(ADC_CH_USB_VBUS_SNS); - if (get_video_power() && vbus > 4000) - set_video_power(0); - else if (!get_video_power() && vbus <= 4000) - set_video_power(1); -} -DECLARE_HOOK(HOOK_SECOND, usb_monitor_detach, HOOK_PRIO_DEFAULT); +DECLARE_HOOK(HOOK_SECOND, power_tweak, HOOK_PRIO_DEFAULT); /*****************************************************************************/ /* -- cgit v1.2.1