summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--driver/tcpm/fusb302.c67
-rw-r--r--driver/tcpm/fusb302.h2
2 files changed, 66 insertions, 3 deletions
diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c
index 66c131fb37..bbb6015e56 100644
--- a/driver/tcpm/fusb302.c
+++ b/driver/tcpm/fusb302.c
@@ -434,7 +434,6 @@ static int fusb302_tcpm_init(int port)
tcpm_set_polarity(port, 0);
tcpm_set_vconn(port, 0);
- /* Turn on the power! */
/* TODO: Reduce power consumption */
tcpc_write(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_ALL);
@@ -1008,9 +1007,73 @@ void tcpm_set_bist_test_data(int port)
}
#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+static int fusb302_set_toggle_mode(int port, int mode)
+{
+ int reg, rv;
+
+ rv = i2c_read8(tcpc_config[port].i2c_info.port,
+ tcpc_config[port].i2c_info.addr_flags,
+ TCPC_REG_CONTROL2, &reg);
+ if (rv)
+ return rv;
+
+ reg &= ~TCPC_REG_CONTROL2_MODE_MASK;
+ reg |= mode << TCPC_REG_CONTROL2_MODE_POS;
+ return i2c_write8(tcpc_config[port].i2c_info.port,
+ tcpc_config[port].i2c_info.addr_flags,
+ TCPC_REG_CONTROL2, reg);
+}
+
static int fusb302_tcpm_enter_low_power_mode(int port)
{
- return tcpc_write(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_LOW);
+ int reg, rv, mode = TCPC_REG_CONTROL2_MODE_DRP;
+
+ /**
+ * vendor's suggested LPM flow:
+ * - enable low power mode and set up other things
+ * - sleep 250 us
+ * - start toggling
+ */
+ rv = i2c_write8(tcpc_config[port].i2c_info.port,
+ tcpc_config[port].i2c_info.addr_flags,
+ TCPC_REG_POWER, TCPC_REG_POWER_PWR_LOW);
+ if (rv)
+ return rv;
+
+ switch (pd_get_dual_role(port)) {
+ case PD_DRP_TOGGLE_ON:
+ mode = TCPC_REG_CONTROL2_MODE_DRP;
+ break;
+ case PD_DRP_TOGGLE_OFF:
+ mode = TCPC_REG_CONTROL2_MODE_UFP;
+ break;
+ case PD_DRP_FREEZE:
+ mode = pd_get_role(port) == PD_ROLE_SINK ?
+ TCPC_REG_CONTROL2_MODE_UFP :
+ TCPC_REG_CONTROL2_MODE_DFP;
+ break;
+ case PD_DRP_FORCE_SINK:
+ mode = TCPC_REG_CONTROL2_MODE_UFP;
+ break;
+ case PD_DRP_FORCE_SOURCE:
+ mode = TCPC_REG_CONTROL2_MODE_DFP;
+ break;
+ }
+ rv = fusb302_set_toggle_mode(port, mode);
+ if (rv)
+ return rv;
+
+ usleep(250);
+
+ rv = i2c_read8(tcpc_config[port].i2c_info.port,
+ tcpc_config[port].i2c_info.addr_flags,
+ TCPC_REG_CONTROL2, &reg);
+ if (rv)
+ return rv;
+ reg |= TCPC_REG_CONTROL2_TOGGLE;
+ return i2c_write8(tcpc_config[port].i2c_info.port,
+ tcpc_config[port].i2c_info.addr_flags,
+ TCPC_REG_CONTROL2, reg);
}
#endif
diff --git a/driver/tcpm/fusb302.h b/driver/tcpm/fusb302.h
index ec418407f7..b4a8599ea8 100644
--- a/driver/tcpm/fusb302.h
+++ b/driver/tcpm/fusb302.h
@@ -76,7 +76,7 @@
#define TCPC_REG_CONTROL2 0x08
/* two-bit field, valid values below */
-#define TCPC_REG_CONTROL2_MODE (1<<1)
+#define TCPC_REG_CONTROL2_MODE_MASK (0x3<<TCPC_REG_CONTROL2_MODE_POS)
#define TCPC_REG_CONTROL2_MODE_DFP (0x3)
#define TCPC_REG_CONTROL2_MODE_UFP (0x2)
#define TCPC_REG_CONTROL2_MODE_DRP (0x1)