summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/samus_pd/board.c9
-rw-r--r--board/samus_pd/board.h18
-rw-r--r--chip/stm32/i2c-stm32f0.c24
-rw-r--r--chip/stm32/registers.h1
-rw-r--r--common/usb_pd_protocol.c46
-rw-r--r--include/system.h1
6 files changed, 74 insertions, 25 deletions
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c
index a62299d71c..f250dd34a6 100644
--- a/board/samus_pd/board.c
+++ b/board/samus_pd/board.c
@@ -50,21 +50,27 @@ void pch_evt(enum gpio_signal signal)
switch (ps) {
case POWER_S5:
if (gpio_get_level(GPIO_PCH_SLP_S5_L)) {
+ /* S5 -> S3 */
hook_notify(HOOK_CHIPSET_STARTUP);
ps = POWER_S3;
}
break;
case POWER_S3:
if (gpio_get_level(GPIO_PCH_SLP_S3_L)) {
+ /* S3 -> S0: disable deep sleep */
+ disable_sleep(SLEEP_MASK_AP_RUN);
hook_notify(HOOK_CHIPSET_RESUME);
ps = POWER_S0;
} else if (!gpio_get_level(GPIO_PCH_SLP_S5_L)) {
+ /* S3 -> S5 */
hook_notify(HOOK_CHIPSET_SHUTDOWN);
ps = POWER_S5;
}
break;
case POWER_S0:
if (!gpio_get_level(GPIO_PCH_SLP_S3_L)) {
+ /* S0 -> S3: enable deep sleep */
+ enable_sleep(SLEEP_MASK_AP_RUN);
hook_notify(HOOK_CHIPSET_SUSPEND);
ps = POWER_S3;
}
@@ -117,12 +123,15 @@ static void board_init(void)
/* Determine initial chipset state */
if (slp_s5 && slp_s3) {
+ disable_sleep(SLEEP_MASK_AP_RUN);
hook_notify(HOOK_CHIPSET_RESUME);
ps = POWER_S0;
} else if (slp_s5 && !slp_s3) {
+ enable_sleep(SLEEP_MASK_AP_RUN);
hook_notify(HOOK_CHIPSET_STARTUP);
ps = POWER_S3;
} else {
+ enable_sleep(SLEEP_MASK_AP_RUN);
hook_notify(HOOK_CHIPSET_SHUTDOWN);
ps = POWER_S5;
}
diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h
index 4cc58a56e4..a3364071b7 100644
--- a/board/samus_pd/board.h
+++ b/board/samus_pd/board.h
@@ -12,14 +12,21 @@
#define CPU_CLOCK 48000000
/* the UART console is on USART1 (PA9/PA10) */
-#undef CONFIG_UART_CONSOLE
+#undef CONFIG_UART_CONSOLE
#define CONFIG_UART_CONSOLE 1
/* Optional features */
+#define CONFIG_ADC
#define CONFIG_BOARD_PRE_INIT
+#define CONFIG_FORCE_CONSOLE_RESUME
+#define CONFIG_HW_CRC
+#define CONFIG_I2C
+#undef CONFIG_LID_SWITCH
+#define CONFIG_LOW_POWER_IDLE
#define CONFIG_STM_HWTIMER32
+#undef CONFIG_TASK_PROFILING
#define CONFIG_USB_POWER_DELIVERY
-#undef CONFIG_USB_PD_COMM_ENABLED
+#undef CONFIG_USB_PD_COMM_ENABLED
#define CONFIG_USB_PD_COMM_ENABLED 0
#define CONFIG_USB_PD_CUSTOM_VDM
#define CONFIG_USB_PD_DUAL_ROLE
@@ -27,14 +34,9 @@
#define CONFIG_USB_PD_INTERNAL_COMP
#define CONFIG_USB_PD_READ_INFO_ON_CONNECT
#define CONFIG_USBC_SS_MUX
-#define CONFIG_ADC
-#define CONFIG_HW_CRC
-#define CONFIG_I2C
#define CONFIG_USB_SWITCH_TSU6721
#define CONFIG_VBOOT_HASH
-#undef CONFIG_WATCHDOG_HELP
-#undef CONFIG_LID_SWITCH
-#undef CONFIG_TASK_PROFILING
+#undef CONFIG_WATCHDOG_HELP
/* I2C ports configuration */
#define I2C_PORT_MASTER 1
diff --git a/chip/stm32/i2c-stm32f0.c b/chip/stm32/i2c-stm32f0.c
index 5dc40fcebc..47393fc209 100644
--- a/chip/stm32/i2c-stm32f0.c
+++ b/chip/stm32/i2c-stm32f0.c
@@ -104,9 +104,21 @@ static void i2c_init_port(const struct i2c_port_t *p)
if (!(STM32_RCC_APB1ENR & (1 << (21 + port))))
STM32_RCC_APB1ENR |= 1 << (21 + port);
- /* Default clock to i2c port 0 is HSI (8MHz). Change to SYSCLK. */
- if (port == 0)
+ if (port == 0) {
+#if defined(CONFIG_HOSTCMD_I2C_SLAVE_ADDR) && \
+defined(CONFIG_LOW_POWER_IDLE) && \
+(I2C_PORT_EC == STM32_I2C1_PORT)
+ /*
+ * Use HSI (8MHz) for i2c clock. This allows smooth wakeup
+ * from STOP mode since HSI is only clock running immediately
+ * upon exit from STOP mode.
+ */
+ STM32_RCC_CFGR3 &= ~0x10;
+#else
+ /* Use SYSCLK for i2c clock. */
STM32_RCC_CFGR3 |= 0x10;
+#endif
+ }
/* Configure GPIOs */
gpio_config_module(MODULE_I2C, 1);
@@ -418,6 +430,14 @@ static void i2c_init(void)
#ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR
STM32_I2C_CR1(I2C_PORT_EC) |= STM32_I2C_CR1_RXIE | STM32_I2C_CR1_ERRIE
| STM32_I2C_CR1_ADDRIE | STM32_I2C_CR1_STOPIE;
+#if defined(CONFIG_LOW_POWER_IDLE) && (I2C_PORT_EC == STM32_I2C1_PORT)
+ /*
+ * If using low power idle and EC port is I2C1, then set I2C1 to wake
+ * from STOP mode on address match. Note, this only works on I2C1 and
+ * only if the clock to I2C1 is HSI 8MHz.
+ */
+ STM32_I2C_CR1(I2C_PORT_EC) |= STM32_I2C_CR1_WUPEN;
+#endif
STM32_I2C_OAR1(I2C_PORT_EC) = 0x8000 | CONFIG_HOSTCMD_I2C_SLAVE_ADDR;
task_enable_irq(IRQ_SLAVE);
#endif
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index 4b557cb8e9..a806c74afa 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -415,6 +415,7 @@ typedef volatile struct timer_ctlr timer_ctlr_t;
#define STM32_I2C_CR1_NACKIE (1 << 4)
#define STM32_I2C_CR1_STOPIE (1 << 5)
#define STM32_I2C_CR1_ERRIE (1 << 7)
+#define STM32_I2C_CR1_WUPEN (1 << 18)
#define STM32_I2C_CR2(n) REG32(stm32_i2c_reg(n, 0x04))
#define STM32_I2C_CR2_RD_WRN (1 << 10)
#define STM32_I2C_CR2_START (1 << 13)
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 161a851519..b49d66ac88 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -15,6 +15,7 @@
#include "host_command.h"
#include "registers.h"
#include "sha1.h"
+#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
@@ -283,9 +284,27 @@ static inline void set_state_timeout(int port,
pd[port].timeout_state = timeout_state;
}
+/* Return flag for pd state is connected */
+static int pd_is_connected(int port)
+{
+ if (pd[port].task_state == PD_STATE_DISABLED)
+ return 0;
+
+#ifdef CONFIG_USB_PD_DUAL_ROLE
+ /* Check if sink is connected */
+ if (pd[port].role == PD_ROLE_SINK)
+ return pd[port].task_state != PD_STATE_SNK_DISCONNECTED;
+#endif
+ /* Must be a source */
+ return pd[port].task_state != PD_STATE_SRC_DISCONNECTED;
+}
+
static inline void set_state(int port, enum pd_states next_state)
{
enum pd_states last_state = pd[port].task_state;
+#ifdef CONFIG_LOW_POWER_IDLE
+ int i;
+#endif
set_state_timeout(port, 0, 0);
pd[port].task_state = next_state;
@@ -298,6 +317,18 @@ static inline void set_state(int port, enum pd_states next_state)
}
#endif
+#ifdef CONFIG_LOW_POWER_IDLE
+ /* If any PD port is connected, then disable deep sleep */
+ for (i = 0; i < PD_PORT_COUNT; i++) {
+ if (pd_is_connected(i))
+ break;
+ }
+ if (i == PD_PORT_COUNT)
+ enable_sleep(SLEEP_MASK_USB_PD);
+ else
+ disable_sleep(SLEEP_MASK_USB_PD);
+#endif
+
/* Log state transition, except for toggling between sink and source */
if (last_state == next_state)
return;
@@ -640,21 +671,6 @@ static void handle_vdm_request(int port, int cnt, uint32_t *payload)
vid, payload[0] & 0xFFFF);
}
-/* Return flag for pd state is connected */
-static int pd_is_connected(int port)
-{
- if (pd[port].task_state == PD_STATE_DISABLED)
- return 0;
-
-#ifdef CONFIG_USB_PD_DUAL_ROLE
- /* Check if sink is connected */
- if (pd[port].role == PD_ROLE_SINK)
- return pd[port].task_state != PD_STATE_SNK_DISCONNECTED;
-#endif
- /* Must be a source */
- return pd[port].task_state != PD_STATE_SRC_DISCONNECTED;
-}
-
static void execute_hard_reset(int port)
{
pd[port].msg_id = 0;
diff --git a/include/system.h b/include/system.h
index b4c68bd3ce..6d38cae769 100644
--- a/include/system.h
+++ b/include/system.h
@@ -291,6 +291,7 @@ enum {
SLEEP_MASK_I2C = (1 << 2), /* I2C master communication on-going */
SLEEP_MASK_CHARGING = (1 << 3), /* Charging loop on-going */
SLEEP_MASK_USB_PWR = (1 << 4), /* USB power loop on-going */
+ SLEEP_MASK_USB_PD = (1 << 5), /* USB PD device connected */
SLEEP_MASK_FORCE_NO_DSLEEP = (1 << 15), /* Force disable. */