summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVijay Hiremath <vijay.p.hiremath@intel.com>2016-05-09 18:36:53 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-06-08 19:17:56 -0700
commit4a6967951f107dfaf4ea7cc14516b5b1c0819244 (patch)
tree4dcfa0abbe51ead60b7cca0867890e6d1e69d97f
parent6e874dc7e7535189d4bd0e62ae1f98ba8d2c1650 (diff)
downloadchrome-ec-4a6967951f107dfaf4ea7cc14516b5b1c0819244.tar.gz
Driver: BD99955: Use Charger interrupt to detect VBUS activity
Added support to enable the BD99955 charger interrupt to detect the VBUS activity. With this approach GPIO USB_Cx_VBUS_DET_N pin can be removed. BUG=chrome-os-partner:53688 BRANCH=none TEST=Manually tested on Amenia. Type-C, DCP & SDP chargers can negotiate to desired current & voltage. Battery can charge. USB3.0 & USB2.0 sync devices are detected by the Kernel. Change-Id: I5470092c5cd43026aafc1a638ba446d0037c71e7 Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com> Reviewed-on: https://chromium-review.googlesource.com/343650 Commit-Ready: Vijay P Hiremath <vijay.p.hiremath@intel.com> Tested-by: Vijay P Hiremath <vijay.p.hiremath@intel.com> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--board/amenia/board.c24
-rw-r--r--board/amenia/board.h2
-rw-r--r--board/amenia/gpio.inc8
-rw-r--r--board/amenia/usb_pd_policy.c3
-rw-r--r--common/usb_charger.c12
-rw-r--r--driver/charger/bd99955.c106
-rw-r--r--driver/charger/bd99955.h14
-rw-r--r--include/usb_charge.h13
8 files changed, 144 insertions, 38 deletions
diff --git a/board/amenia/board.c b/board/amenia/board.c
index 63d53fdcc2..6895c868f3 100644
--- a/board/amenia/board.c
+++ b/board/amenia/board.c
@@ -80,26 +80,6 @@ static void tcpc_alert_event(enum gpio_signal signal)
#endif
}
-void vbus0_evt(enum gpio_signal signal)
-{
- if (!gpio_get_level(GPIO_USB_C0_RST_L))
- return;
-
- /* VBUS present GPIO is inverted */
- usb_charger_vbus_change(0, !gpio_get_level(signal));
- task_wake(TASK_ID_PD_C0);
-}
-
-void vbus1_evt(enum gpio_signal signal)
-{
- if (!gpio_get_level(GPIO_USB_C1_RST_L))
- return;
-
- /* VBUS present GPIO is inverted */
- usb_charger_vbus_change(1, !gpio_get_level(signal));
- task_wake(TASK_ID_PD_C1);
-}
-
void board_set_tcpc_power_mode(int port, int normal_mode)
{
}
@@ -216,11 +196,9 @@ void board_tcpc_init(void)
/* Enable TCPC0 interrupt */
gpio_enable_interrupt(GPIO_USB_C0_PD_INT);
- gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE_L);
/* Enable TCPC1 interrupt */
gpio_enable_interrupt(GPIO_USB_C1_PD_INT_L);
- gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE_L);
}
DECLARE_HOOK(HOOK_INIT, board_tcpc_init, HOOK_PRIO_INIT_I2C+1);
@@ -284,10 +262,8 @@ void chipset_do_shutdown(void)
/* Initialize board. */
static void board_init(void)
{
-#if 0 /* TODO: CHARGER */
/* Enable charger interrupt */
gpio_enable_interrupt(GPIO_CHARGER_INT_L);
-#endif
/* Enable tablet mode interrupt for input device enable */
gpio_enable_interrupt(GPIO_TABLET_MODE_L);
diff --git a/board/amenia/board.h b/board/amenia/board.h
index d4dfd2b705..d8e417ea7e 100644
--- a/board/amenia/board.h
+++ b/board/amenia/board.h
@@ -86,7 +86,7 @@
#define TCPC1_I2C_ADDR 0x16
#define CONFIG_USB_PD_TCPM_MUX
#define CONFIG_USB_PD_TRY_SRC
-#define CONFIG_USB_PD_VBUS_DETECT_GPIO
+#define CONFIG_USB_PD_VBUS_DETECT_CHARGER
#define CONFIG_USB_PORT_POWER_SMART
#define GPIO_USB1_CTL1 GPIO_USB_CTL1
#define GPIO_USB1_CTL2 GPIO_UNIMPLEMENTED
diff --git a/board/amenia/gpio.inc b/board/amenia/gpio.inc
index 3a32f511a2..8e0dc6c98a 100644
--- a/board/amenia/gpio.inc
+++ b/board/amenia/gpio.inc
@@ -26,14 +26,12 @@ GPIO_INT(PCH_SUSPWRDNACK, PIN(B, 1), GPIO_INT_BOTH, power_
GPIO_INT(ALL_SYS_PGOOD, PIN(6, 2), GPIO_INT_BOTH, power_signal_interrupt) /* A31 - PS2_CLK1 for ALL_SYS_PWRGD */
GPIO_INT(RSMRST_L_PGOOD, PIN(9, 3), GPIO_INT_BOTH, power_signal_interrupt) /* A46 - TA1/F_DIO2 for PMIC_RSMRST_N */
-GPIO_INT(USB_C0_VBUS_WAKE_L, PIN(A, 7), GPIO_INT_BOTH | GPIO_PULL_UP, vbus0_evt) /* B56 - PS2_DAT3/TB2/F_DIO3 for USB_C0_VBUS_DET_N */
GPIO_INT(USB_C0_PD_INT, PIN(8, 5), GPIO_INT_RISING, tcpc_alert_event) /* A43 - RXD for USB_C0_PHY_INT */
-
-GPIO_INT(USB_C1_VBUS_WAKE_L, PIN(6, 1), GPIO_INT_BOTH | GPIO_PULL_UP, vbus1_evt) /* B32 - GPIO61 for USB_C1_VBUS_DET_N */
GPIO_INT(USB_C1_PD_INT_L, PIN(9, 4), GPIO_INT_FALLING, tcpc_alert_event) /* B49 - GPIO94 for USB_C1_PHY_INT_N */
+GPIO_INT(CHARGER_INT_L, PIN(0, 2), GPIO_INT_FALLING | GPIO_PULL_UP, bd99955_vbus_interrupt) /* A01 - GPIO02 for CHRGR_INT_N */
-/* TODO: CHARGER */
-GPIO(CHARGER_INT_L, PIN(0, 2), GPIO_INT_FALLING | GPIO_PULL_UP ) /* A01 - GPIO02 for CHRGR_INT_N */
+GPIO(NC_USB_C0_VBUS_WAKE_L, PIN(A, 7), GPIO_INPUT | GPIO_PULL_UP) /* B56 - PS2_DAT3/TB2/F_DIO3 for USB_C0_VBUS_DET_N */
+GPIO(NC_USB_C1_VBUS_WAKE_L, PIN(6, 1), GPIO_INPUT | GPIO_PULL_UP) /* B32 - GPIO61 for USB_C1_VBUS_DET_N */
/* Board ID */
GPIO(BOARD_VERSION1, PIN(0, 4), GPIO_INPUT) /* A02 - KSO13 for EC_BRD_ID1 */
diff --git a/board/amenia/usb_pd_policy.c b/board/amenia/usb_pd_policy.c
index e2355d93d2..821272beb0 100644
--- a/board/amenia/usb_pd_policy.c
+++ b/board/amenia/usb_pd_policy.c
@@ -105,8 +105,7 @@ void typec_set_input_current_limit(int port, uint32_t max_ma,
int pd_snk_is_vbus_provided(int port)
{
- return !gpio_get_level(port ? GPIO_USB_C1_VBUS_WAKE_L :
- GPIO_USB_C0_VBUS_WAKE_L);
+ return bd99955_is_vbus_provided(port);
}
int pd_board_checks(void)
diff --git a/common/usb_charger.c b/common/usb_charger.c
index a6b580072b..9888dac199 100644
--- a/common/usb_charger.c
+++ b/common/usb_charger.c
@@ -62,11 +62,13 @@ void usb_charger_vbus_change(int port, int vbus_level)
pd_vbus_low(port);
/* Update VBUS supplier and signal VBUS change to USB_CHG task */
update_vbus_supplier(port, vbus_level);
-#if CONFIG_USB_PD_PORT_COUNT == 2
- task_set_event(port ? TASK_ID_USB_CHG_P1 : TASK_ID_USB_CHG_P0,
- USB_CHG_EVENT_VBUS, 0);
-#else
- task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_VBUS, 0);
+
+ /* USB Charger task */
+ task_set_event(USB_CHG_PORT_TO_TASK_ID(port), USB_CHG_EVENT_VBUS, 0);
+
+#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER
+ /* USB PD task */
+ task_wake(PD_PORT_TO_TASK_ID(port));
#endif
}
diff --git a/driver/charger/bd99955.c b/driver/charger/bd99955.c
index cd3e446fba..6f3ce6c90f 100644
--- a/driver/charger/bd99955.c
+++ b/driver/charger/bd99955.c
@@ -306,8 +306,70 @@ static void bd99955_bc12_detach(int port, int type)
/* notify host of power info change */
pd_send_host_event(PD_EVENT_POWER_CHANGE);
}
-#endif /* defined(HAS_TASK_USB_CHG_P0) || defined(HAS_TASK_USB_CHG_P1) */
+#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER
+static int bd99955_enable_vbus_detect_interrupts(int port, int enable)
+{
+ int reg;
+ int rv;
+ int port_reg;
+ int mask_val;
+
+ /* 1st Level Interrupt Setting */
+ rv = ch_raw_read16(BD99955_CMD_INT0_SET, &reg,
+ BD99955_EXTENDED_COMMAND);
+ if (rv)
+ return rv;
+
+ mask_val = ((port == BD99955_CHARGE_PORT_VBUS) ?
+ BD99955_CMD_INT0_SET_INT1_EN :
+ BD99955_CMD_INT0_SET_INT2_EN) |
+ BD99955_CMD_INT0_SET_INT0_EN;
+ if (enable)
+ reg |= mask_val;
+ else
+ reg &= ~mask_val;
+
+ rv = ch_raw_write16(BD99955_CMD_INT0_SET, reg,
+ BD99955_EXTENDED_COMMAND);
+ if (rv)
+ return rv;
+
+ /* 2nd Level Interrupt Setting */
+ port_reg = (port == BD99955_CHARGE_PORT_VBUS) ?
+ BD99955_CMD_INT1_SET : BD99955_CMD_INT2_SET;
+ rv = ch_raw_read16(port_reg, &reg, BD99955_EXTENDED_COMMAND);
+ if (rv)
+ return rv;
+
+ if (enable)
+ reg |= (BD99955_CMD_INT_SET_RES | BD99955_CMD_INT_SET_DET);
+ else
+ reg &= ~(BD99955_CMD_INT_SET_RES | BD99955_CMD_INT_SET_DET);
+
+ return ch_raw_write16(port_reg, reg, BD99955_EXTENDED_COMMAND);
+}
+
+static int bd99955_get_vbus_detect_interrupts(int port, int get)
+{
+ int rv;
+ int reg;
+ int port_reg;
+
+ port_reg = (port == BD99955_CHARGE_PORT_VBUS) ?
+ BD99955_CMD_INT1_STATUS : BD99955_CMD_INT2_STATUS;
+ if (get) {
+ rv = ch_raw_read16(port_reg, &reg, BD99955_EXTENDED_COMMAND);
+
+ return rv ? 0 : reg &
+ (BD99955_CMD_INT_SET_RES | BD99955_CMD_INT_SET_DET);
+ } else
+ return ch_raw_write16(port_reg,
+ (BD99955_CMD_INT_SET_RES | BD99955_CMD_INT_SET_DET),
+ BD99955_EXTENDED_COMMAND);
+}
+#endif /* CONFIG_USB_PD_VBUS_DETECT_CHARGER */
+#endif /* defined(HAS_TASK_USB_CHG_P0) || defined(HAS_TASK_USB_CHG_P1) */
/* chip specific interfaces */
@@ -570,6 +632,12 @@ static void bd99995_init(void)
reg &= ~BD99955_CMD_VM_CTRL_SET_EXTIADPEN;
ch_raw_write16(BD99955_CMD_VM_CTRL_SET, reg,
BD99955_EXTENDED_COMMAND);
+
+#if (defined(HAS_TASK_USB_CHG_P0) || defined(HAS_TASK_USB_CHG_P1)) && \
+ defined(CONFIG_USB_PD_VBUS_DETECT_CHARGER)
+ bd99955_enable_vbus_detect_interrupts(BD99955_CHARGE_PORT_VBUS, 1);
+ bd99955_enable_vbus_detect_interrupts(BD99955_CHARGE_PORT_VCC, 1);
+#endif
}
DECLARE_HOOK(HOOK_INIT, bd99995_init, HOOK_PRIO_INIT_EXTPOWER);
@@ -697,12 +765,48 @@ void usb_charger_set_switches(int port, enum usb_switch setting)
bd99955_enable_usb_switch(port, usb_switch_state[port]);
}
+#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER
+/* TODO: Use only one usb_charger_task for both the ports */
+void bd99955_vbus_interrupt_deferred(void)
+{
+ int port;
+ int intr;
+
+ for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; port++) {
+ /* Get the VBUS interrupt */
+ intr = bd99955_get_vbus_detect_interrupts(port, 1);
+ if (!intr)
+ continue;
+
+ if (intr & BD99955_CMD_INT_SET_RES)
+ usb_charger_vbus_change(port, 0);
+
+ if (intr & BD99955_CMD_INT_SET_DET)
+ usb_charger_vbus_change(port, 1);
+
+ /* Clear the VBUS interrupt */
+ bd99955_get_vbus_detect_interrupts(port, 0);
+ }
+}
+DECLARE_DEFERRED(bd99955_vbus_interrupt_deferred);
+
+void bd99955_vbus_interrupt(enum gpio_signal signal)
+{
+ hook_call_deferred(&bd99955_vbus_interrupt_deferred_data, 0);
+}
+#endif /* CONFIG_USB_PD_VBUS_DETECT_CHARGER */
+
void usb_charger_task(void)
{
int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1);
int bc12_type = CHARGE_SUPPLIER_NONE;
int vbus_provided;
+#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER
+ /* Clear any pending VBUS interrupts */
+ bd99955_get_vbus_detect_interrupts(port, 0);
+#endif
+
while (1) {
vbus_provided = pd_snk_is_vbus_provided(port);
diff --git a/driver/charger/bd99955.h b/driver/charger/bd99955.h
index 6b508611f5..87a1e7bc67 100644
--- a/driver/charger/bd99955.h
+++ b/driver/charger/bd99955.h
@@ -218,7 +218,15 @@ enum bd99955_charge_port {
#define BD99955_CMD_EXTIADP_AVE_VAL 0x63
#define BD99955_CMD_VACPCLPS_TH_SET 0x64
#define BD99955_CMD_INT0_SET 0x68
+#define BD99955_CMD_INT0_SET_INT2_EN (1 << 2)
+#define BD99955_CMD_INT0_SET_INT1_EN (1 << 1)
+#define BD99955_CMD_INT0_SET_INT0_EN (1 << 0)
+
#define BD99955_CMD_INT1_SET 0x69
+/* Bits for both INT1 & INT2 reg */
+#define BD99955_CMD_INT_SET_DET (1 << 1)
+#define BD99955_CMD_INT_SET_RES (1 << 0)
+
#define BD99955_CMD_INT2_SET 0x6A
#define BD99955_CMD_INT3_SET 0x6B
#define BD99955_CMD_INT4_SET 0x6C
@@ -227,6 +235,10 @@ enum bd99955_charge_port {
#define BD99955_CMD_INT7_SET 0x6F
#define BD99955_CMD_INT0_STATUS 0x70
#define BD99955_CMD_INT1_STATUS 0x71
+/* Bits for both INT1_STATUS & INT2_STATUS reg */
+#define BD99955_CMD_INT_STATUS_DET (1 << 1)
+#define BD99955_CMD_INT_STATUS_RES (1 << 0)
+
#define BD99955_CMD_INT2_STATUS 0x72
#define BD99955_CMD_INT3_STATUS 0x73
#define BD99955_CMD_INT4_STATUS 0x74
@@ -251,5 +263,7 @@ int bd99955_is_vbus_provided(int port);
int bd99955_select_input_port(enum bd99955_charge_port port);
/* Enable/Disable charging triggered by BC1.2 */
int bd99955_bc12_enable_charging(enum bd99955_charge_port port, int enable);
+/* Interrupt handler for USB charger VBUS */
+void bd99955_vbus_interrupt(enum gpio_signal signal);
#endif /* __CROS_EC_BD99955_H */
diff --git a/include/usb_charge.h b/include/usb_charge.h
index 5d21a6aab9..5de334583d 100644
--- a/include/usb_charge.h
+++ b/include/usb_charge.h
@@ -52,6 +52,19 @@ int usb_charge_ports_enabled(void);
#define USB_CHG_EVENT_VBUS TASK_EVENT_CUSTOM(2)
#define USB_CHG_EVENT_INTR TASK_EVENT_CUSTOM(4)
+/*
+ * Define USB_CHG_PORT_TO_TASK_ID() and TASK_ID_TO_USB_CHG__PORT() macros to
+ * go between USB_CHG port number and task ID. Assume that TASK_ID_USB_CHG_P0,
+ * is the lowest task ID and IDs are on a continuous range.
+ */
+#ifdef HAS_TASK_USB_CHG_P0
+#define USB_CHG_PORT_TO_TASK_ID(port) (TASK_ID_USB_CHG_P0 + (port))
+#define TASK_ID_TO_USB_CHG_PORT(id) ((id) - TASK_ID_USB_CHG_P0)
+#else
+#define USB_CHG_PORT_TO_TASK_ID(port) -1 /* dummy task ID */
+#define TASK_ID_TO_USB_CHG_PORT(id) 0
+#endif /* HAS_TASK_USB_CHG_P0 */
+
/**
* Returns true if the passed port is a power source.
*