spring: support new ID detection circuit

This enables the EC to switch the signals to ANX7808 properly.

BUG=chrome-os-partner:18165
TEST=Manual on reworked Spring board
BRANCH=none

Change-Id: Ib3ff57e17afab9ba8fc78fdb037e65aae844f38b
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/44897
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Vic Yang
2013-03-08 09:22:54 +08:00
committed by ChromeBot
parent f568b82321
commit a44e0d91c8
2 changed files with 78 additions and 11 deletions

View File

@@ -27,8 +27,11 @@
#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
/* Devices that need VBUS power */
#define POWERED_DEVICE_TYPE (TSU6721_TYPE_OTG | \
TSU6721_TYPE_JIG_UART_ON)
#define POWERED_5000_DEVICE_TYPE (TSU6721_TYPE_OTG)
#define POWERED_3300_DEVICE_TYPE (TSU6721_TYPE_JIG_UART_ON)
/* Voltage threshold of D+ for video */
#define VIDEO_ID_THRESHOLD 1335
/* PWM controlled current limit */
#define I_LIMIT_500MA 90
@@ -50,6 +53,11 @@
#define PWM_CTRL_VBUS_LOW 4500
#define PWM_CTRL_VBUS_HIGH 4700 /* Must be higher than 4.5V */
/* Delay for signals to settle */
#define DELAY_POWER_MS 20
#define DELAY_USB_DP_DN_MS 20
#define DELAY_ID_MUX_MS 30
static int current_dev_type = TSU6721_TYPE_NONE;
static int nominal_pwm_duty;
static int current_pwm_duty;
@@ -163,7 +171,7 @@ static int board_apple_charger_current(void)
tsu6721_disable_interrupts();
tsu6721_mux(TSU6721_MUX_USB);
/* Wait 20ms for signal to stablize */
msleep(20);
msleep(DELAY_USB_DP_DN_MS);
adc_read_all_channels(data);
vp = data[ADC_CH_USB_DP_SNS];
vn = data[ADC_CH_USB_DN_SNS];
@@ -177,6 +185,26 @@ static int board_apple_charger_current(void)
return apple_charger_type[type];
}
static int board_probe_video(int device_type)
{
tsu6721_disable_interrupts();
gpio_set_level(GPIO_ID_MUX, 0);
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, 1);
msleep(DELAY_ID_MUX_MS);
tsu6721_enable_interrupts();
return device_type;
} else {
/* Not USB host but video */
device_type = (device_type & ~TSU6721_TYPE_USB_HOST) |
TSU6721_TYPE_JIG_UART_ON;
return device_type;
}
}
void board_pwm_duty_cycle(int percent)
{
if (current_ilim_config != ILIM_CONFIG_PWM)
@@ -270,6 +298,14 @@ void usb_charge_interrupt(enum gpio_signal signal)
task_wake(TASK_ID_PMU_TPS65090_CHARGER);
}
static int usb_has_power_input(int dev_type)
{
if (dev_type & TSU6721_TYPE_JIG_UART_ON)
return 1;
return (dev_type & TSU6721_TYPE_VBUS_DEBOUNCED) &&
!(dev_type & POWERED_5000_DEVICE_TYPE);
}
static void usb_device_change(int dev_type)
{
int need_boost;
@@ -280,6 +316,13 @@ static void usb_device_change(int dev_type)
over_current_pwm_duty = 0;
/*
* Video output is recognized incorrectly as USB host. When we see
* USB host, probe for video output.
*/
if (dev_type & TSU6721_TYPE_USB_HOST)
dev_type = board_probe_video(dev_type);
/*
* When a power source is removed, record time, power source type,
* and PWM duty cycle. Then when we see a power source, compare type
@@ -309,24 +352,28 @@ static void usb_device_change(int dev_type)
}
/*
* Supply VBUS if needed. If we toggle power output, wait for a moment,
* and then update device type. To avoid race condition, check if power
* requirement changes during this time.
* Supply 5V VBUS if needed. If we toggle power output, wait for a
* moment, and then update device type. To avoid race condition, check
* if power requirement changes during this time.
*/
do {
if (retry_limit-- <= 0)
break;
need_boost = !(dev_type & POWERED_DEVICE_TYPE);
need_boost = !(dev_type & POWERED_5000_DEVICE_TYPE);
if (need_boost != gpio_get_level(GPIO_BOOST_EN)) {
gpio_set_level(GPIO_BOOST_EN, need_boost);
msleep(20);
msleep(DELAY_POWER_MS);
dev_type = tsu6721_get_device_type();
}
} while (need_boost == !!(dev_type & POWERED_DEVICE_TYPE));
} while (need_boost == !!(dev_type & POWERED_5000_DEVICE_TYPE));
if ((dev_type & TSU6721_TYPE_VBUS_DEBOUNCED) &&
!(dev_type & POWERED_DEVICE_TYPE)) {
/* Supply 3.3V VBUS if needed. */
if (dev_type & POWERED_3300_DEVICE_TYPE) {
pmu_enable_fet(FET_VIDEO, 1, NULL);
}
if (usb_has_power_input(dev_type)) {
/* Limit USB port current. 500mA for not listed types. */
int current_limit = I_LIMIT_500MA;
if (dev_type & TSU6721_TYPE_CHG12)
@@ -376,6 +423,25 @@ static void usb_device_change(int dev_type)
current_dev_type = dev_type;
}
/*
* TODO(victoryang): Get rid of polling loop when ADC watchdog is ready.
* See crosbug.com/p/18171
*/
static void board_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) {
pmu_enable_fet(FET_VIDEO, 0, NULL);
gpio_set_level(GPIO_ID_MUX, 1);
msleep(DELAY_ID_MUX_MS);
tsu6721_enable_interrupts();
usb_device_change(TSU6721_TYPE_NONE);
}
}
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();

View File

@@ -69,6 +69,7 @@ enum FASTCHARGE_TIMEOUT {
};
#define FET_BACKLIGHT 1
#define FET_VIDEO 2
#define FET_WWAN 3
#define FET_CAMERA 5
#define FET_LCD_PANEL 6