From a041fe062a1122301fb0f5a7113b14dc8c33e782 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 Original-Change-Id: Ic035b7332e07ca385d766c735ce39efd31e46034 Signed-off-by: Vic Yang Reviewed-on: https://gerrit.chromium.org/gerrit/49578 Reviewed-by: Vincent Palatin Change-Id: Ia6cbbe102491642c514cb47919793b96e20efbbe Signed-off-by: Vic Yang Reviewed-on: https://gerrit.chromium.org/gerrit/49715 Reviewed-by: Vincent Palatin --- board/spring/usb_charging.c | 104 +++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 36 deletions(-) diff --git a/board/spring/usb_charging.c b/board/spring/usb_charging.c index f17a455bb1..1abec4ea82 100644 --- a/board/spring/usb_charging.c +++ b/board/spring/usb_charging.c @@ -79,7 +79,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, @@ -89,6 +90,7 @@ static enum { static enum { ADC_WATCH_NONE, ADC_WATCH_TOAD, + ADC_WATCH_VIDEO, } current_watchdog = ADC_WATCH_NONE; struct { @@ -308,7 +310,7 @@ static int board_pwm_check_vbus_low(int vbus, int battery_current) return vbus < PWM_CTRL_VBUS_HARD_LOW && current_pwm_duty < 100; } -static void board_pwm_tweak(void) +static void board_power_tweak(void) { int vbus, current; @@ -316,6 +318,15 @@ static void board_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; @@ -342,7 +353,7 @@ static void board_pwm_tweak(void) CPRINTF("[%T PWM duty down %d%%]\n", current_pwm_duty); } } -DECLARE_HOOK(HOOK_SECOND, board_pwm_tweak, HOOK_PRIO_DEFAULT); +DECLARE_HOOK(HOOK_SECOND, board_power_tweak, HOOK_PRIO_DEFAULT); void board_pwm_nominal_duty_cycle(int percent) { @@ -371,13 +382,43 @@ static void board_adc_watch_toad(void) current_watchdog = ADC_WATCH_TOAD; } -static void board_adc_watchdog_interrupt(void) +static void board_adc_watch_video(void) { - if (current_watchdog == ADC_WATCH_TOAD) { - pending_tsu6721_reset = 1; - task_disable_irq(STM32_IRQ_ADC_1); - task_wake(TASK_ID_PMU_TPS65090_CHARGER); + 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 void board_adc_watchdog_interrupt(void) +{ + 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_PMU_TPS65090_CHARGER); } DECLARE_IRQ(STM32_IRQ_ADC_1, board_adc_watchdog_interrupt, 2); @@ -507,7 +548,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; @@ -533,6 +573,8 @@ static void usb_device_change(int dev_type) if ((dev_type & TOAD_DEVICE_TYPE) && (dev_type & TSU6721_TYPE_VBUS_DEBOUNCED)) board_adc_watch_toad(); + else if (dev_type & TSU6721_TYPE_JIG_UART_ON) + board_adc_watch_video(); usb_log_dev_type(dev_type); @@ -545,46 +587,36 @@ static void usb_device_change(int dev_type) enable_sleep(SLEEP_MASK_USB_PWR); } -/* - * TODO(victoryang): Get rid of polling loop when ADC watchdog is ready. - * See crosbug.com/p/18171 - */ -static void board_usb_monitor_detach(void) +void board_usb_charge_update(int force_update) { - int vbus; + int int_val = 0; + int want_reset = 0; - if (!(current_dev_type & TSU6721_TYPE_JIG_UART_ON)) - return; + if (pending_video_detach || pending_toad_redetect) { + current_watchdog = ADC_WATCH_NONE; + adc_disable_watchdog(); + want_reset = 1; + } - if (adc_read_channel(ADC_CH_USB_DP_SNS) > VIDEO_ID_THRESHOLD) { + if (pending_video_detach) { 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, board_usb_monitor_detach, HOOK_PRIO_DEFAULT); + pending_video_detach = 0; + pending_toad_redetect = 0; -void board_usb_charge_update(int force_update) -{ - int int_val = 0; + if (!want_reset) { + int_val = tsu6721_get_interrupts(); + want_reset = (int_val & TSU6721_INT_DETACH); + } - if (pending_tsu6721_reset) { - current_watchdog = ADC_WATCH_NONE; - adc_disable_watchdog(); + 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); -- cgit v1.2.1