summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2012-12-26 16:47:38 +0800
committerChromeBot <chrome-bot@google.com>2013-02-07 22:06:05 -0800
commitc93378dafad7229e34719165c09f31e15b6300d8 (patch)
tree23e534457a91ee7e323d615110ddb876e7f77040
parentf84a5fa8b1f6d688c73a1e6e9b33df79489cbfef (diff)
downloadchrome-ec-stabilize-bluetooth-smart.tar.gz
spring: Distinguish Apple Chargersstabilize-bluetooth-smart
This uses D+/D- voltage to distinguish different Apple chargers. BUG=chrome-os-partner:14319 TEST=Manual on Spring BRANCH=none Change-Id: I50075d466f6e6b1adf613748cf433d7f43c04bfe Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/42850 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/spring/usb_charging.c39
-rw-r--r--common/tsu6721.c27
-rw-r--r--include/tsu6721.h13
3 files changed, 61 insertions, 18 deletions
diff --git a/board/spring/usb_charging.c b/board/spring/usb_charging.c
index b919ec851b..e1b9029bcb 100644
--- a/board/spring/usb_charging.c
+++ b/board/spring/usb_charging.c
@@ -5,11 +5,13 @@
/* USB charging control for spring board */
+#include "adc.h"
#include "board.h"
#include "console.h"
#include "gpio.h"
#include "lp5562.h"
#include "registers.h"
+#include "stm32_adc.h"
#include "task.h"
#include "timer.h"
#include "tsu6721.h"
@@ -27,13 +29,19 @@
/* PWM controlled current limit */
#define I_LIMIT_500MA 85
-#define I_LIMIT_1000MA 70
+#define I_LIMIT_1000MA 75
#define I_LIMIT_1500MA 50
#define I_LIMIT_2000MA 35
+#define I_LIMIT_2400MA 25
#define I_LIMIT_3000MA 0
static enum ilim_config current_ilim_config = ILIM_CONFIG_MANUAL_OFF;
+static const int apple_charger_type[4] = {I_LIMIT_500MA,
+ I_LIMIT_1000MA,
+ I_LIMIT_2000MA,
+ I_LIMIT_2400MA};
+
static void board_ilim_use_gpio(void)
{
/* Disable counter */
@@ -107,6 +115,31 @@ void board_ilim_config(enum ilim_config config)
}
}
+/* Returns Apple charger current limit */
+static int board_apple_charger_current(void)
+{
+ int vp, vn;
+ int type = 0;
+ int data[ADC_CH_COUNT];
+
+ /* TODO(victoryang): Handle potential race condition. */
+ tsu6721_disable_interrupts();
+ tsu6721_mux(TSU6721_MUX_USB);
+ /* Wait 20ms for signal to stablize */
+ msleep(20);
+ adc_read_all_channels(data);
+ vp = data[ADC_CH_USB_DP_SNS];
+ vn = data[ADC_CH_USB_DN_SNS];
+ tsu6721_mux(TSU6721_MUX_AUTO);
+ tsu6721_enable_interrupts();
+ if (vp > 1200)
+ type |= 0x2;
+ if (vn > 1200)
+ type |= 0x1;
+
+ return apple_charger_type[type];
+}
+
void board_pwm_duty_cycle(int percent)
{
if (current_ilim_config != ILIM_CONFIG_PWM)
@@ -143,8 +176,7 @@ static void usb_device_change(int dev_type)
if (dev_type & TSU6721_TYPE_CHG12)
current_limit = I_LIMIT_3000MA;
else if (dev_type & TSU6721_TYPE_APPLE_CHG) {
- /* TODO: Distinguish 1A/2A chargers. */
- current_limit = I_LIMIT_1000MA;
+ current_limit = board_apple_charger_current();
} else if ((dev_type & TSU6721_TYPE_CDP) ||
(dev_type & TSU6721_TYPE_DCP))
current_limit = I_LIMIT_1500MA;
@@ -154,6 +186,7 @@ static void usb_device_change(int dev_type)
/* Turns on battery LED */
lp5562_poweron();
} else {
+ board_ilim_config(ILIM_CONFIG_MANUAL_ON);
lp5562_poweroff();
}
diff --git a/common/tsu6721.c b/common/tsu6721.c
index ba6d3ad4b0..8ea369c463 100644
--- a/common/tsu6721.c
+++ b/common/tsu6721.c
@@ -45,20 +45,24 @@ void tsu6721_write(uint8_t reg, uint8_t val)
CPRINTF("[%T TSU6721 I2C write failed]\n");
}
-void tsu6721_enable_interrupts(int mask)
+void tsu6721_enable_interrupts(void)
{
int ctrl = tsu6721_read(TSU6721_REG_CONTROL);
- tsu6721_write(TSU6721_REG_INT_MASK1, (~mask) & 0xff);
- tsu6721_write(TSU6721_REG_INT_MASK2, ((~mask) >> 8) & 0xff);
tsu6721_write(TSU6721_REG_CONTROL, ctrl & 0x1e);
}
-void tsu6721_disable_interrupt(void)
+void tsu6721_disable_interrupts(void)
{
int ctrl = tsu6721_read(TSU6721_REG_CONTROL);
tsu6721_write(TSU6721_REG_CONTROL, ctrl | 0x1);
}
+void tsu6721_set_interrupt_mask(uint16_t mask)
+{
+ tsu6721_write(TSU6721_REG_INT_MASK1, (~mask) & 0xff);
+ tsu6721_write(TSU6721_REG_INT_MASK2, ((~mask) >> 8) & 0xff);
+}
+
int tsu6721_get_interrupts(void)
{
return (tsu6721_read(TSU6721_REG_INT1) << 8) |
@@ -89,7 +93,7 @@ int tsu6721_mux(enum tsu6721_mux sel)
return EC_ERROR_INVAL;
}
- if (sel == TSU6721_MUX_NONE) {
+ if (sel == TSU6721_MUX_AUTO) {
tsu6721_write(TSU6721_REG_CONTROL, ctrl | TSU6721_CTRL_AUTO);
} else {
tsu6721_write(TSU6721_REG_MANUAL1, sel);
@@ -114,10 +118,11 @@ void tsu6721_init(void)
settings = (settings & ~0x38);
tsu6721_write(TSU6721_REG_TIMER, settings);
- tsu6721_enable_interrupts(TSU6721_INT_ATTACH |
- TSU6721_INT_DETACH |
- TSU6721_INT_ADC_CHANGE |
- TSU6721_INT_VBUS);
+ tsu6721_set_interrupt_mask(TSU6721_INT_ATTACH |
+ TSU6721_INT_DETACH |
+ TSU6721_INT_ADC_CHANGE |
+ TSU6721_INT_VBUS);
+ tsu6721_enable_interrupts();
}
/*
* TODO(vpalatin): using the I2C early in the HOOK_INIT
@@ -165,7 +170,7 @@ static int command_usbmux(int argc, char **argv)
} else if (!strcasecmp(argv[1], "uart2")) {
tsu6721_mux(TSU6721_MUX_AUDIO);
} else if (!strcasecmp(argv[1], "auto")) {
- tsu6721_mux(TSU6721_MUX_NONE);
+ tsu6721_mux(TSU6721_MUX_AUTO);
} else { /* read one register */
ccprintf("Invalid mux value: %s\n", argv[1]);
return EC_ERROR_INVAL;
@@ -191,7 +196,7 @@ static int usb_command_mux(struct host_cmd_handler_args *args)
return EC_RES_ACCESS_DENIED;
/* Safety check */
- if (p->mux != TSU6721_MUX_NONE &&
+ if (p->mux != TSU6721_MUX_AUTO &&
p->mux != TSU6721_MUX_USB &&
p->mux != TSU6721_MUX_UART &&
p->mux != TSU6721_MUX_AUDIO)
diff --git a/include/tsu6721.h b/include/tsu6721.h
index f1101acf06..66bf5b6a33 100644
--- a/include/tsu6721.h
+++ b/include/tsu6721.h
@@ -32,7 +32,7 @@
#define TSU6721_CTRL_AUTO (1 << 2)
enum tsu6721_mux {
- TSU6721_MUX_NONE = 0x00,
+ TSU6721_MUX_AUTO = 0x00,
TSU6721_MUX_USB = 0x24,
TSU6721_MUX_AUDIO = 0x48,
TSU6721_MUX_UART = 0x6C,
@@ -81,13 +81,15 @@ uint8_t tsu6721_read(uint8_t reg);
/* Write TSU6721 register. */
void tsu6721_write(uint8_t reg, uint8_t val);
-/* Enable interrupt(s). The parameter 'mask' can be one or a combination of
- * TSU6721_INT_* */
-void tsu6721_enable_interrupts(int mask);
+/* Enable interrupts. */
+void tsu6721_enable_interrupts(void);
/* Disable all interrupts. */
void tsu6721_disable_interrupts(void);
+/* Set interrupt mask. */
+void tsu6721_set_interrupt_mask(uint16_t mask);
+
/* Get and clear current interrupt status. Return value is a combination of
* TSU6721_INT_* */
int tsu6721_get_interrupts(void);
@@ -96,4 +98,7 @@ int tsu6721_get_interrupts(void);
* TSU6721_TYPE_* */
int tsu6721_get_device_type(void);
+/* Control TSU6721 mux. */
+int tsu6721_mux(enum tsu6721_mux sel);
+
#endif /* TSU6721_H */