summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWai-Hong Tam <waihong@google.com>2020-08-31 15:46:46 -0700
committerCommit Bot <commit-bot@chromium.org>2020-09-02 01:45:16 +0000
commit20b99a7070220a3ef191ca20a4b1155b0acc4e18 (patch)
treea945c2afefbbee68b6f91a10eba24a4b9d534e07
parent60dc637cf3dd8366467925b74c646a825eff53a8 (diff)
downloadchrome-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.mk3
-rw-r--r--driver/ln9310.c187
-rw-r--r--driver/ln9310.h133
-rw-r--r--include/config.h2
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 */