1414#include <zephyr/device.h>
1515#include <zephyr/drivers/uart.h>
1616#include <zephyr/drivers/clock_control.h>
17+ #include <zephyr/pm/policy.h>
1718#include <zephyr/irq.h>
19+ #include <zephyr/pm/device.h>
1820#include <fsl_usart.h>
1921#include <soc.h>
2022#include <fsl_device_registers.h>
@@ -86,8 +88,33 @@ struct mcux_flexcomm_data {
8688#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
8789 struct uart_config uart_config ;
8890#endif
91+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
92+ bool pm_policy_state_lock ;
93+ #endif
8994};
9095
96+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
97+ static void mcux_flexcomm_pm_policy_state_lock_get (const struct device * dev )
98+ {
99+ struct mcux_flexcomm_data * data = dev -> data ;
100+
101+ if (!data -> pm_policy_state_lock ) {
102+ data -> pm_policy_state_lock = true;
103+ pm_policy_device_power_lock_get (dev );
104+ }
105+ }
106+
107+ static void mcux_flexcomm_pm_policy_state_lock_put (const struct device * dev )
108+ {
109+ struct mcux_flexcomm_data * data = dev -> data ;
110+
111+ if (data -> pm_policy_state_lock ) {
112+ data -> pm_policy_state_lock = false;
113+ pm_policy_device_power_lock_put (dev );
114+ }
115+ }
116+ #endif
117+
91118static int mcux_flexcomm_poll_in (const struct device * dev , unsigned char * c )
92119{
93120 const struct mcux_flexcomm_config * config = dev -> config ;
@@ -179,6 +206,14 @@ static void mcux_flexcomm_irq_tx_enable(const struct device *dev)
179206 const struct mcux_flexcomm_config * config = dev -> config ;
180207 uint32_t mask = kUSART_TxLevelInterruptEnable ;
181208
209+ /* Indicates that this device started a transaction that should
210+ * not be interrupted by putting the SoC in states that would
211+ * interfere with this transfer.
212+ */
213+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
214+ mcux_flexcomm_pm_policy_state_lock_get (dev );
215+ #endif
216+
182217 USART_EnableInterrupts (config -> base , mask );
183218}
184219
@@ -187,6 +222,10 @@ static void mcux_flexcomm_irq_tx_disable(const struct device *dev)
187222 const struct mcux_flexcomm_config * config = dev -> config ;
188223 uint32_t mask = kUSART_TxLevelInterruptEnable ;
189224
225+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
226+ mcux_flexcomm_pm_policy_state_lock_put (dev );
227+ #endif
228+
190229 USART_DisableInterrupts (config -> base , mask );
191230}
192231
@@ -467,11 +506,19 @@ static int mcux_flexcomm_uart_tx(const struct device *dev, const uint8_t *buf,
467506 /* Enable TX DMA requests */
468507 USART_EnableTxDMA (config -> base , true);
469508
509+ /* Do not allow the system to suspend until the transmission has completed */
510+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
511+ mcux_flexcomm_pm_policy_state_lock_get (dev );
512+ #endif
513+
470514 /* Trigger the DMA to start transfer */
471515 ret = dma_start (config -> tx_dma .dev , config -> tx_dma .channel );
472516 if (ret ) {
473517 irq_unlock (key );
474- return ret ;
518+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
519+ mcux_flexcomm_pm_policy_state_lock_put (dev );
520+ #endif
521+ return ret ;
475522 }
476523
477524 /* Schedule a TX abort for @param timeout */
@@ -993,15 +1040,18 @@ static void mcux_flexcomm_isr(const struct device *dev)
9931040 data -> tx_data .xfer_buf = NULL ;
9941041
9951042 async_user_callback (dev , & tx_done_event );
1043+
1044+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
1045+ mcux_flexcomm_pm_policy_state_lock_put (dev );
1046+ #endif
9961047 }
9971048
9981049 }
9991050#endif /* CONFIG_UART_ASYNC_API */
10001051}
10011052#endif /* CONFIG_UART_MCUX_FLEXCOMM_ISR_SUPPORT */
10021053
1003-
1004- static int mcux_flexcomm_init (const struct device * dev )
1054+ static int mcux_flexcomm_init_common (const struct device * dev )
10051055{
10061056 const struct mcux_flexcomm_config * config = dev -> config ;
10071057#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
@@ -1067,6 +1117,42 @@ static int mcux_flexcomm_init(const struct device *dev)
10671117 return 0 ;
10681118}
10691119
1120+ static uint32_t usart_intenset ;
1121+ static int mcux_flexcomm_pm_action (const struct device * dev , enum pm_device_action action )
1122+ {
1123+ const struct mcux_flexcomm_config * config = dev -> config ;
1124+
1125+ usart_intenset = USART_GetEnabledInterrupts (config -> base );
1126+
1127+ switch (action ) {
1128+ case PM_DEVICE_ACTION_RESUME :
1129+ break ;
1130+ case PM_DEVICE_ACTION_SUSPEND :
1131+ break ;
1132+ case PM_DEVICE_ACTION_TURN_OFF :
1133+ break ;
1134+ case PM_DEVICE_ACTION_TURN_ON :
1135+ int ret = mcux_flexcomm_init_common (dev );
1136+
1137+ if (ret ) {
1138+ return ret ;
1139+ }
1140+ USART_EnableInterrupts (config -> base , usart_intenset );
1141+ break ;
1142+ default :
1143+ return - ENOTSUP ;
1144+ }
1145+ return 0 ;
1146+ }
1147+
1148+ static int mcux_flexcomm_init (const struct device * dev )
1149+ {
1150+ /* Rest of the init is done from the PM_DEVICE_TURN_ON action
1151+ * which is invoked by pm_device_driver_init().
1152+ */
1153+ return pm_device_driver_init (dev , mcux_flexcomm_pm_action );
1154+ }
1155+
10701156static DEVICE_API (uart , mcux_flexcomm_driver_api ) = {
10711157 .poll_in = mcux_flexcomm_poll_in ,
10721158 .poll_out = mcux_flexcomm_poll_out ,
@@ -1202,9 +1288,11 @@ static const struct mcux_flexcomm_config mcux_flexcomm_##n##_config = { \
12021288 \
12031289 static const struct mcux_flexcomm_config mcux_flexcomm_##n##_config; \
12041290 \
1291+ PM_DEVICE_DT_INST_DEFINE(n, mcux_flexcomm_pm_action); \
1292+ \
12051293 DEVICE_DT_INST_DEFINE(n, \
1206- mcux_flexcomm_init, \
1207- NULL, \
1294+ & mcux_flexcomm_init, \
1295+ PM_DEVICE_DT_INST_GET(n), \
12081296 &mcux_flexcomm_##n##_data, \
12091297 &mcux_flexcomm_##n##_config, \
12101298 PRE_KERNEL_1, \
0 commit comments