diff options
author | Wai-Hong Tam <waihong@google.com> | 2020-08-31 15:46:46 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-09-02 01:45:16 +0000 |
commit | 20b99a7070220a3ef191ca20a4b1155b0acc4e18 (patch) | |
tree | a945c2afefbbee68b6f91a10eba24a4b9d534e07 | |
parent | 60dc637cf3dd8366467925b74c646a825eff53a8 (diff) | |
download | chrome-ec-20b99a7070220a3ef191ca20a4b1155b0acc4e18.tar.gz |
driver: Add LN9310 switchcap driver
Add LN9310 2:1 and 3:1 switchcap driver. It will be used in Trogdor
projects.
BRANCH=None
BUG=b:163867792
TEST=Defined the CONFIG and built correctly.
Change-Id: I14b55c7cd3be06e3811cc58a182b1694e6ad57ff
Signed-off-by: Wai-Hong Tam <waihong@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2386481
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-rw-r--r-- | driver/build.mk | 3 | ||||
-rw-r--r-- | driver/ln9310.c | 187 | ||||
-rw-r--r-- | driver/ln9310.h | 133 | ||||
-rw-r--r-- | include/config.h | 2 |
4 files changed, 325 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk index d970bd142b..5645c16094 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -180,6 +180,9 @@ endif driver-$(CONFIG_USBC_PPC_SYV682X)+=ppc/syv682x.o driver-$(CONFIG_USBC_PPC_NX20P3483)+=ppc/nx20p348x.o +# Switchcap +driver-$(CONFIG_LN9310)+=ln9310.o + # video converters driver-$(CONFIG_MCDP28X0)+=mcdp28x0.o diff --git a/driver/ln9310.c b/driver/ln9310.c new file mode 100644 index 0000000000..5a82f3fa28 --- /dev/null +++ b/driver/ln9310.c @@ -0,0 +1,187 @@ +/* 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. + * + * LION Semiconductor LN-9310 switched capacitor converter. + */ + +#include "common.h" +#include "console.h" +#include "ln9310.h" +#include "hooks.h" +#include "i2c.h" +#include "util.h" + +#define CPUTS(outstr) cputs(CC_CHIPSET, outstr) +#define CPRINTF(format, args...) cprintf(CC_CHIPSET, format, ## args) +#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args) + +static int power_good; + +int ln9310_power_good(void) +{ + return power_good; +} + +static inline int raw_read8(int offset, int *value) +{ + return i2c_read8(ln9310_config.i2c_port, + ln9310_config.i2c_addr_flags, + offset, + value); +} + +static inline int field_update8(int offset, int mask, int value) +{ + /* Clear mask and then set value in i2c reg value */ + return i2c_field_update8(ln9310_config.i2c_port, + ln9310_config.i2c_addr_flags, + offset, + mask, + value); +} + +static void ln9310_irq_deferred(void) +{ + int status, val, pg_2to1, pg_3to1; + + status = raw_read8(LN9310_REG_INT1, &val); + if (status) { + CPRINTS("LN9310 reading INT1 failed"); + return; + } + + CPRINTS("LN9310 received interrupt: 0x%x", val); + /* Don't care other interrupts except mode change */ + if (!(val & LN9310_INT1_MODE)) + return; + + /* Check if the device is active in 2:1 or 3:1 switching mode */ + status = raw_read8(LN9310_REG_SYS_STS, &val); + if (status) { + CPRINTS("LN9310 reading SYS_STS failed"); + return; + } + CPRINTS("LN9310 system status: 0x%x", val); + + /* Either 2:1 or 3:1 mode active is treated as PGOOD */ + pg_2to1 = !!(val & LN9310_SYS_SWITCHING21_ACTIVE); + pg_3to1 = !!(val & LN9310_SYS_SWITCHING31_ACTIVE); + power_good = pg_2to1 || pg_3to1; +} +DECLARE_DEFERRED(ln9310_irq_deferred); + +void ln9310_interrupt(enum gpio_signal signal) +{ + hook_call_deferred(&ln9310_irq_deferred_data, 0); +} + +static int is_battery_3s(void) +{ + int status, val, batt3s; + + CPRINTS("LN9310 checking input voltage (2S/3S), threshold=10V"); + /* + * Turn on INFET_OUT_SWITCH_OK comparator; + * configure INFET_OUT_SWITCH_OK to 10V. + */ + field_update8(LN9310_REG_TRACK_CTRL, + LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_MASK | + LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_MASK, + LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_ON | + LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_10V); + + /* Read INFET_OUT_SWITCH_OK comparator */ + status = raw_read8(LN9310_REG_BC_STS_B, &val); + if (status) { + CPRINTS("LN9310 reading BC_STS_B failed"); + return -1; + } + CPRINTS("LN9310 BC_STS_B: 0x%x", val); + + /* + * If INFET_OUT_SWITCH_OK=0, VIN < 10V --> 2S battery + * If INFET_OUT_SWITCH_OK=1, VIN > 10V --> 3S battery + */ + batt3s = !!(val & LN9310_BC_STS_B_INFET_OUT_SWITCH_OK); + CPRINTS("LN9310 %s battery detected", batt3s ? "3S" : "2S"); + + /* Turn off INFET_OUT_SWITCH_OK comparator */ + field_update8(LN9310_REG_TRACK_CTRL, + LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_MASK, + LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_OFF); + + return batt3s; +} + +static void ln9310_init_3to1(void) +{ + CPRINTS("LN9310 init (3:1 operation)"); + + /* Enable track protection and SC_OUT configs for 3:1 switching */ + field_update8(LN9310_REG_MODE_CHANGE_CFG, + LN9310_MODE_TM_TRACK_MASK | + LN9310_MODE_TM_SC_OUT_PRECHG_MASK | + LN9310_MODE_TM_VIN_OV_CFG_MASK, + LN9310_MODE_TM_TRACK_SWITCH31 | + LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH31 | + LN9310_MODE_TM_VIN_OV_CFG_3S); + + /* Enable 3:1 operation mode */ + field_update8(LN9310_REG_PWR_CTRL, + LN9310_PWR_OP_MODE_MASK, + LN9310_PWR_OP_MODE_SWITCH31); + + /* 3S lower bounde delta configurations */ + field_update8(LN9310_REG_SYS_CTRL, + LN9310_SYS_CTRL_LB_DELTA_MASK, + LN9310_SYS_CTRL_LB_DELTA_3S); +} + +static void ln9310_init_2to1(void) +{ + CPRINTS("LN9310 init (2:1 operation)"); + + /* Enable track protection and SC_OUT configs for 2:1 switching */ + field_update8(LN9310_REG_MODE_CHANGE_CFG, + LN9310_MODE_TM_TRACK_MASK | + LN9310_MODE_TM_SC_OUT_PRECHG_MASK, + LN9310_MODE_TM_TRACK_SWITCH21 | + LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH21); + + /* Enable 2:1 operation mode */ + field_update8(LN9310_REG_PWR_CTRL, + LN9310_PWR_OP_MODE_MASK, + LN9310_PWR_OP_MODE_SWITCH21); + + /* 2S lower bounde delta configurations */ + field_update8(LN9310_REG_SYS_CTRL, + LN9310_SYS_CTRL_LB_DELTA_MASK, + LN9310_SYS_CTRL_LB_DELTA_2S); +} + +void ln9310_init(void) +{ + int status, val, batt3s; + + batt3s = is_battery_3s(); + if (batt3s == -1) + return; + else if (batt3s) + ln9310_init_3to1(); + else + ln9310_init_2to1(); + + /* Unmask the MODE change interrupt */ + field_update8(LN9310_REG_INT1_MSK, + LN9310_INT1_MODE, + 0); + + /* Dummy clear all interrupts */ + status = raw_read8(LN9310_REG_INT1, &val); + if (status) { + CPRINTS("LN9310 reading INT1 failed"); + return; + } + CPRINTS("LN9310 cleared interrupts: 0x%x", val); +} diff --git a/driver/ln9310.h b/driver/ln9310.h new file mode 100644 index 0000000000..92aa16e822 --- /dev/null +++ b/driver/ln9310.h @@ -0,0 +1,133 @@ +/* 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. + * + * LION Semiconductor LN-9310 switched capacitor converter. + */ + +#ifndef __CROS_EC_LN9310_H +#define __CROS_EC_LN9310_H + +/* I2C address */ +#define LN9310_I2C_ADDR_0_FLAGS 0x72 +#define LN9310_I2C_ADDR_1_FLAGS 0x73 +#define LN9310_I2C_ADDR_2_FLAGS 0x53 +#define LN9310_I2C_ADDR_3_FLAGS 0x54 + +/* Registers */ +#define LN9310_REG_CHIP_ID 0x00 +#define LN9310_CHIP_ID 0x44 +#define LN9310_REG_INT1 0x01 +#define LN9310_REG_INT1_MSK 0x02 +#define LN9310_INT1_TIMER BIT(0) +#define LN9310_INT1_INFET BIT(1) +#define LN9310_INT1_TEMP BIT(2) +#define LN9310_INT1_REV_CURR BIT(3) +#define LN9310_INT1_MODE BIT(4) +#define LN9310_INT1_ALARM BIT(5) +#define LN9310_INT1_OK BIT(6) +#define LN9310_INT1_FAULT BIT(7) + +#define LN9310_REG_SYSGPIO_MSK 0x03 + +#define LN9310_REG_SYS_STS 0x04 +#define LN9310_SYS_STANDBY BIT(0) +#define LN9310_SYS_SWITCHING21_ACTIVE BIT(1) +#define LN9310_SYS_SWITCHING31_ACTIVE BIT(2) +#define LN9310_SYS_BYPASS_ACTIVE BIT(3) +#define LN9310_SYS_INFET_OK BIT(4) +#define LN9310_SYS_SC_OUT_SWITCH_OK BIT(5) +#define LN9310_SYS_INFET_OUT_SWITCH_OK BIT(6) + +#define LN9310_REG_SAFETY_STS 0x05 +#define LN9310_REG_FAULT1_STS 0x06 +#define LN9310_REG_FAULT2_STS 0x07 + +#define LN9310_REG_PWR_CTRL 0x1d +#define LN9310_PWR_OP_MODE0 BIT(0) +#define LN9310_PWR_OP_MODE1 BIT(1) +#define LN9310_PWR_INFET_EN BIT(2) +#define LN9310_PWR_INFET_AUTO_MODE BIT(3) +#define LN9310_PWR_REVERSE_MODE BIT(4) +#define LN9310_PWR_VIN_OV_IGNORE BIT(5) +#define LN9310_PWR_OP_MANUAL_UPDATE BIT(6) +#define LN9310_PWR_FORCE_INSNS_EN BIT(7) +#define LN9310_PWR_OP_MODE_MASK 0x03 +#define LN9310_PWR_OP_MODE_DISABLED 0x00 +#define LN9310_PWR_OP_MODE_BYPASS 0x01 +#define LN9310_PWR_OP_MODE_SWITCH21 0x02 +#define LN9310_PWR_OP_MODE_SWITCH31 0x03 + +#define LN9310_REG_SYS_CTRL 0x1e +#define LN9310_SYS_CTRL_LB_DELTA_MASK 0x38 +#define LN9310_SYS_CTRL_LB_DELTA_2S 0x4 +#define LN9310_SYS_CTRL_LB_DELTA_3S 0x4 + +#define LN9310_REG_STARTUP_CTRL 0x1f +#define LN9310_REG_IIN_CTRL 0x20 +#define LN9310_REG_VIN_CTRL 0x21 + +#define LN9310_REG_TRACK_CTRL 0x22 +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_EN BIT(7) +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG2 BIT(6) +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG1 BIT(5) +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG0 BIT(4) +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_MASK 0x80 +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_ON 0x80 +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_OFF 0x00 +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_MASK 0x70 +#define LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_10V 0x10 + +#define LN9310_REG_OCP_CTRL 0x23 +#define LN9310_REG_TIMER_CTRL 0x24 +#define LN9310_REG_RECOVERY_CTRL 0x25 +#define LN9310_REG_LB_CTRL 0x26 +#define LN9310_REG_SC_OUT_OV_CTRL 0x29 +#define LN9310_REG_STS_CTRL 0x2d + +#define LN9310_REG_MODE_CHANGE_CFG 0x2e +#define LN9310_MODE_TM_VIN_OV_CFG0 BIT(0) +#define LN9310_MODE_TM_VIN_OV_CFG1 BIT(1) +#define LN9310_MODE_TM_VIN_OV_CFG2 BIT(2) +#define LN9310_MODE_TM_SC_OUT_PRECHG_CFG0 BIT(3) +#define LN9310_MODE_TM_SC_OUT_PRECHG_CFG1 BIT(4) +#define LN9310_MODE_TM_TRACK_CFG0 BIT(5) +#define LN9310_MODE_TM_TRACK_CFG1 BIT(6) +#define LN9310_MODE_FORCE_MODE_CFG BIT(7) +#define LN9310_MODE_TM_TRACK_MASK 0x60 +#define LN9310_MODE_TM_TRACK_BYPASS 0x00 +#define LN9310_MODE_TM_TRACK_SWITCH21 0x20 +#define LN9310_MODE_TM_TRACK_SWITCH31 0x60 +#define LN9310_MODE_TM_SC_OUT_PRECHG_MASK 0x18 +#define LN9310_MODE_TM_SC_OUT_PRECHG_BYPASS 0x0 +#define LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH21 0x08 +#define LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH31 0x18 +#define LN9310_MODE_TM_VIN_OV_CFG_MASK 0x07 +#define LN9310_MODE_TM_VIN_OV_CFG_2S 0x0 /* 14V */ +#define LN9310_MODE_TM_VIN_OV_CFG_3S 0x2 /* 20V */ + +#define LN9310_REG_SC_DITHER_CTRL 0x2f + +#define LN9310_REG_BC_STS_B 0x51 +#define LN9310_BC_STS_B_INFET_OUT_SWITCH_OK BIT(5) +#define LN9310_BC_STS_B_INFET_OUT_SWITCH_OK_MASK 0x20 + +/* Define configuration of LN9310 part */ +struct ln9310_config_t { + const int i2c_port; + const int i2c_addr_flags; +}; + +/* Configuration struct defined at board level */ +extern const struct ln9310_config_t ln9310_config; + +/* Init the driver */ +void ln9310_init(void); + +/* Interrupt handler */ +void ln9310_interrupt(enum gpio_signal signal); + +/* Return the POWER_GOOD status */ +int ln9310_power_good(void); + +#endif /* __CROS_EC_LN9310_H */ diff --git a/include/config.h b/include/config.h index ea17b81bb7..50b0a12e75 100644 --- a/include/config.h +++ b/include/config.h @@ -3739,6 +3739,8 @@ #undef CONFIG_UART_TX_REQ_CH #undef CONFIG_UART_RX_REQ_CH +/* Driver of LN9310 switchcap */ +#undef CONFIG_LN9310 /*****************************************************************************/ /* USB PD config */ |