summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVijay Hiremath <vijay.p.hiremath@intel.com>2016-04-16 01:08:55 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-05-24 15:46:01 -0700
commit313355302b2bc829e7ca16455ffa2a39b46ff4f4 (patch)
treeeb0f338c0c59156408c90402b61847665d157746
parentf4e617e11866c4ce353d42f8c83331017fbf7eb2 (diff)
downloadchrome-ec-313355302b2bc829e7ca16455ffa2a39b46ff4f4.tar.gz
Driver: BD99955: Enable BC1.2 support
BUG=none BRANCH=none TEST=Manually tested on Amenia. Connected Zinger, Type-C, DCP & CDP chargers. Device can negotiate to desired current & voltage and the battery can charge. USB2.0 sync device is detected by Kernel. Change-Id: I58cb69289eef9a966e06bef8fe31d35beaec5e27 Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com> Reviewed-on: https://chromium-review.googlesource.com/341030 Commit-Ready: Vijay P Hiremath <vijay.p.hiremath@intel.com> Tested-by: Vijay P Hiremath <vijay.p.hiremath@intel.com> Tested-by: Kevin K Wong <kevin.k.wong@intel.com> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--board/amenia/board.c66
-rw-r--r--board/amenia/board.h1
-rw-r--r--board/amenia/ec.tasklist2
-rw-r--r--board/chell/board.c4
-rw-r--r--board/elm/board.c4
-rw-r--r--board/glados/board.c4
-rw-r--r--board/kevin/board.c2
-rw-r--r--board/lucid/board.c2
-rw-r--r--board/oak/board.c4
-rw-r--r--board/reef/board.c4
-rw-r--r--board/ryu/board.c4
-rw-r--r--board/ryu/board.h2
-rw-r--r--board/samus_pd/board.c4
-rw-r--r--board/strago/board.c4
-rw-r--r--board/wheatley/board.c4
-rw-r--r--common/charge_manager.c20
-rw-r--r--common/charge_ramp.c3
-rw-r--r--driver/charger/bd99955.c274
-rw-r--r--driver/charger/bd99955.h42
-rw-r--r--include/charge_manager.h2
-rw-r--r--include/config.h1
-rw-r--r--test/charge_manager.c2
-rw-r--r--test/charge_ramp.c2
23 files changed, 372 insertions, 85 deletions
diff --git a/board/amenia/board.c b/board/amenia/board.c
index 402ae5519c..d2695d62ca 100644
--- a/board/amenia/board.c
+++ b/board/amenia/board.c
@@ -49,43 +49,6 @@
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
-#if 1 /* TODO: CHARGER / BC1.2 */
-static void update_vbus_supplier(int port, int vbus_level)
-{
- struct charge_port_info charge;
-
- charge.voltage = USB_CHARGER_VOLTAGE_MV;
- charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0;
- charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, port, &charge);
-}
-
-static void reset_charge(int port)
-{
- struct charge_port_info charge_none;
-
- charge_none.voltage = USB_CHARGER_VOLTAGE_MV;
- charge_none.current = 0;
- charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY,
- port,
- &charge_none);
- charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP,
- port,
- &charge_none);
- charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP,
- port,
- &charge_none);
- charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP,
- port,
- &charge_none);
- charge_manager_update_charge(CHARGE_SUPPLIER_OTHER,
- port,
- &charge_none);
-
- /* Initialize VBUS supplier based on whether VBUS is present */
- update_vbus_supplier(port, pd_snk_is_vbus_provided(port));
-}
-#endif
-
uint16_t tcpc_get_alert_status(void)
{
uint16_t status = 0;
@@ -123,8 +86,7 @@ void vbus0_evt(enum gpio_signal signal)
return;
/* VBUS present GPIO is inverted */
- update_vbus_supplier(0, !gpio_get_level(signal));
-
+ usb_charger_vbus_change(0, !gpio_get_level(signal));
task_wake(TASK_ID_PD_C0);
}
@@ -134,8 +96,7 @@ void vbus1_evt(enum gpio_signal signal)
return;
/* VBUS present GPIO is inverted */
- update_vbus_supplier(1, !gpio_get_level(signal));
-
+ usb_charger_vbus_change(1, !gpio_get_level(signal));
task_wake(TASK_ID_PD_C1);
}
@@ -309,14 +270,6 @@ const struct button_config buttons[CONFIG_BUTTON_COUNT] = {
/* Initialize board. */
static void board_init(void)
{
-#if 1 /* TODO: CHARGER / BC1.2 */
- int i;
-
- /* Initialize all BC1.2 charge suppliers to 0 */
- for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++)
- reset_charge(i);
-#endif
-
#if 0 /* TODO: CHARGER */
/* Enable charger interrupt */
gpio_enable_interrupt(GPIO_CHARGER_INT_L);
@@ -343,8 +296,7 @@ int board_set_active_charge_port(int charge_port)
int is_real_port = (charge_port >= 0 &&
charge_port < CONFIG_USB_PD_PORT_COUNT);
/* check if we are source vbus on that port */
- int source = gpio_get_level(charge_port == 0 ? GPIO_USB_C0_5V_EN :
- GPIO_USB_C1_5V_EN);
+ int source = usb_charger_port_is_sourcing_vbus(charge_port);
if (is_real_port && source) {
CPRINTS("Skip enable p%d", charge_port);
@@ -374,10 +326,20 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
+ /* Enable charging trigger by BC1.2 detection */
+ if (supplier == CHARGE_SUPPLIER_BC12_CDP ||
+ supplier == CHARGE_SUPPLIER_BC12_DCP ||
+ supplier == CHARGE_SUPPLIER_BC12_SDP) {
+ if (bd99955_bc12_enable_charging(port, 1))
+ return;
+ }
+
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
}
diff --git a/board/amenia/board.h b/board/amenia/board.h
index 368e7b0b2e..b6117d23cd 100644
--- a/board/amenia/board.h
+++ b/board/amenia/board.h
@@ -42,6 +42,7 @@
#define CONFIG_CHARGER_NARROW_VDC
#define CONFIG_CHARGER_SENSE_RESISTOR 10
#define CONFIG_CHARGER_SENSE_RESISTOR_AC 20
+#define CONFIG_USB_CHARGER
#define CONFIG_CHIPSET_APOLLOLAKE
#define CONFIG_CMD_ACCELS
diff --git a/board/amenia/ec.tasklist b/board/amenia/ec.tasklist
index f47a845f66..8418f4d0f6 100644
--- a/board/amenia/ec.tasklist
+++ b/board/amenia/ec.tasklist
@@ -19,6 +19,8 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(ALS, als_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P0, usb_charger_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P1, usb_charger_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CHARGER, charger_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_NOTEST(MOTIONSENSE, motion_sense_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \
diff --git a/board/chell/board.c b/board/chell/board.c
index b1dd93881d..6404844c3b 100644
--- a/board/chell/board.c
+++ b/board/chell/board.c
@@ -352,9 +352,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/board/elm/board.c b/board/elm/board.c
index 809680931d..3a51b0ba68 100644
--- a/board/elm/board.c
+++ b/board/elm/board.c
@@ -289,9 +289,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/board/glados/board.c b/board/glados/board.c
index 8855ae9518..29d05f1dea 100644
--- a/board/glados/board.c
+++ b/board/glados/board.c
@@ -323,9 +323,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/board/kevin/board.c b/board/kevin/board.c
index 1e4cb24a77..f3f99d38b9 100644
--- a/board/kevin/board.c
+++ b/board/kevin/board.c
@@ -196,7 +196,7 @@ int board_set_active_charge_port(int charge_port)
return bd99955_select_input_port(bd99955_port);
}
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/board/lucid/board.c b/board/lucid/board.c
index f5f03e2895..86a423b653 100644
--- a/board/lucid/board.c
+++ b/board/lucid/board.c
@@ -165,7 +165,7 @@ int board_set_active_charge_port(int charge_port)
return EC_SUCCESS;
}
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
int rv;
diff --git a/board/oak/board.c b/board/oak/board.c
index f66c35acee..66ac54d314 100644
--- a/board/oak/board.c
+++ b/board/oak/board.c
@@ -318,9 +318,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/board/reef/board.c b/board/reef/board.c
index 3a6ca25559..81c7054b7a 100644
--- a/board/reef/board.c
+++ b/board/reef/board.c
@@ -363,9 +363,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/board/ryu/board.c b/board/ryu/board.c
index aa59a6778a..0c570a4d2d 100644
--- a/board/ryu/board.c
+++ b/board/ryu/board.c
@@ -546,9 +546,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
int rv;
diff --git a/board/ryu/board.h b/board/ryu/board.h
index 3c5be953ba..a0a20f6479 100644
--- a/board/ryu/board.h
+++ b/board/ryu/board.h
@@ -276,7 +276,7 @@ enum usb_strings {
#define PD_PREFER_LOW_VOLTAGE
/* Set the charge current limit. */
-void board_set_charge_limit(int charge_ma);
+void board_set_charge_limit(int port, int supplier, int charge_ma);
/* PP1800 transition GPIO interrupt handler */
void pp1800_on_off_evt(enum gpio_signal signal);
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c
index 80e99dd9da..de4a46729a 100644
--- a/board/samus_pd/board.c
+++ b/board/samus_pd/board.c
@@ -495,9 +495,11 @@ static int board_update_charge_limit(int charge_ma)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
/* Update current limit and notify EC if it changed */
if (board_update_charge_limit(charge_ma))
diff --git a/board/strago/board.c b/board/strago/board.c
index 32ca7aa4a8..5c123e7ef4 100644
--- a/board/strago/board.c
+++ b/board/strago/board.c
@@ -346,9 +346,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/board/wheatley/board.c b/board/wheatley/board.c
index f8754eae0c..408e833697 100644
--- a/board/wheatley/board.c
+++ b/board/wheatley/board.c
@@ -305,9 +305,11 @@ int board_set_active_charge_port(int charge_port)
/**
* Set the charge limit based upon desired maximum.
*
+ * @param port Port number.
+ * @param supplier Charge supplier type.
* @param charge_ma Desired charge limit (mA).
*/
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
diff --git a/common/charge_manager.c b/common/charge_manager.c
index 02bcbee5e3..d57037aae8 100644
--- a/common/charge_manager.c
+++ b/common/charge_manager.c
@@ -527,8 +527,9 @@ static void charge_manager_refresh(void)
/* Enable or disable charge ramp */
charger_set_hw_ramp(board_is_ramp_allowed(new_supplier));
#endif
- board_set_charge_limit(new_charge_current);
-#endif
+ board_set_charge_limit(new_port, new_supplier,
+ new_charge_current);
+#endif /* HAS_TASK_CHG_RAMP */
CPRINTS("CL: p%d s%d i%d v%d", new_port, new_supplier,
new_charge_current, new_charge_voltage);
}
@@ -996,3 +997,18 @@ DECLARE_CONSOLE_COMMAND(chglim, command_external_power_limit,
"Set max charger current / voltage",
NULL);
#endif /* CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT */
+
+#ifdef CONFIG_CMD_CHARGE_SUPPLIER_INFO
+static int charge_supplier_info(int argc, char **argv)
+{
+ ccprintf("port=%d, type=%d, cur=%dmA, vtg=%dmV\n",
+ charge_manager_get_active_charge_port(),
+ charge_supplier,
+ charge_current,
+ charge_voltage);
+
+ return 0;
+}
+DECLARE_CONSOLE_COMMAND(chgsup, charge_supplier_info,
+ NULL, "print chg supplier info", NULL);
+#endif
diff --git a/common/charge_ramp.c b/common/charge_ramp.c
index e5f6d99e26..775093f837 100644
--- a/common/charge_ramp.c
+++ b/common/charge_ramp.c
@@ -319,7 +319,8 @@ void chg_ramp_task(void)
active_icl = active_icl_new;
/* Set the input current limit */
- board_set_charge_limit(chg_ramp_get_current_limit());
+ board_set_charge_limit(active_port, active_sup,
+ chg_ramp_get_current_limit());
if (ramp_st == CHG_RAMP_STABILIZE)
/*
diff --git a/driver/charger/bd99955.c b/driver/charger/bd99955.c
index 713a90be1c..c07cf70493 100644
--- a/driver/charger/bd99955.c
+++ b/driver/charger/bd99955.c
@@ -8,16 +8,28 @@
#include "battery.h"
#include "battery_smart.h"
#include "bd99955.h"
+#include "charge_manager.h"
#include "charger.h"
#include "console.h"
+#include "ec_commands.h"
#include "hooks.h"
#include "i2c.h"
#include "task.h"
+#include "time.h"
#include "util.h"
+#include "usb_charge.h"
+#include "usb_pd.h"
+
+#define OTPROM_LOAD_WAIT_RETRY 3
+
+#define BD99955_CHARGE_PORT_COUNT 2
/* Console output macros */
#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
+/* TODO: Add accurate timeout for detecting BC1.2 */
+#define BC12_DETECT_RETRY 10
+
/* Charger parameters */
static const struct charger_info bd99955_charger_info = {
.name = CHARGER_NAME,
@@ -37,6 +49,14 @@ static enum bd99955_command charger_map_cmd = BD99955_INVALID_COMMAND;
static struct mutex bd99955_map_mutex;
+#if defined(HAS_TASK_USB_CHG_P0) || defined(HAS_TASK_USB_CHG_P1)
+/* USB switch */
+static enum usb_switch usb_switch_state[BD99955_CHARGE_PORT_COUNT] = {
+ USB_SWITCH_DISCONNECT,
+ USB_SWITCH_DISCONNECT,
+};
+#endif
+
static inline int ch_raw_read16(int cmd, int *param,
enum bd99955_command map_cmd)
{
@@ -108,9 +128,34 @@ static int bd99955_charger_enable(int enable)
static int bd99955_por_reset(void)
{
- return ch_raw_write16(BD99955_CMD_SYSTEM_CTRL_SET,
- BD99955_CMD_SYSTEM_CTRL_SET_OTPLD |
- BD99955_CMD_SYSTEM_CTRL_SET_ALLRST,
+ int rv;
+ int reg;
+ int i;
+
+ rv = ch_raw_write16(BD99955_CMD_SYSTEM_CTRL_SET,
+ BD99955_CMD_SYSTEM_CTRL_SET_OTPLD |
+ BD99955_CMD_SYSTEM_CTRL_SET_ALLRST,
+ BD99955_EXTENDED_COMMAND);
+ if (rv)
+ return rv;
+
+ /* Wait until OTPROM loading is finished */
+ for (i = 0; i < OTPROM_LOAD_WAIT_RETRY; i++) {
+ msleep(10);
+ rv = ch_raw_read16(BD99955_CMD_SYSTEM_STATUS, &reg,
+ BD99955_EXTENDED_COMMAND);
+
+ if (!rv && (reg & BD99955_CMD_SYSTEM_STATUS_OTPLD_STATE) &&
+ (reg & BD99955_CMD_SYSTEM_STATUS_ALLRST_STATE))
+ break;
+ }
+
+ if (rv)
+ return rv;
+ if (i == OTPROM_LOAD_WAIT_RETRY)
+ return EC_ERROR_TIMEOUT;
+
+ return ch_raw_write16(BD99955_CMD_SYSTEM_CTRL_SET, 0,
BD99955_EXTENDED_COMMAND);
}
@@ -131,6 +176,125 @@ static int bd99955_get_charger_op_status(int *status)
BD99955_EXTENDED_COMMAND);
}
+#if defined(HAS_TASK_USB_CHG_P0) || defined(HAS_TASK_USB_CHG_P1)
+static int bd99955_get_bc12_device_type(enum bd99955_charge_port port)
+{
+ int rv;
+ int reg;
+
+ rv = ch_raw_read16((port == BD99955_CHARGE_PORT_VBUS) ?
+ BD99955_CMD_VBUS_UCD_STATUS :
+ BD99955_CMD_VCC_UCD_STATUS,
+ &reg, BD99955_EXTENDED_COMMAND);
+ if (rv)
+ return CHARGE_SUPPLIER_NONE;
+
+ switch (reg & BD99955_TYPE_MASK) {
+ case BD99955_TYPE_CDP:
+ return CHARGE_SUPPLIER_BC12_CDP;
+ case BD99955_TYPE_DCP:
+ return CHARGE_SUPPLIER_BC12_DCP;
+ case BD99955_TYPE_SDP:
+ return CHARGE_SUPPLIER_BC12_SDP;
+ case BD99955_TYPE_VBUS_OPEN:
+ case BD99955_TYPE_PUP_PORT:
+ case BD99955_TYPE_OPEN_PORT:
+ default:
+ return CHARGE_SUPPLIER_NONE;
+ }
+}
+
+static int bd99955_get_bc12_ilim(int charge_supplier)
+{
+ switch (charge_supplier) {
+ case CHARGE_SUPPLIER_BC12_CDP:
+ return 1500;
+ case CHARGE_SUPPLIER_BC12_DCP:
+ return 2000;
+ case CHARGE_SUPPLIER_BC12_SDP:
+ return 900;
+ default:
+ return 500;
+ }
+}
+
+static int bd99955_enable_usb_switch(enum bd99955_charge_port port,
+ enum usb_switch setting)
+{
+ int rv;
+ int reg;
+ int port_reg;
+
+ port_reg = (port == BD99955_CHARGE_PORT_VBUS) ?
+ BD99955_CMD_VBUS_UCD_SET : BD99955_CMD_VCC_UCD_SET;
+
+ rv = ch_raw_read16(port_reg, &reg, BD99955_EXTENDED_COMMAND);
+ if (rv)
+ return rv;
+
+ if (setting == USB_SWITCH_CONNECT)
+ reg |= BD99955_CMD_UCD_SET_USB_SW_EN;
+ else
+ reg &= ~BD99955_CMD_UCD_SET_USB_SW_EN;
+
+ return ch_raw_write16(port_reg, reg, BD99955_EXTENDED_COMMAND);
+}
+
+static int bd99955_bc12_detect(int port)
+{
+ int i;
+ int bc12_type;
+ struct charge_port_info charge;
+
+ /*
+ * BC1.2 detection starts 100ms after VBUS/VCC attach and typically
+ * completes 312ms after VBUS/VCC attach.
+ */
+ msleep(312);
+ for (i = 0; i < BC12_DETECT_RETRY; i++) {
+ /* get device type */
+ bc12_type = bd99955_get_bc12_device_type(port);
+
+ /* Detected BC1.2 */
+ if (bc12_type != CHARGE_SUPPLIER_NONE)
+ break;
+
+ /* TODO: Add accurate timeout for detecting BC1.2 */
+ msleep(100);
+ }
+
+ /* BC1.2 device attached */
+ if (bc12_type != CHARGE_SUPPLIER_NONE) {
+ /* Update charge manager */
+ charge.voltage = USB_CHARGER_VOLTAGE_MV;
+ charge.current = bd99955_get_bc12_ilim(bc12_type);
+ charge_manager_update_charge(bc12_type, port, &charge);
+
+ /* notify host of power info change */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+ }
+
+ return bc12_type;
+}
+
+static void bd99955_bc12_detach(int port, int type)
+{
+ struct charge_port_info charge = {
+ .voltage = USB_CHARGER_VOLTAGE_MV,
+ .current = 0,
+ };
+
+ /* Update charge manager */
+ charge_manager_update_charge(type, port, &charge);
+
+ /* Disable charging trigger by BC1.2 detection */
+ bd99955_bc12_enable_charging(port, 0);
+
+ /* 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) */
+
/* chip specific interfaces */
@@ -140,7 +304,6 @@ int charger_set_input_current(int input_current)
/* Input current step 32 mA */
input_current &= ~0x1F;
-
rv = ch_raw_write16(BD99955_CMD_IBUS_LIM_SET, input_current,
BD99955_BAT_CHG_COMMAND);
if (rv)
@@ -247,9 +410,7 @@ int charger_get_status(int *status)
*status |= CHARGER_POWER_FAIL;
/* Safety signal ranges & battery presence */
- ch_status = (reg & BD99955_CMD_CHGOP_STATUS_BATTEMP0) |
- ((reg & BD99955_CMD_CHGOP_STATUS_BATTEMP1) << 1) |
- ((reg & BD99955_CMD_CHGOP_STATUS_BATTEMP2) << 2);
+ ch_status = (reg & BD99955_BATTTEMP_MASK) >> 8;
*status |= CHARGER_BATTERY_PRESENT;
@@ -346,31 +507,44 @@ static void bd99995_init(void)
int reg;
const struct battery_info *bi = battery_get_info();
- /* Disable BC1.2 detection on VCC */
+ /* Enable BC1.2 detection on VCC */
if (ch_raw_read16(BD99955_CMD_VCC_UCD_SET, &reg,
BD99955_EXTENDED_COMMAND))
return;
- reg &= ~BD99955_CMD_UCD_SET_USBDETEN;
+ reg |= BD99955_CMD_UCD_SET_USBDETEN;
+ reg &= ~BD99955_CMD_UCD_SET_USB_SW_EN;
ch_raw_write16(BD99955_CMD_VCC_UCD_SET, reg,
BD99955_EXTENDED_COMMAND);
- /* Disable BC1.2 detection on VBUS */
+ /* Enable BC1.2 detection on VBUS */
if (ch_raw_read16(BD99955_CMD_VBUS_UCD_SET, &reg,
BD99955_EXTENDED_COMMAND))
return;
- reg &= ~BD99955_CMD_UCD_SET_USBDETEN;
+ reg |= BD99955_CMD_UCD_SET_USBDETEN;
+ reg &= ~BD99955_CMD_UCD_SET_USB_SW_EN;
ch_raw_write16(BD99955_CMD_VBUS_UCD_SET, reg,
BD99955_EXTENDED_COMMAND);
- /* Disable BC1.2 charge enable trigger */
+ /* Disable charging trigger by BC1.2 on VCC & VBUS. */
if (ch_raw_read16(BD99955_CMD_CHGOP_SET1, &reg,
BD99955_EXTENDED_COMMAND))
return;
- reg |= (BD99955_CMD_CHGOP_SET1_VCC_BC_DISEN |
- BD99955_CMD_CHGOP_SET1_VBUS_BC_DISEN);
+ reg |= (BD99955_CMD_CHGOP_SET1_SDP_CHG_TRIG_EN |
+ BD99955_CMD_CHGOP_SET1_SDP_CHG_TRIG |
+ BD99955_CMD_CHGOP_SET1_VBUS_BC_DISEN |
+ BD99955_CMD_CHGOP_SET1_VCC_BC_DISEN |
+ BD99955_CMD_CHGOP_SET1_ILIM_AUTO_DISEN);
ch_raw_write16(BD99955_CMD_CHGOP_SET1, reg,
BD99955_EXTENDED_COMMAND);
+ /* Enable BC1.2 USB charging and DC/DC converter */
+ if (ch_raw_read16(BD99955_CMD_CHGOP_SET2, &reg,
+ BD99955_EXTENDED_COMMAND))
+ return;
+ reg &= ~(BD99955_CMD_CHGOP_SET2_USB_SUS);
+ ch_raw_write16(BD99955_CMD_CHGOP_SET2, reg,
+ BD99955_EXTENDED_COMMAND);
+
/* Set battery OVP to 500 + maximum battery voltage */
ch_raw_write16(BD99955_CMD_VBATOVP_SET,
(bi->voltage_max + 500) & 0x7ff0,
@@ -449,6 +623,78 @@ int bd99955_select_input_port(enum bd99955_charge_port port)
BD99955_EXTENDED_COMMAND);
}
+#if defined(HAS_TASK_USB_CHG_P0) || defined(HAS_TASK_USB_CHG_P1)
+int bd99955_bc12_enable_charging(enum bd99955_charge_port port, int enable)
+{
+ int rv;
+ int reg;
+ int mask_val;
+
+ /*
+ * For BC1.2, enable VBUS/VCC_BC_DISEN charging trigger by BC1.2
+ * detection and disable SDP_CHG_TRIG, SDP_CHG_TRIG_EN. Vice versa
+ * for USB-C.
+ */
+ rv = ch_raw_read16(BD99955_CMD_CHGOP_SET1, &reg,
+ BD99955_EXTENDED_COMMAND);
+ if (rv)
+ return rv;
+
+ mask_val = (BD99955_CMD_CHGOP_SET1_SDP_CHG_TRIG_EN |
+ BD99955_CMD_CHGOP_SET1_SDP_CHG_TRIG |
+ ((port == BD99955_CHARGE_PORT_VBUS) ?
+ BD99955_CMD_CHGOP_SET1_VBUS_BC_DISEN :
+ BD99955_CMD_CHGOP_SET1_VCC_BC_DISEN));
+
+ if (enable)
+ reg &= ~mask_val;
+ else
+ reg |= mask_val;
+
+ return ch_raw_write16(BD99955_CMD_CHGOP_SET1, reg,
+ BD99955_EXTENDED_COMMAND);
+}
+
+void usb_charger_set_switches(int port, enum usb_switch setting)
+{
+ /* If switch is not changing then return */
+ if (setting == usb_switch_state[port] ||
+ pd_snk_is_vbus_provided(port))
+ return;
+
+ if (setting != USB_SWITCH_RESTORE)
+ usb_switch_state[port] = setting;
+ bd99955_enable_usb_switch(port, usb_switch_state[port]);
+}
+
+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;
+
+ while (1) {
+ vbus_provided = pd_snk_is_vbus_provided(port);
+
+ if (vbus_provided) {
+ /* Charger/sync attached */
+ bc12_type = bd99955_bc12_detect(port);
+ } else if (bc12_type != CHARGE_SUPPLIER_NONE &&
+ !vbus_provided) {
+ /* Charger/sync detached */
+ bd99955_bc12_detach(port, bc12_type);
+ bc12_type = CHARGE_SUPPLIER_NONE;
+ }
+
+ /* Wait for interrupt */
+ task_wait_event(-1);
+ }
+}
+#endif /* defined(HAS_TASK_USB_CHG_P0) || defined(HAS_TASK_USB_CHG_P1) */
+
+
+/*** Console commands ***/
+
#ifdef CONFIG_CMD_CHARGER
static int read_bat(uint8_t cmd)
{
diff --git a/driver/charger/bd99955.h b/driver/charger/bd99955.h
index 0f3e4aa48d..69884dce13 100644
--- a/driver/charger/bd99955.h
+++ b/driver/charger/bd99955.h
@@ -58,6 +58,7 @@ enum bd99955_charge_port {
#define BD99955_CMD_CHGOP_STATUS_BATTEMP2 (1 << 10)
#define BD99955_CMD_CHGOP_STATUS_BATTEMP1 (1 << 9)
#define BD99955_CMD_CHGOP_STATUS_BATTEMP0 (1 << 8)
+#define BD99955_BATTTEMP_MASK 0x700
#define BD99955_CMD_CHGOP_STATUS_BATTEMP_ROOMTEMP 0
#define BD99955_CMD_CHGOP_STATUS_BATTEMP_HOT1 1
#define BD99955_CMD_CHGOP_STATUS_BATTEMP_HOT2 2
@@ -81,11 +82,16 @@ enum bd99955_charge_port {
#define BD99955_CMD_VIN_CTRL_SET_VCC_EN (1 << 5)
#define BD99955_CMD_CHGOP_SET1 0x0B
+#define BD99955_CMD_CHGOP_SET1_ILIM_AUTO_DISEN (1 << 13)
#define BD99955_CMD_CHGOP_SET1_VCC_BC_DISEN (1 << 11)
#define BD99955_CMD_CHGOP_SET1_VBUS_BC_DISEN (1 << 10)
+#define BD99955_CMD_CHGOP_SET1_SDP_CHG_TRIG_EN (1 << 9)
+#define BD99955_CMD_CHGOP_SET1_SDP_CHG_TRIG (1 << 8)
+
#define BD99955_CMD_CHGOP_SET2 0x0C
#define BD99955_CMD_CHGOP_SET2_BATT_LEARN (1 << 8)
#define BD99955_CMD_CHGOP_SET2_CHG_EN (1 << 7)
+#define BD99955_CMD_CHGOP_SET2_USB_SUS (1 << 6)
#define BD99955_CMD_VBUSCLPS_TH_SET 0x0D
#define BD99955_CMD_VCCCLPS_TH_SET 0x0E
@@ -121,10 +127,39 @@ enum bd99955_charge_port {
#define BD99955_CMD_PMON_DACIN_VAL 0x26
#define BD99955_CMD_IOUT_DACIN_VAL 0x27
#define BD99955_CMD_VCC_UCD_SET 0x28
-/* Bits for both VCC_UDC_SET and VBUS_UCD_SET regs */
+/* Bits for both VCC_UCD_SET and VBUS_UCD_SET regs */
#define BD99955_CMD_UCD_SET_BCSRETRY (1 << 12)
#define BD99955_CMD_UCD_SET_USBDETEN (1 << 7)
+#define BD99955_CMD_UCD_SET_USB_SW_EN (1 << 1)
+
#define BD99955_CMD_VCC_UCD_STATUS 0x29
+/* Bits for both VCC_UCD_STATUS and VBUS_UCD_STATUS regs */
+#define BD99955_CMD_UCD_STATUS_DCDFAIL (1 << 15)
+#define BD99955_CMD_UCD_STATUS_CHGPORT1 (1 << 13)
+#define BD99955_CMD_UCD_STATUS_CHGPORT0 (1 << 12)
+#define BD99955_CMD_UCD_STATUS_PUPDET (1 << 11)
+#define BD99955_CMD_UCD_STATUS_CHGDET (1 << 6)
+#define BD99955_TYPE_VBUS_OPEN 0
+#define BD99955_TYPE_SDP BD99955_CMD_UCD_STATUS_CHGPORT0
+/*
+ * TODO: For CDP detection, from the datasheet CHGDET & CHGPORT[1] bits need
+ * to be high and rest need to be low. However following bits are high CHGDET,
+ * DCDFAIL, CHGPORT[1], CHGPORT[0] and rest low.
+ */
+#define BD99955_TYPE_CDP (BD99955_CMD_UCD_STATUS_CHGDET | \
+ BD99955_CMD_UCD_STATUS_CHGPORT1 | \
+ BD99955_CMD_UCD_STATUS_CHGPORT0 | \
+ BD99955_CMD_UCD_STATUS_DCDFAIL)
+#define BD99955_TYPE_DCP (BD99955_CMD_UCD_STATUS_CHGDET | \
+ BD99955_CMD_UCD_STATUS_CHGPORT0 | \
+ BD99955_CMD_UCD_STATUS_CHGPORT1)
+#define BD99955_TYPE_PUP_PORT (BD99955_CMD_UCD_STATUS_PUPDET | \
+ BD99955_CMD_UCD_STATUS_DCDFAIL | \
+ BD99955_CMD_UCD_STATUS_CHGPORT0)
+#define BD99955_TYPE_OPEN_PORT (BD99955_CMD_UCD_STATUS_DCDFAIL | \
+ BD99955_CMD_UCD_STATUS_CHGPORT0)
+#define BD99955_TYPE_MASK 0xB840
+
#define BD99955_CMD_VCC_IDD_STATUS 0x2A
#define BD99955_CMD_VCC_UCD_FCTRL_SET 0x2B
#define BD99955_CMD_VCC_UCD_FCTRL_EN 0x2C
@@ -138,6 +173,9 @@ enum bd99955_charge_port {
#define BD99955_CMD_IC_SET1 0x3A
#define BD99955_CMD_IC_SET2 0x3B
#define BD99955_CMD_SYSTEM_STATUS 0x3C
+#define BD99955_CMD_SYSTEM_STATUS_OTPLD_STATE (1 << 1)
+#define BD99955_CMD_SYSTEM_STATUS_ALLRST_STATE (1 << 0)
+
#define BD99955_CMD_SYSTEM_CTRL_SET 0x3D
#define BD99955_CMD_SYSTEM_CTRL_SET_OTPLD (1 << 1)
#define BD99955_CMD_SYSTEM_CTRL_SET_ALLRST (1 << 0)
@@ -213,5 +251,7 @@ enum bd99955_charge_port {
int bd99955_extpower_is_present(void);
/* Select input port from {VCC, VBUS, VCC&VBUS, NONE}. */
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);
#endif /* __CROS_EC_BD99955_H */
diff --git a/include/charge_manager.h b/include/charge_manager.h
index ec0e35a7b1..28546e22a1 100644
--- a/include/charge_manager.h
+++ b/include/charge_manager.h
@@ -100,6 +100,6 @@ void charge_manager_save_log(int port);
int board_set_active_charge_port(int charge_port);
/* Set the charge current limit. */
-void board_set_charge_limit(int charge_ma);
+void board_set_charge_limit(int port, int supplier, int charge_ma);
#endif /* __CROS_EC_CHARGE_MANAGER_H */
diff --git a/include/config.h b/include/config.h
index c55a234769..effc6d9cc7 100644
--- a/include/config.h
+++ b/include/config.h
@@ -524,6 +524,7 @@
#undef CONFIG_CMD_BATDEBUG
#define CONFIG_CMD_BATTFAKE
#define CONFIG_CMD_CHARGER
+#define CONFIG_CMD_CHARGE_SUPPLIER_INFO
#undef CONFIG_CMD_CHGRAMP
#undef CONFIG_CMD_CLOCKGATES
#undef CONFIG_CMD_COMXTEST
diff --git a/test/charge_manager.c b/test/charge_manager.c
index b60e19e0dc..962fc98a64 100644
--- a/test/charge_manager.c
+++ b/test/charge_manager.c
@@ -37,7 +37,7 @@ static int new_power_request[CONFIG_USB_PD_PORT_COUNT];
static int power_role[CONFIG_USB_PD_PORT_COUNT];
/* Callback functions called by CM on state change */
-void board_set_charge_limit(int charge_ma)
+void board_set_charge_limit(int port, int supplier, int charge_ma)
{
active_charge_limit = charge_ma;
}
diff --git a/test/charge_ramp.c b/test/charge_ramp.c
index 12973f46ff..a3279663e2 100644
--- a/test/charge_ramp.c
+++ b/test/charge_ramp.c
@@ -53,7 +53,7 @@ int board_is_vbus_too_low(enum chg_ramp_vbus_state ramp_state)
vbus_low_current_ma;
}
-void board_set_charge_limit(int limit_ma)
+void board_set_charge_limit(int port, int supplier, int limit_ma)
{
charge_limit_ma = limit_ma;
if (charge_limit_ma > overcurrent_current_ma)