diff options
author | Jeff Chase <jnchase@google.com> | 2020-05-08 06:12:43 -0400 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-05-14 01:58:53 +0000 |
commit | 02ee9d00ac31e6ef36bbc8f378dc319143dccd03 (patch) | |
tree | c21f3339e0b2b9557b488e4fe517a05b74ba4fec | |
parent | ffa5571e4d7de4dc96ba36f5069e3ff150bde071 (diff) | |
download | chrome-ec-02ee9d00ac31e6ef36bbc8f378dc319143dccd03.tar.gz |
endeavour: add pse init
Endeavour has an onboard PoE PSE controller. This change initializes
the controller and sets per port maximum power.
BRANCH=none
BUG=b:155863756
TEST=build + boot, various pse commands
Change-Id: I1505917f6fac8a569f40102162b0d036e8079a36
Signed-off-by: Jeff Chase <jnchase@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2189562
Reviewed-by: Joe Tessler <jrt@chromium.org>
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Commit-Queue: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r-- | board/endeavour/board.c | 2 | ||||
-rw-r--r-- | board/endeavour/board.h | 2 | ||||
-rw-r--r-- | board/endeavour/build.mk | 1 | ||||
-rw-r--r-- | board/endeavour/pse.c | 181 |
4 files changed, 184 insertions, 2 deletions
diff --git a/board/endeavour/board.c b/board/endeavour/board.c index 128b3b4280..8a40c6b7b7 100644 --- a/board/endeavour/board.c +++ b/board/endeavour/board.c @@ -86,7 +86,7 @@ const struct mft_t mft_channels[] = { BUILD_ASSERT(ARRAY_SIZE(mft_channels) == MFT_CH_COUNT); const struct i2c_port_t i2c_ports[] = { - {"poe", I2C_PORT_POE, 400, GPIO_I2C0_0_SCL, GPIO_I2C0_0_SDA}, + {"pse", I2C_PORT_PSE, 400, GPIO_I2C0_0_SCL, GPIO_I2C0_0_SDA}, {"eeprom", I2C_PORT_EEPROM, 400, GPIO_I2C0_1_SCL, GPIO_I2C0_1_SDA}, {"pmic", I2C_PORT_PMIC, 400, GPIO_I2C2_SCL, GPIO_I2C2_SDA}, {"thermal", I2C_PORT_THERMAL, 400, GPIO_I2C3_SCL, GPIO_I2C3_SDA}, diff --git a/board/endeavour/board.h b/board/endeavour/board.h index 19395732c1..29ca1316f9 100644 --- a/board/endeavour/board.h +++ b/board/endeavour/board.h @@ -88,7 +88,7 @@ #define NPCX_TACH_SEL2 1 /* 0:GPIO40/73 1:GPIO93/A6 as TACH */ /* I2C ports */ -#define I2C_PORT_POE NPCX_I2C_PORT0_0 +#define I2C_PORT_PSE NPCX_I2C_PORT0_0 #define I2C_PORT_EEPROM NPCX_I2C_PORT0_1 #define I2C_PORT_PMIC NPCX_I2C_PORT2 #define I2C_PORT_THERMAL NPCX_I2C_PORT3 diff --git a/board/endeavour/build.mk b/board/endeavour/build.mk index b5915c43a8..20f3f4d02c 100644 --- a/board/endeavour/build.mk +++ b/board/endeavour/build.mk @@ -11,3 +11,4 @@ CHIP_VARIANT:=npcx5m6g board-y=board.o board-y+=led.o +board-y+=pse.o diff --git a/board/endeavour/pse.c b/board/endeavour/pse.c new file mode 100644 index 0000000000..c4484d257c --- /dev/null +++ b/board/endeavour/pse.c @@ -0,0 +1,181 @@ +/* Copyright 2020 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. + */ + +/* + * The LTC4291 is a power over ethernet (PoE) power sourcing equipment (PSE) + * controller. + */ + +#include "common.h" +#include "console.h" +#include "ec_commands.h" +#include "hooks.h" +#include "i2c.h" +#include "string.h" +#include "timer.h" +#include "util.h" + +#define LTC4291_I2C_ADDR 0x2C + +#define LTC4291_REG_SUPEVN_COR 0x0B +#define LTC4291_REG_STATPIN 0x11 +#define LTC4291_REG_OPMD 0x12 +#define LTC4291_REG_DISENA 0x13 +#define LTC4291_REG_DETENA 0x14 +#define LTC4291_REG_RSTPB 0x1A +#define LTC4291_REG_ID 0x1B +#define LTC4291_REG_DEVID 0x43 +#define LTC4291_REG_HPMD1 0x46 +#define LTC4291_REG_HPMD2 0x4B +#define LTC4291_REG_HPMD3 0x50 +#define LTC4291_REG_HPMD4 0x55 + +#define LTC4291_FLD_STATPIN_AUTO BIT(0) +#define LTC4291_FLD_RSTPB_RSTALL BIT(4) + +#define LTC4291_OPMD_AUTO 0xFF +#define LTC4291_DISENA_ALL 0x0F +#define LTC4291_DETENA_ALL 0xFF +#define LTC4291_ID 0x64 +#define LTC4291_DEVID 0x38 +#define LTC4291_HPMD_MIN 0x00 +#define LTC4291_HPMD_MAX 0xA8 + +#define LTC4291_RESET_DELAY_MS 10 + +#define I2C_PSE_READ(reg, data) \ + i2c_read8(I2C_PORT_PSE, LTC4291_I2C_ADDR, LTC4291_REG_##reg, (data)) + +#define I2C_PSE_WRITE(reg, data) \ + i2c_write8(I2C_PORT_PSE, LTC4291_I2C_ADDR, LTC4291_REG_##reg, (data)) + +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) + +static int pse_write_hpmd(int port, int val) +{ + switch (port) { + case 0: + return I2C_PSE_WRITE(HPMD1, val); + case 1: + return I2C_PSE_WRITE(HPMD2, val); + case 2: + return I2C_PSE_WRITE(HPMD3, val); + case 3: + return I2C_PSE_WRITE(HPMD4, val); + default: + return EC_ERROR_INVAL; + } +} + +/* + * Port 1: 100W + * Port 2-4: 15W + */ +static int pse_port_hpmd[4] = { + LTC4291_HPMD_MAX, + LTC4291_HPMD_MIN, + LTC4291_HPMD_MIN, + LTC4291_HPMD_MIN, +}; + +static int pse_init_worker(void) +{ + int err, id, devid, statpin, port; + + err = I2C_PSE_WRITE(RSTPB, LTC4291_FLD_RSTPB_RSTALL); + if (err != 0) + return err; + + msleep(LTC4291_RESET_DELAY_MS); + + err = I2C_PSE_READ(ID, &id); + if (err != 0) + return err; + + err = I2C_PSE_READ(DEVID, &devid); + if (err != 0) + return err; + + if (id != LTC4291_ID || devid != LTC4291_DEVID) + return EC_ERROR_INVAL; + + err = I2C_PSE_READ(STATPIN, &statpin); + if (err != 0) + return err; + + /* + * We don't want to supply power until we've had a chance to set the + * limits. + */ + if (statpin & LTC4291_FLD_STATPIN_AUTO) + CPRINTS("WARN: PSE reset in AUTO mode"); + + err = I2C_PSE_WRITE(OPMD, LTC4291_OPMD_AUTO); + if (err != 0) + return err; + + /* Set maximum power each port is allowed to allocate. */ + for (port = 0; port < 4; port++) { + err = pse_write_hpmd(port, pse_port_hpmd[port]); + if (err != 0) + return err; + } + + err = I2C_PSE_WRITE(DISENA, LTC4291_DISENA_ALL); + if (err != 0) + return err; + + err = I2C_PSE_WRITE(DETENA, LTC4291_DETENA_ALL); + if (err != 0) + return err; + + return 0; +} + +static void pse_init(void) +{ + int err; + + err = pse_init_worker(); + if (err != 0) + CPRINTS("PSE init failed: %d", err); + else + CPRINTS("PSE init done"); +} +DECLARE_HOOK(HOOK_INIT, pse_init, HOOK_PRIO_INIT_I2C); + +static int command_pse(int argc, char **argv) +{ + int port; + + /* + * TODO(b/156399232): endeavour: PSE controller reset by PLTRST + * + * Initialization does not reliably work after reset because the device + * is held in reset by the AP. Running this command after boot finishes + * always succeeds. Remove once the reset signal changes. + */ + if (!strncmp(argv[1], "init", 4)) + return pse_init_worker(); + + if (argc != 3) + return EC_ERROR_PARAM_COUNT; + + port = atoi(argv[1]); + if (port < 1 || port > 4) + return EC_ERROR_PARAM1; + + if (!strncmp(argv[2], "off", 3)) + return EC_ERROR_UNIMPLEMENTED; + else if (!strncmp(argv[2], "min", 3)) + return pse_write_hpmd(port - 1, LTC4291_HPMD_MIN); + else if (!strncmp(argv[2], "max", 3)) + return pse_write_hpmd(port - 1, LTC4291_HPMD_MAX); + else + return EC_ERROR_PARAM2; +} +DECLARE_CONSOLE_COMMAND(pse, command_pse, + "<port# 1-4> <off | min | max>", + "Set PSE port power"); |