diff options
author | David Huang <david.huang@quanta.corp-partner.google.com> | 2023-03-17 09:19:45 +0800 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-03-20 04:12:43 +0000 |
commit | 441ba1e1d063ff0bf8befd7055adf77a1e05794c (patch) | |
tree | 9b54bbb2e9f6c3f9ef381fa862f3ccb325d80752 | |
parent | ef44ebdc0a74ddca5b8cf9722f0afe0cf858b70e (diff) | |
download | chrome-ec-441ba1e1d063ff0bf8befd7055adf77a1e05794c.tar.gz |
common: Move pse driver into driver place
Since there are more projects using this driver.
Move it into driver place.
BUG=b:273191751
BRANCH=None
TEST=make buildall -j
Change-Id: I50e2cb480a551ce19722edc2b6f70824f4b9147e
Signed-off-by: David Huang <david.huang@quanta.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4335461
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r-- | driver/build.mk | 3 | ||||
-rw-r--r-- | driver/pse_ltc4291.c | 209 | ||||
-rw-r--r-- | include/config.h | 3 | ||||
-rw-r--r-- | include/driver/pse_ltc4291.h | 60 | ||||
-rw-r--r-- | zephyr/CMakeLists.txt | 2 | ||||
-rw-r--r-- | zephyr/Kconfig | 7 | ||||
-rw-r--r-- | zephyr/shim/include/config_chip.h | 5 |
7 files changed, 289 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk index 23e6dcd149..3d3871e7ec 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -124,6 +124,9 @@ driver-$(CONFIG_GPU_NVIDIA)+=nvidia_gpu.o # Voltage regulators driver-$(CONFIG_REGULATOR_IR357X)+=regulator_ir357x.o +# Power Sourcing Equipment +driver-$(CONFIG_PSE_LTC4291)+=pse_ltc4291.o + # Temperature sensors driver-$(CONFIG_TEMP_SENSOR_ADT7481)+=temp_sensor/adt7481.o driver-$(CONFIG_TEMP_SENSOR_BD99992GW)+=temp_sensor/bd99992gw.o diff --git a/driver/pse_ltc4291.c b/driver/pse_ltc4291.c new file mode 100644 index 0000000000..80255eb501 --- /dev/null +++ b/driver/pse_ltc4291.c @@ -0,0 +1,209 @@ +/* Copyright 2023 The ChromiumOS Authors + * 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 "host_command.h" +#include "i2c.h" +#include "pse_ltc4291.h" +#include "string.h" +#include "timer.h" +#include "util.h" + +#define CPRINTS(format, args...) cprints(CC_SYSTEM, "PSE: " 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; + } +} + +static int pse_port_enable(int port) +{ + /* Enable detection and classification */ + return I2C_PSE_WRITE(DETPB, LTC4291_DETPB_EN_PORT(port)); +} + +static int pse_port_disable(int port) +{ + /* Request power off (this also disables detection/classification) */ + return I2C_PSE_WRITE(PWRPB, LTC4291_PWRPB_OFF_PORT(port)); +} + +static int pse_init_worker(void) +{ + timestamp_t deadline; + int err, id, devid, statpin, port; + + /* Ignore errors -- may already be resetting */ + I2C_PSE_WRITE(RSTPB, LTC4291_FLD_RSTPB_RSTALL); + + deadline.val = get_time().val + LTC4291_RESET_DELAY_US; + while ((err = I2C_PSE_READ(ID, &id)) != EC_SUCCESS) { + if (timestamp_expired(deadline, NULL)) + return EC_ERROR_TIMEOUT; + msleep(1); + } + + err = I2C_PSE_READ(DEVID, &devid); + if (err != EC_SUCCESS) + return err; + + if (id != LTC4291_ID || devid != LTC4291_DEVID) + return EC_ERROR_INVAL; + + err = I2C_PSE_READ(STATPIN, &statpin); + if (err != EC_SUCCESS) + 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 != EC_SUCCESS) + return err; + + /* Set maximum power each port is allowed to allocate. */ + for (port = 0; port < LTC4291_PORT_MAX; port++) { + err = pse_write_hpmd(port, pse_port_hpmd[port]); + if (err != EC_SUCCESS) + return err; + } + + err = I2C_PSE_WRITE(DISENA, LTC4291_DISENA_ALL); + if (err != EC_SUCCESS) + return err; + + err = I2C_PSE_WRITE(DETENA, LTC4291_DETENA_ALL); + if (err != EC_SUCCESS) + return err; + + return EC_SUCCESS; +} + +static void pse_init(void) +{ + int err; + + err = pse_init_worker(); + if (err != EC_SUCCESS) + CPRINTS("PSE init failed: %d", err); + else + CPRINTS("PSE init done"); +} +DECLARE_HOOK(HOOK_CHIPSET_RESUME, pse_init, HOOK_PRIO_DEFAULT); + +/* Also reset the PSE on a reboot to toggle the power. */ +DECLARE_HOOK(HOOK_CHIPSET_RESET, pse_init, HOOK_PRIO_DEFAULT); + +static int command_pse(int argc, const char **argv) +{ + int port; + + /* + * 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 < 0 || port >= LTC4291_PORT_MAX) + return EC_ERROR_PARAM1; + + if (!strncmp(argv[2], "off", 3)) + return pse_port_disable(port); + else if (!strncmp(argv[2], "on", 2)) + return pse_port_enable(port); + else if (!strncmp(argv[2], "min", 3)) + return pse_write_hpmd(port, LTC4291_HPMD_MIN); + else if (!strncmp(argv[2], "max", 3)) + return pse_write_hpmd(port, LTC4291_HPMD_MAX); + else + return EC_ERROR_PARAM2; +} +DECLARE_CONSOLE_COMMAND(pse, command_pse, "<port# 0-3> <off | on | min | max>", + "Set PSE port power"); + +static int ec_command_pse_status(int port, uint8_t *status) +{ + int detena, statpwr; + int err; + + err = I2C_PSE_READ(DETENA, &detena); + if (err != EC_SUCCESS) + return err; + + err = I2C_PSE_READ(STATPWR, &statpwr); + if (err != EC_SUCCESS) + return err; + + if ((detena & LTC4291_DETENA_EN_PORT(port)) == 0) + *status = EC_PSE_STATUS_DISABLED; + else if ((statpwr & LTC4291_STATPWR_ON_PORT(port)) == 0) + *status = EC_PSE_STATUS_ENABLED; + else + *status = EC_PSE_STATUS_POWERED; + + return EC_SUCCESS; +} + +static enum ec_status ec_command_pse(struct host_cmd_handler_args *args) +{ + const struct ec_params_pse *p = args->params; + int err = 0; + + if (p->port >= LTC4291_PORT_MAX) + return EC_RES_INVALID_PARAM; + + switch (p->cmd) { + case EC_PSE_STATUS: { + struct ec_response_pse_status *r = args->response; + + args->response_size = sizeof(*r); + err = ec_command_pse_status(p->port, &r->status); + break; + } + case EC_PSE_ENABLE: + err = pse_port_enable(p->port); + break; + case EC_PSE_DISABLE: + err = pse_port_disable(p->port); + break; + default: + return EC_RES_INVALID_PARAM; + } + + if (err) + return EC_RES_ERROR; + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_PSE, ec_command_pse, EC_VER_MASK(0)); diff --git a/include/config.h b/include/config.h index af7ef8d94d..59900a7fcb 100644 --- a/include/config.h +++ b/include/config.h @@ -3748,6 +3748,9 @@ /* Support PS/2 interface */ #undef CONFIG_PS2 +/* Support Power Sourcing Equipment */ +#undef CONFIG_PSE_LTC4291 + /* * Define this option to enable programmable voltage detector which will * trigger an interrupt when the voltage drops below a threshold specified diff --git a/include/driver/pse_ltc4291.h b/include/driver/pse_ltc4291.h new file mode 100644 index 0000000000..4db9ac4998 --- /dev/null +++ b/include/driver/pse_ltc4291.h @@ -0,0 +1,60 @@ +/* Copyright 2023 The ChromiumOS Authors + * 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 "i2c.h" +#include "timer.h" +#include "util.h" + +#define LTC4291_I2C_ADDR 0x2C + +#define LTC4291_REG_SUPEVN_COR 0x0B +#define LTC4291_REG_STATPWR 0x10 +#define LTC4291_REG_STATPIN 0x11 +#define LTC4291_REG_OPMD 0x12 +#define LTC4291_REG_DISENA 0x13 +#define LTC4291_REG_DETENA 0x14 +#define LTC4291_REG_DETPB 0x18 +#define LTC4291_REG_PWRPB 0x19 +#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_REG_LPWRPB 0x6E + +#define LTC4291_FLD_STATPIN_AUTO BIT(0) +#define LTC4291_FLD_RSTPB_RSTALL BIT(4) + +#define LTC4291_STATPWR_ON_PORT(port) (0x01 << (port)) +#define LTC4291_DETENA_EN_PORT(port) (0x11 << (port)) +#define LTC4291_DETPB_EN_PORT(port) (0x11 << (port)) +#define LTC4291_PWRPB_OFF_PORT(port) (0x10 << (port)) + +#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_PORT_MAX 4 + +#define LTC4291_RESET_DELAY_US (20 * MSEC) + +#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)) + +extern const int pse_port_hpmd[LTC4291_PORT_MAX]; diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 33dabdeba5..a9a8e6c4f0 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -376,6 +376,8 @@ if (CONFIG_PLATFORM_EC_HIBERNATE AND CONFIG_AP_PWRSEQ) endif () zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_PANIC "${PLATFORM_EC}/common/panic_output.c") +zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_PSE_LTC4291 + "${PLATFORM_EC}/driver/pse_ltc4291.c") zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_SHA256_SW "${PLATFORM_EC}/common/sha256.c") zephyr_library_sources_ifdef(CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE diff --git a/zephyr/Kconfig b/zephyr/Kconfig index f8ae3553ab..5a4850da25 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -562,6 +562,13 @@ config PLATFORM_EC_BUTTON_DEBOUNCE help Configure the button debounce time in us per project requirement. +config PLATFORM_EC_PSE_LTC4291 + bool "power sourcing equipment (PSE) support" + help + Enable the power sourcing equipment (PSE) driver support for + Analog Device power over ethernet (PoE) power sourcing equipment (PSE) + controller. + config PLATFORM_EC_PWM_HC bool help diff --git a/zephyr/shim/include/config_chip.h b/zephyr/shim/include/config_chip.h index e073f13396..d8ef2b04f2 100644 --- a/zephyr/shim/include/config_chip.h +++ b/zephyr/shim/include/config_chip.h @@ -835,6 +835,11 @@ extern char mock_jump_data[CONFIG_PLATFORM_EC_PRESERVED_END_OF_RAM_SIZE]; #define CONFIG_BUTTON_TRIGGERED_RECOVERY #endif +#undef CONFIG_PSE_LTC4291 +#ifdef PLATFORM_EC_PSE_LTC4291 +#define CONFIG_PSE_LTC4291 +#endif + #undef CONFIG_PWM_KBLIGHT #undef CONFIG_KEYBOARD_BACKLIGHT #ifdef CONFIG_PLATFORM_EC_PWM_KBLIGHT |