spring: reset TSU6721 when Toad's ID changes

When Toad's ID changes, VBUS goes low for 10ms. This, however, is not
picked up by TSU6721 and thus we need to monitor VBUS and reset TSU6721
when necessary. By resetting TSU6721, we can force it to update device
type.

BUG=chrome-os-partner:18292
TEST=manual
BRANCH=spring

Change-Id: Ib96bbb0f101c8c5f5371591603af2dee27f01cc8
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/45727
This commit is contained in:
Vic Yang
2013-03-18 15:12:05 +08:00
committed by ChromeBot
parent f8d5958b6f
commit 19920f1f74
4 changed files with 66 additions and 3 deletions

View File

@@ -31,6 +31,9 @@
#define POWERED_5000_DEVICE_TYPE (TSU6721_TYPE_OTG)
#define POWERED_3300_DEVICE_TYPE (TSU6721_TYPE_JIG_UART_ON)
/* Toad cable */
#define TOAD_DEVICE_TYPE (TSU6721_TYPE_UART | TSU6721_TYPE_AUDIO3)
/* Voltage threshold of D+ for video */
#define VIDEO_ID_THRESHOLD 1335
@@ -63,11 +66,18 @@ static int current_dev_type = TSU6721_TYPE_NONE;
static int nominal_pwm_duty;
static int current_pwm_duty;
static int pending_tsu6721_reset;
static enum {
LIMIT_NORMAL,
LIMIT_AGGRESSIVE,
} current_limit_mode = LIMIT_AGGRESSIVE;
static enum {
ADC_WATCH_NONE,
ADC_WATCH_TOAD,
} current_watchdog = ADC_WATCH_NONE;
/*
* Last time we see a power source removed. Also records the power source
* type and PWM duty cycle at that moment.
@@ -299,6 +309,25 @@ void usb_charge_interrupt(enum gpio_signal signal)
task_wake(TASK_ID_PMU_TPS65090_CHARGER);
}
static void board_adc_watch_toad(void)
{
/* Watch VBUS and interrupt if voltage goes under 3V. */
adc_enable_watchdog(STM32_AIN(5), 4095, 1800);
task_clear_pending_irq(STM32_IRQ_ADC_1);
task_enable_irq(STM32_IRQ_ADC_1);
current_watchdog = ADC_WATCH_TOAD;
}
static void board_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_PMU_TPS65090_CHARGER);
}
}
DECLARE_IRQ(STM32_IRQ_ADC_1, board_adc_watchdog_interrupt, 2);
static int usb_has_power_input(int dev_type)
{
if (dev_type & TSU6721_TYPE_JIG_UART_ON)
@@ -390,6 +419,10 @@ static void usb_device_change(int dev_type)
board_ilim_config(ILIM_CONFIG_MANUAL_ON);
}
if ((dev_type & TOAD_DEVICE_TYPE) &&
(dev_type & TSU6721_TYPE_VBUS_DEBOUNCED))
board_adc_watch_toad();
/* Log to console */
CPRINTF("[%T USB Attached: ");
if (dev_type == TSU6721_TYPE_NONE)
@@ -412,6 +445,10 @@ static void usb_device_change(int dev_type)
CPRINTF("Apple charger]\n");
else if (dev_type & TSU6721_TYPE_JIG_UART_ON)
CPRINTF("JIG UART ON]\n");
else if (dev_type & TSU6721_TYPE_AUDIO3)
CPRINTF("Audio 3]\n");
else if (dev_type & TSU6721_TYPE_UART)
CPRINTF("UART]\n");
else if (dev_type & TSU6721_TYPE_VBUS_DEBOUNCED)
CPRINTF("Unknown with power]\n");
else
@@ -443,7 +480,16 @@ DECLARE_HOOK(HOOK_SECOND, board_usb_monitor_detach, HOOK_PRIO_DEFAULT);
void board_usb_charge_update(int force_update)
{
int int_val = tsu6721_get_interrupts();
int int_val = 0;
if (pending_tsu6721_reset) {
current_watchdog = ADC_WATCH_NONE;
adc_disable_watchdog();
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);

View File

@@ -97,6 +97,9 @@ static int adc_enable_watchdog_no_lock(void)
/* Set channel */
STM32_ADC_CR1 = (STM32_ADC_CR1 & ~0x1f) | watchdog_ain_id;
/* Clear interrupt bit */
STM32_ADC_SR &= ~0x1;
/* AWDSGL=1, SCAN=1, AWDIE=1, AWDEN=1 */
STM32_ADC_CR1 |= (1 << 9) | (1 << 8) | (1 << 6) | (1 << 23);
@@ -138,8 +141,8 @@ static int adc_disable_watchdog_no_lock(void)
if (!adc_watchdog_enabled())
return EC_ERROR_UNKNOWN;
/* AWDEN=0 */
STM32_ADC_CR1 &= ~(1 << 23);
/* AWDEN=0, AWDIE=0 */
STM32_ADC_CR1 &= ~(1 << 23) & ~(1 << 6);
/* CONT=0 */
STM32_ADC_CR2 &= ~(1 << 1);

View File

@@ -24,6 +24,9 @@
/* 8-bit I2C address */
#define TSU6721_I2C_ADDR (0x25 << 1)
/* Delay values */
#define TSU6721_SW_RESET_DELAY 15
static int saved_interrupts;
uint8_t tsu6721_read(uint8_t reg)
@@ -86,6 +89,14 @@ int tsu6721_get_device_type(void)
(tsu6721_read(TSU6721_REG_DEV_TYPE1));
}
void tsu6721_reset(void)
{
tsu6721_write(TSU6721_REG_RESET, 0x1);
/* TSU6721 reset takes ~10ms. Let's wait for 15ms to be safe. */
msleep(TSU6721_SW_RESET_DELAY);
tsu6721_init();
}
int tsu6721_mux(enum tsu6721_mux sel)
{
uint8_t id = tsu6721_read(TSU6721_REG_ADC);

View File

@@ -105,4 +105,7 @@ int tsu6721_get_device_type(void);
/* Control TSU6721 mux. */
int tsu6721_mux(enum tsu6721_mux sel);
/* Reset TSU6721. */
void tsu6721_reset(void);
#endif /* TSU6721_H */