diff options
author | Aseda Aboagye <aaboagye@google.com> | 2017-11-29 23:26:36 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-12-06 01:08:24 -0800 |
commit | fb32b6d30cf55408f4bdb36b729c99452f6e8e11 (patch) | |
tree | 8506ce54893a0cf9953ea7bcaaf29d96eb1b0df9 | |
parent | fb43b2f4869182e9337c031a4d516ce820fe78d1 (diff) | |
download | chrome-ec-fb32b6d30cf55408f4bdb36b729c99452f6e8e11.tar.gz |
ppc: Create generic PPC driver framework.
This commit introduces a driver framework for power path controllers.
It provides some common PPC APIs as well as allowing a board to use
multiple different PPCs drivers/parts. This should make it easier to
add PPC drivers in the future.
BUG=None
BRANCH=None
TEST=`make -j buildall`
TEST=Flash zoombini; verify PPC works as expected.
TEST=Flash meowth; verify PPC works as expected.
Change-Id: Icfb99f384610590b431456cfd28d4aff18442cb2
Signed-off-by: Aseda Aboagye <aaboagye@google.com>
Reviewed-on: https://chromium-review.googlesource.com/807630
Commit-Ready: Aseda Aboagye <aaboagye@chromium.org>
Tested-by: Aseda Aboagye <aaboagye@chromium.org>
Reviewed-by: Edward Hill <ecgh@chromium.org>
Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r-- | board/zoombini/board.c | 37 | ||||
-rw-r--r-- | board/zoombini/usb_pd_policy.c | 10 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/usbc_ppc.c | 76 | ||||
-rw-r--r-- | driver/ppc/sn5s330.c | 115 | ||||
-rw-r--r-- | driver/ppc/sn5s330.h | 22 | ||||
-rw-r--r-- | include/usbc_ppc.h | 70 |
7 files changed, 211 insertions, 120 deletions
diff --git a/board/zoombini/board.c b/board/zoombini/board.c index d728df4ae3..27a361eae3 100644 --- a/board/zoombini/board.c +++ b/board/zoombini/board.c @@ -35,6 +35,7 @@ #include "tcpci.h" #include "usb_mux.h" #include "usb_pd_tcpm.h" +#include "usbc_ppc.h" #include "util.h" #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) @@ -135,10 +136,14 @@ const struct i2c_port_t i2c_ports[] = { const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); /* TODO(aaboagye): Add the other ports. 3 for Zoombini, 2 for Meowth */ -const struct sn5s330_config sn5s330_chips[] = { - {I2C_PORT_TCPC0, SN5S330_ADDR0}, +const struct ppc_config_t ppc_chips[] = { + { + .i2c_port = I2C_PORT_TCPC0, + .i2c_addr = SN5S330_ADDR0, + .drv = &sn5s330_drv + }, }; -const unsigned int sn5s330_cnt = ARRAY_SIZE(sn5s330_chips); +const unsigned int ppc_cnt = ARRAY_SIZE(ppc_chips); #ifdef BOARD_ZOOMBINI /* GPIO to enable/disable the USB Type-A port. */ @@ -306,7 +311,6 @@ int board_set_active_charge_port(int port) port < CONFIG_USB_PD_PORT_COUNT); int i; int rv; - int is_enabled; if (!is_real_port && port != CHARGE_PORT_NONE) return EC_ERROR_INVAL; @@ -315,10 +319,10 @@ int board_set_active_charge_port(int port) if (port == CHARGE_PORT_NONE) { /* Disable all ports. */ - for (i = 0; i < sn5s330_cnt; i++) { - rv = sn5s330_pp_fet_enable(i, SN5S330_PP2, 0); + for (i = 0; i < ppc_cnt; i++) { + rv = ppc_vbus_sink_enable(i, 0); if (rv) { - CPRINTS("Disabling C%d PP2 FET failed.", i); + CPRINTS("Disabling p%d sink path failed.", i); return rv; } } @@ -327,29 +331,26 @@ int board_set_active_charge_port(int port) } /* Check if the port is sourcing VBUS. */ - if (sn5s330_is_pp_fet_enabled(port, SN5S330_PP1, &is_enabled)) - return EC_ERROR_UNKNOWN; - - if (is_enabled) { + if (ppc_is_sourcing_vbus(port)) { CPRINTF("Skip enable p%d", port); return EC_ERROR_INVAL; } /* - * Turn off the other ports' PP2 FET, before enabling the requested - * charge port. + * Turn off the other ports' sink path FETs, before enabling the + * requested charge port. */ - for (i = 0; i < sn5s330_cnt; i++) { + for (i = 0; i < ppc_cnt; i++) { if (i == port) continue; - if (sn5s330_pp_fet_enable(i, SN5S330_PP2, 0)) - CPRINTS("C%d: PP2 disable failed.", i); + if (ppc_vbus_sink_enable(i, 0)) + CPRINTS("p%d: sink path disable failed.", i); } /* Enable requested charge port. */ - if (sn5s330_pp_fet_enable(port, SN5S330_PP2, 1)) { - CPRINTS("C%d: PP2 enable failed."); + if (ppc_vbus_sink_enable(port, 1)) { + CPRINTS("p%d: sink path enable failed."); return EC_ERROR_UNKNOWN; } diff --git a/board/zoombini/usb_pd_policy.c b/board/zoombini/usb_pd_policy.c index 7623afb5f7..02e29a0736 100644 --- a/board/zoombini/usb_pd_policy.c +++ b/board/zoombini/usb_pd_policy.c @@ -7,12 +7,12 @@ #include "common.h" #include "console.h" #include "compile_time_macros.h" -#include "driver/ppc/sn5s330.h" #include "ec_commands.h" #include "gpio.h" #include "system.h" #include "usb_mux.h" #include "usb_pd.h" +#include "usbc_ppc.h" #include "util.h" #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) @@ -106,7 +106,7 @@ int pd_is_valid_input_voltage(int mv) void pd_power_supply_reset(int port) { /* Disable VBUS. */ - sn5s330_pp_fet_enable(port, SN5S330_PP1, 0); + ppc_vbus_source_enable(port, 0); /* Notify host of power info change. */ pd_send_host_event(PD_EVENT_POWER_CHANGE); @@ -116,16 +116,16 @@ int pd_set_power_supply_ready(int port) { int rv; - if (port >= sn5s330_cnt) + if (port >= ppc_cnt) return EC_ERROR_INVAL; /* Disable charging. */ - rv = sn5s330_pp_fet_enable(port, SN5S330_PP2, 0); + rv = ppc_vbus_sink_enable(port, 0); if (rv) return rv; /* Provide Vbus. */ - rv = sn5s330_pp_fet_enable(port, SN5S330_PP1, 1); + rv = ppc_vbus_source_enable(port, 1); if (rv) return rv; diff --git a/common/build.mk b/common/build.mk index c0ea4bbd5f..70922f95fe 100644 --- a/common/build.mk +++ b/common/build.mk @@ -112,6 +112,7 @@ common-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_protocol.o usb_pd_policy.o common-$(CONFIG_USB_PD_LOGGING)+=event_log.o pd_log.o common-$(CONFIG_USB_PD_TCPC)+=usb_pd_tcpc.o common-$(CONFIG_USB_UPDATE)+=usb_update.o update_fw.o +common-$(CONFIG_USBC_PPC)+=usbc_ppc.o common-$(CONFIG_VBOOT_EFS)+=vboot/vboot.o common-$(CONFIG_VBOOT_HASH)+=sha256.o vboot_hash.o common-$(CONFIG_VOLUME_BUTTONS)+=button.o diff --git a/common/usbc_ppc.c b/common/usbc_ppc.c new file mode 100644 index 0000000000..5d41619a79 --- /dev/null +++ b/common/usbc_ppc.c @@ -0,0 +1,76 @@ +/* Copyright 2017 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* USB-C Power Path Controller Common Code */ + +#include "common.h" +#include "console.h" +#include "hooks.h" +#include "usbc_ppc.h" +#include "util.h" + +#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) +#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) + +/* Simple wrappers to dispatch to the drivers. */ + +int ppc_is_sourcing_vbus(int port) +{ + if ((port < 0) || (port >= ppc_cnt)) { + CPRINTS("%s(%d) Invalid port!", __func__, port); + return 0; + } + + return ppc_chips[port].drv->is_sourcing_vbus(port); +} + +int ppc_vbus_sink_enable(int port, int enable) +{ + if ((port < 0) || (port >= ppc_cnt)) + return EC_ERROR_INVAL; + + return ppc_chips[port].drv->vbus_sink_enable(port, enable); +} + +int ppc_vbus_source_enable(int port, int enable) +{ + if ((port < 0) || (port >= ppc_cnt)) + return EC_ERROR_INVAL; + + return ppc_chips[port].drv->vbus_source_enable(port, enable); +} + +static void ppc_init(void) +{ + int i; + int rv; + + for (i = 0; i < ppc_cnt; i++) { + rv = ppc_chips[i].drv->init(i); + if (rv) + CPRINTS("p%d: PPC init failed! (%d)", i, rv); + else + CPRINTS("p%d: PPC init'd.", i); + } +} +DECLARE_HOOK(HOOK_INIT, ppc_init, HOOK_PRIO_INIT_I2C + 1); + +#ifdef CONFIG_CMD_PPC_DUMP +static int command_ppc_dump(int argc, char **argv) +{ + int port; + + if (argc < 2) + return EC_ERROR_PARAM_COUNT; + + port = atoi(argv[1]); + if (port >= ppc_cnt) + return EC_ERROR_PARAM1; + + return ppc_chips[port].drv->reg_dump(port); +} +DECLARE_CONSOLE_COMMAND(ppc_dump, command_ppc_dump, "<Type-C port>", + "dump the PPC regs"); +#endif /* defined(CONFIG_CMD_PPC_DUMP) */ diff --git a/driver/ppc/sn5s330.c b/driver/ppc/sn5s330.c index 05cb9eac14..136861aac6 100644 --- a/driver/ppc/sn5s330.c +++ b/driver/ppc/sn5s330.c @@ -17,54 +17,38 @@ #include "i2c.h" #include "system.h" #include "timer.h" +#include "usbc_ppc.h" #include "util.h" #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) #define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) -static int read_reg(uint8_t chip_idx, int reg, int *regval) +static int read_reg(uint8_t port, int reg, int *regval) { - if (chip_idx >= sn5s330_cnt) - return EC_ERROR_INVAL; - - return i2c_read8(sn5s330_chips[chip_idx].i2c_port, - sn5s330_chips[chip_idx].i2c_addr, - reg, - regval); + return i2c_read8(ppc_chips[port].i2c_port, + ppc_chips[port].i2c_addr, + reg, + regval); } -static int write_reg(uint8_t chip_idx, int reg, int regval) +static int write_reg(uint8_t port, int reg, int regval) { - if (chip_idx >= sn5s330_cnt) - return EC_ERROR_INVAL; - - return i2c_write8(sn5s330_chips[chip_idx].i2c_port, - sn5s330_chips[chip_idx].i2c_addr, + return i2c_write8(ppc_chips[port].i2c_port, + ppc_chips[port].i2c_addr, reg, regval); } #ifdef CONFIG_CMD_PPC_DUMP -static int command_sn5s330_dump(int argc, char **argv) +static int sn5s330_dump(int port) { int i; int data; - int chip_idx; - int port; - int addr; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - chip_idx = atoi(argv[1]); - if (chip_idx >= sn5s330_cnt) - return EC_ERROR_PARAM1; - - port = sn5s330_chips[chip_idx].i2c_port; - addr = sn5s330_chips[chip_idx].i2c_addr; + const int i2c_port = ppc_chips[port].i2c_port; + const int i2c_addr = ppc_chips[port].i2c_addr; for (i = SN5S330_FUNC_SET1; i <= SN5S330_FUNC_SET12; i++) { - i2c_read8(port, addr, i, &data); + i2c_read8(i2c_port, i2c_addr, i, &data); ccprintf("FUNC_SET%d [%02Xh] = 0x%02x\n", i - SN5S330_FUNC_SET1 + 1, i, @@ -72,7 +56,7 @@ static int command_sn5s330_dump(int argc, char **argv) } for (i = SN5S330_INT_STATUS_REG1; i <= SN5S330_INT_STATUS_REG4; i++) { - i2c_read8(port, addr, i, &data); + i2c_read8(i2c_port, i2c_addr, i, &data); ccprintf("INT_STATUS_REG%d [%02Xh] = 0x%02x\n", i - SN5S330_INT_STATUS_REG1 + 1, i, @@ -81,7 +65,7 @@ static int command_sn5s330_dump(int argc, char **argv) for (i = SN5S330_INT_TRIP_RISE_REG1; i <= SN5S330_INT_TRIP_RISE_REG3; i++) { - i2c_read8(port, addr, i, &data); + i2c_read8(i2c_port, i2c_addr, i, &data); ccprintf("INT_TRIP_RISE_REG%d [%02Xh] = 0x%02x\n", i - SN5S330_INT_TRIP_RISE_REG1 + 1, i, @@ -90,7 +74,7 @@ static int command_sn5s330_dump(int argc, char **argv) for (i = SN5S330_INT_TRIP_FALL_REG1; i <= SN5S330_INT_TRIP_FALL_REG3; i++) { - i2c_read8(port, addr, i, &data); + i2c_read8(i2c_port, i2c_addr, i, &data); ccprintf("INT_TRIP_FALL_REG%d [%02Xh] = 0x%02x\n", i - SN5S330_INT_TRIP_FALL_REG1 + 1, i, @@ -99,7 +83,7 @@ static int command_sn5s330_dump(int argc, char **argv) for (i = SN5S330_INT_MASK_RISE_REG1; i <= SN5S330_INT_MASK_RISE_REG3; i++) { - i2c_read8(port, addr, i, &data); + i2c_read8(i2c_port, i2c_addr, i, &data); ccprintf("INT_MASK_RISE_REG%d [%02Xh] = 0x%02x\n", i - SN5S330_INT_MASK_RISE_REG1 + 1, i, @@ -108,7 +92,7 @@ static int command_sn5s330_dump(int argc, char **argv) for (i = SN5S330_INT_MASK_FALL_REG1; i <= SN5S330_INT_MASK_FALL_REG3; i++) { - i2c_read8(port, addr, i, &data); + i2c_read8(i2c_port, i2c_addr, i, &data); ccprintf("INT_MASK_FALL_REG%d [%02Xh] = 0x%02x\n", i - SN5S330_INT_MASK_FALL_REG1 + 1, i, @@ -117,22 +101,20 @@ static int command_sn5s330_dump(int argc, char **argv) return EC_SUCCESS; } -DECLARE_CONSOLE_COMMAND(ppc_dump, command_sn5s330_dump, - "<Type-C port>", "dump the SN5S330 regs"); #endif /* defined(CONFIG_CMD_PPC_DUMP) */ -static int get_func_set3(uint8_t chip_idx, int *regval) +static int get_func_set3(uint8_t port, int *regval) { int status; - status = read_reg(chip_idx, SN5S330_FUNC_SET3, regval); + status = read_reg(port, SN5S330_FUNC_SET3, regval); if (status) CPRINTS("Failed to read FUNC_SET3!"); return status; } -int sn5s330_is_pp_fet_enabled(uint8_t chip_idx, enum sn5s330_pp_idx pp, +static int sn5s330_is_pp_fet_enabled(uint8_t port, enum sn5s330_pp_idx pp, int *is_enabled) { int pp_bit; @@ -148,7 +130,7 @@ int sn5s330_is_pp_fet_enabled(uint8_t chip_idx, enum sn5s330_pp_idx pp, return EC_ERROR_INVAL; } - status = get_func_set3(chip_idx, ®val); + status = get_func_set3(port, ®val); if (status) return status; @@ -157,7 +139,8 @@ int sn5s330_is_pp_fet_enabled(uint8_t chip_idx, enum sn5s330_pp_idx pp, return EC_SUCCESS; } -int sn5s330_pp_fet_enable(uint8_t chip_idx, enum sn5s330_pp_idx pp, int enable) +static int sn5s330_pp_fet_enable(uint8_t port, enum sn5s330_pp_idx pp, + int enable) { int regval; int status; @@ -170,7 +153,7 @@ int sn5s330_pp_fet_enable(uint8_t chip_idx, enum sn5s330_pp_idx pp, int enable) else return EC_ERROR_INVAL; - status = get_func_set3(chip_idx, ®val); + status = get_func_set3(port, ®val); if (status) return status; @@ -179,7 +162,7 @@ int sn5s330_pp_fet_enable(uint8_t chip_idx, enum sn5s330_pp_idx pp, int enable) else regval &= ~pp_bit; - status = write_reg(chip_idx, SN5S330_FUNC_SET3, regval); + status = write_reg(port, SN5S330_FUNC_SET3, regval); if (status) { CPRINTS("Failed to set FUNC_SET3!"); return status; @@ -188,17 +171,14 @@ int sn5s330_pp_fet_enable(uint8_t chip_idx, enum sn5s330_pp_idx pp, int enable) return EC_SUCCESS; } -static int init_sn5s330(int idx) +static int sn5s330_init(int port) { int regval; int status; int retries; - int i2c_port; - int i2c_addr; int reg; - - i2c_port = sn5s330_chips[idx].i2c_port; - i2c_addr = sn5s330_chips[idx].i2c_addr; + const int i2c_port = ppc_chips[port].i2c_port; + const int i2c_addr = ppc_chips[port].i2c_addr; /* Set the sourcing current limit value. */ #if defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) && \ @@ -306,7 +286,7 @@ static int init_sn5s330(int idx) } /* Turn off PP1 FET. */ - status = sn5s330_pp_fet_enable(idx, SN5S330_PP1, 0); + status = sn5s330_pp_fet_enable(port, SN5S330_PP1, 0); if (status) { CPRINTS("Failed to turn off PP1 FET!"); } @@ -415,7 +395,7 @@ static int init_sn5s330(int idx) SN5S330_DB_BOOT); /* Turn on PP2 FET. */ - status = sn5s330_pp_fet_enable(idx, SN5S330_PP2, 1); + status = sn5s330_pp_fet_enable(port, SN5S330_PP2, 1); if (status) { CPRINTS("Failed to turn on PP2 FET!"); return status; @@ -425,24 +405,9 @@ static int init_sn5s330(int idx) return EC_SUCCESS; } -static void sn5s330_init(void) -{ - int i; - int rv; - - for (i = 0; i < sn5s330_cnt; i++) { - rv = init_sn5s330(i); - if (!rv) - CPRINTS("C%d: SN5S330 init done.", i); - else - CPRINTS("C%d: SN5S330 init failed! (%d)", i, rv); - } -} -DECLARE_HOOK(HOOK_INIT, sn5s330_init, HOOK_PRIO_INIT_I2C + 1); - -int ppc_is_sourcing_vbus(int port) +static int sn5s330_is_sourcing_vbus(int port) { - int is_sourcing_vbus; + int is_sourcing_vbus = 0; int rv; rv = sn5s330_is_pp_fet_enabled(port, SN5S330_PP1, &is_sourcing_vbus); @@ -455,12 +420,22 @@ int ppc_is_sourcing_vbus(int port) return is_sourcing_vbus; } -int ppc_vbus_sink_enable(int port, int enable) +static int sn5s330_vbus_sink_enable(int port, int enable) { return sn5s330_pp_fet_enable(port, SN5S330_PP2, !!enable); } -int ppc_vbus_source_enable(int port, int enable) +static int sn5s330_vbus_source_enable(int port, int enable) { return sn5s330_pp_fet_enable(port, SN5S330_PP1, !!enable); } + +const struct ppc_drv sn5s330_drv = { + .init = &sn5s330_init, + .is_sourcing_vbus = &sn5s330_is_sourcing_vbus, + .vbus_sink_enable = &sn5s330_vbus_sink_enable, + .vbus_source_enable = &sn5s330_vbus_source_enable, +#ifdef CONFIG_CMD_PPC_DUMP + .reg_dump = &sn5s330_dump, +#endif /* defined(CONFIG_CMD_PPC_DUMP) */ +}; diff --git a/driver/ppc/sn5s330.h b/driver/ppc/sn5s330.h index f1bea3da46..059df14a30 100644 --- a/driver/ppc/sn5s330.h +++ b/driver/ppc/sn5s330.h @@ -116,26 +116,6 @@ enum sn5s330_pp_idx { */ #define SN5S330_ILIM_PP1_MASK (1 << 4) -/** - * Determine if a PP FET is enabled or not. - * - * @param chip_idx: The index into the sn5s330_chips[] table. - * @param pp: The power path index (PP1 or PP2). - * @param is_enabled: 1 to turn on the FET, 0 to turn off. - * @return EC_SUCCESS if i2c access worked, otherwise an error. - */ -int sn5s330_is_pp_fet_enabled(uint8_t chip_idx, enum sn5s330_pp_idx pp, - int *is_enabled); - -/** - * Turn on/off the PP1 or PP2 FET. - * - * @param chip_idx: The index into the sn5s330_chips[] table. - * @param pp: The power path index (PP1 or PP2). - * @param enable: 1 to turn on the FET, 0 to turn off. - * @return EC_SUCCESS on success, - * otherwise if failed to enable the FET. - */ -int sn5s330_pp_fet_enable(uint8_t chip_idx, enum sn5s330_pp_idx pp, int enable); +extern const struct ppc_drv sn5s330_drv; #endif /* defined(__CROS_EC_SN5S330_H) */ diff --git a/include/usbc_ppc.h b/include/usbc_ppc.h index 0af3e766e3..05e671728a 100644 --- a/include/usbc_ppc.h +++ b/include/usbc_ppc.h @@ -8,30 +8,88 @@ #include "common.h" - /* Common APIs for USB Type-C Power Path Controllers (PPC) */ +struct ppc_drv { + /** + * Initialize the PPC. + * + * @param port: The Type-C port number. + * @return EC_SUCCESS when init was successful, error otherwise. + */ + int (*init)(int port); + + /** + * Is the port sourcing Vbus? + * + * @param port: The Type-C port number. + * @return 1 if sourcing Vbus, 0 if not. + */ + int (*is_sourcing_vbus)(int port); + + /** + * Turn on/off the charge path FET, such that current flows into the + * system. + * + * @param port: The Type-C port number. + * @param enable: 1: Turn on the FET, 0: turn off the FET. + * @return EC_SUCCESS on success, error otherwise. + */ + int (*vbus_sink_enable)(int port, int enable); + + /** + * Turn on/off the source path FET, such that current flows from the + * system. + * + * @param port: The Type-C port number. + * @param enable: 1: Turn on the FET, 0: turn off the FET. + * @return EC_SUCCESS on success, error otherwise. + */ + int (*vbus_source_enable)(int port, int enable); + +#ifdef CONFIG_CMD_PPC_DUMP + /** + * Perform a register dump of the PPC. + * + * @param port: The Type-C port number. + * @return EC_SUCCESS on success, error otherwise. + */ + int (*reg_dump)(int port); +#endif /* defined(CONFIG_CMD_PPC_DUMP) */ +}; + +struct ppc_config_t { + int i2c_port; + int i2c_addr; + const struct ppc_drv *drv; +}; + +extern const struct ppc_config_t ppc_chips[]; +extern const unsigned int ppc_cnt; + /** * Is the port sourcing Vbus? * - * @param port: The type c port. + * @param port: The Type-C port number. * @return 1 if sourcing Vbus, 0 if not. */ int ppc_is_sourcing_vbus(int port); /** - * Allow current to flow into the system. + * Turn on/off the charge path FET, such that current flows into the + * system. * - * @param port: The Type-C port's FET to open. + * @param port: The Type-C port number. * @param enable: 1: Turn on the FET, 0: turn off the FET. * @return EC_SUCCESS on success, error otherwise. */ int ppc_vbus_sink_enable(int port, int enable); /** - * Allow current out of the system. + * Turn on/off the source path FET, such that current flows from the + * system. * - * @param port: The Type-C port's FET to open. + * @param port: The Type-C port number. * @param enable: 1: Turn on the FET, 0: turn off the FET. * @return EC_SUCCESS on success, error otherwise. */ |