Skip to content

Commit 529a501

Browse files
committed
drivers: spi: stm32: Disable/enable SPI on LPM enter/exit
Add pm_control function to disable/enable SPI on LPM enter/exit. Signed-off-by: Yong Cong Sin <[email protected]>
1 parent 1966b7f commit 529a501

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

drivers/spi/spi_ll_stm32.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,10 @@ static int spi_stm32_init(const struct device *dev)
839839
return err;
840840
}
841841

842+
#ifdef CONFIG_PM_DEVICE
843+
data->pm_state = PM_DEVICE_STATE_ACTIVE;
844+
#endif
845+
842846
#ifdef CONFIG_SPI_STM32_INTERRUPT
843847
cfg->irq_config(dev);
844848
#endif
@@ -861,6 +865,76 @@ static int spi_stm32_init(const struct device *dev)
861865
return 0;
862866
}
863867

868+
#ifdef CONFIG_PM_DEVICE
869+
static int spi_stm32_set_power_state(const struct device *dev,
870+
uint32_t new_state)
871+
{
872+
const struct spi_stm32_config *cfg = DEV_CFG(dev);
873+
struct spi_stm32_data *data = DEV_DATA(dev);
874+
SPI_TypeDef *spi = cfg->spi;
875+
876+
/* setting a low power mode */
877+
if (new_state != PM_DEVICE_STATE_ACTIVE) {
878+
#ifdef SPI_SR_FTLVL
879+
/* 1. Wait until FTLVL[1:0] = 00 (no more data to transmit) */
880+
while (LL_SPI_GetTxFIFOLevel(spi) > 0) {
881+
}
882+
#endif
883+
/* 2. Wait until BSY=0 (the last data frame is processed) */
884+
while (ll_func_spi_is_busy(spi)) {
885+
/* NOP */
886+
}
887+
/* 3. Disable the SPI (SPE=0) */
888+
LL_SPI_Disable(spi);
889+
#ifdef SPI_SR_FRLVL
890+
/* 4. Read data until FRLVL[1:0] = 00 (read all the received data)
891+
* We wait until all data is read */
892+
while (LL_SPI_GetRxFIFOLevel(spi) > 0) {
893+
}
894+
#endif
895+
} else if (new_state == PM_DEVICE_STATE_ACTIVE) {
896+
LL_SPI_Enable(spi);
897+
}
898+
data->pm_state = new_state;
899+
/* UartInstance returning to active mode has nothing special to do */
900+
return 0;
901+
}
902+
903+
/**
904+
* @brief disable the UART channel
905+
*
906+
* This routine is called to put the device in low power mode.
907+
*
908+
* @param dev UART device struct
909+
*
910+
* @return 0
911+
*/
912+
static int spi_stm32_pm_control(const struct device *dev,
913+
uint32_t ctrl_command,
914+
uint32_t *state, pm_device_cb cb,
915+
void *arg)
916+
{
917+
struct spi_stm32_data *data = DEV_DATA(dev);
918+
919+
if (ctrl_command == PM_DEVICE_STATE_SET) {
920+
uint32_t new_state = *state;
921+
922+
if (new_state != data->pm_state) {
923+
spi_stm32_set_power_state(dev, new_state);
924+
}
925+
} else {
926+
__ASSERT_NO_MSG(ctrl_command == PM_DEVICE_STATE_GET);
927+
*state = data->pm_state;
928+
}
929+
930+
if (cb) {
931+
cb(dev, 0, state, arg);
932+
}
933+
934+
return 0;
935+
}
936+
#endif /* CONFIG_PM_DEVICE */
937+
864938
#ifdef CONFIG_SPI_STM32_INTERRUPT
865939
#define STM32_SPI_IRQ_HANDLER_DECL(id) \
866940
static void spi_stm32_irq_config_func_##id(const struct device *dev)
@@ -955,7 +1029,7 @@ static struct spi_stm32_data spi_stm32_dev_data_##id = { \
9551029
SPI_DMA_STATUS_SEM(id) \
9561030
}; \
9571031
\
958-
DEVICE_DT_INST_DEFINE(id, &spi_stm32_init, NULL, \
1032+
DEVICE_DT_INST_DEFINE(id, &spi_stm32_init, &spi_stm32_pm_control, \
9591033
&spi_stm32_dev_data_##id, &spi_stm32_cfg_##id, \
9601034
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
9611035
&api_funcs); \

drivers/spi/spi_ll_stm32.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ struct spi_stm32_data {
5252
struct stream dma_rx;
5353
struct stream dma_tx;
5454
#endif
55+
#ifdef CONFIG_PM_DEVICE
56+
uint32_t pm_state;
57+
#endif
5558
};
5659

5760
static inline uint32_t ll_func_tx_is_empty(SPI_TypeDef *spi)

0 commit comments

Comments
 (0)