diff --git a/arch/arm/src/stm32f7/stm32_i2c.c b/arch/arm/src/stm32f7/stm32_i2c.c index 26c79131fb4..d7b599084d3 100644 --- a/arch/arm/src/stm32f7/stm32_i2c.c +++ b/arch/arm/src/stm32f7/stm32_i2c.c @@ -2857,7 +2857,7 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s * dev) #ifdef CONFIG_PM /* Unregister power management callbacks */ - pm_unregister(&priv->pm_cb); + pm_unregister(&((struct stm32_i2c_inst_s *)dev)->priv->pm_cb); #endif /* Disable power and other HW resource (GPIO's) */ diff --git a/arch/arm/src/stm32l4/stm32l4_1wire.c b/arch/arm/src/stm32l4/stm32l4_1wire.c index b5969982fa7..35b2c0c2d76 100644 --- a/arch/arm/src/stm32l4/stm32l4_1wire.c +++ b/arch/arm/src/stm32l4/stm32l4_1wire.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ #include #include #include +#include #include #include @@ -127,6 +129,9 @@ struct stm32_1wire_priv_s uint8_t *byte; /* Current byte */ uint8_t bit; /* Current bit */ volatile int result; /* Exchange result */ +#ifdef CONFIG_PM + struct pm_callback_s pm_cb; /* PM callbacks */ +#endif }; /* 1-Wire device, Instance */ @@ -168,6 +173,10 @@ static int stm32_1wire_read(FAR struct onewire_dev_s *dev, uint8_t *buffer, static int stm32_1wire_exchange(FAR struct onewire_dev_s *dev, bool reset, const uint8_t *txbuffer, int txbuflen, uint8_t *rxbuffer, int rxbuflen); +#ifdef CONFIG_PM +static int stm32_1wire_pm_prepare(FAR struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif /**************************************************************************** * Private Data @@ -189,7 +198,10 @@ static struct stm32_1wire_priv_s stm32_1wire1_priv = { .config = &stm32_1wire1_config, .refs = 0, - .msgs = NULL + .msgs = NULL, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_1wire_pm_prepare, +#endif }; #endif @@ -208,7 +220,10 @@ static struct stm32_1wire_priv_s stm32_1wire2_priv = { .config = &stm32_1wire2_config, .refs = 0, - .msgs = NULL + .msgs = NULL, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_1wire_pm_prepare, +#endif }; #endif @@ -227,7 +242,10 @@ static struct stm32_1wire_priv_s stm32_1wire3_priv = { .config = &stm32_1wire3_config, .refs = 0, - .msgs = NULL + .msgs = NULL, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_1wire_pm_prepare, +#endif }; #endif @@ -246,7 +264,10 @@ static struct stm32_1wire_priv_s stm32_1wire4_priv = { .config = &stm32_1wire4_config, .refs = 0, - .msgs = NULL + .msgs = NULL, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_1wire_pm_prepare, +#endif }; #endif @@ -265,7 +286,10 @@ static struct stm32_1wire_priv_s stm32_1wire5_priv = { .config = &stm32_1wire5_config, .refs = 0, - .msgs = NULL + .msgs = NULL, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32_1wire_pm_prepare, +#endif }; #endif @@ -1028,6 +1052,76 @@ static int stm32_1wire_exchange(FAR struct onewire_dev_s *dev, bool reset, return result; } +/************************************************************************************ + * Name: stm32_1wire_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a + * warning that the system is about to enter into a new power state. The + * driver should begin whatever operations that may be required to enter + * power state. The driver may abort the state change mode by returning + * a non-zero value from the callback function. + * + * Input Parameters: + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state + * data at the end of the structure. + * domain - Identifies the activity domain of the state change + * pmstate - Identifies the new PM state + * + * Returned Value: + * 0 (OK) means the event was successfully processed and that the driver + * is prepared for the PM state change. Non-zero means that the driver + * is not prepared to perform the tasks needed achieve this power setting + * and will cause the state change to be aborted. NOTE: The prepare + * method will also be recalled when reverting from lower back to higher + * power consumption modes (say because another driver refused a lower + * power state change). Drivers are not permitted to return non-zero + * values when reverting back to higher power consumption modes! + * + ************************************************************************************/ + +#ifdef CONFIG_PM +static int stm32_1wire_pm_prepare(FAR struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + struct stm32_1wire_priv_s *priv = + (struct stm32_1wire_priv_s *)((char *)cb - + offsetof(struct stm32_1wire_priv_s, pm_cb)); + int sval; + + /* Logic to prepare for a reduced power state goes here. */ + + switch (pmstate) + { + case PM_NORMAL: + case PM_IDLE: + break; + + case PM_STANDBY: + case PM_SLEEP: + /* Check if exclusive lock for 1-Wire bus is held. */ + + if (nxsem_getvalue(&priv->sem_excl, &sval) < 0) + { + DEBUGASSERT(false); + return -EINVAL; + } + + if (sval <= 0) + { + /* Exclusive lock is held, do not allow entry to deeper PM states. */ + + return -EBUSY; + } + + break; + } + + return OK; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -1053,7 +1147,10 @@ FAR struct onewire_dev_s *stm32l4_1wireinitialize(int port) { struct stm32_1wire_priv_s *priv = NULL; /* Private data of device with multiple instances */ struct stm32_1wire_inst_s *inst = NULL; /* Device, single instance */ - int irqs; + irqstate_t irqs; +#ifdef CONFIG_PM + int ret; +#endif /* Get 1-Wire private structure */ @@ -1116,6 +1213,14 @@ FAR struct onewire_dev_s *stm32l4_1wireinitialize(int port) { stm32_1wire_sem_init(priv); stm32_1wire_init(priv); + +#ifdef CONFIG_PM + /* Register to receive power management callbacks */ + + ret = pm_register(&priv->pm_cb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif } leave_critical_section(irqs); @@ -1140,7 +1245,7 @@ FAR struct onewire_dev_s *stm32l4_1wireinitialize(int port) int stm32l4_1wireuninitialize(FAR struct onewire_dev_s *dev) { struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv; - int irqs; + irqstate_t irqs; DEBUGASSERT(priv != NULL); @@ -1162,6 +1267,12 @@ int stm32l4_1wireuninitialize(FAR struct onewire_dev_s *dev) leave_critical_section(irqs); +#ifdef CONFIG_PM + /* Unregister power management callbacks */ + + pm_unregister(&priv->pm_cb); +#endif + /* Disable power and other HW resource (GPIO's) */ stm32_1wire_deinit(priv); diff --git a/arch/arm/src/stm32l4/stm32l4_i2c.c b/arch/arm/src/stm32l4/stm32l4_i2c.c index 6fd44d6da30..cd334ef6487 100644 --- a/arch/arm/src/stm32l4/stm32l4_i2c.c +++ b/arch/arm/src/stm32l4/stm32l4_i2c.c @@ -6,7 +6,7 @@ * * Copyright (C) 2011 Uros Platise. All rights reserved. * Author: Uros Platise - * Copyright (C) 2011-2013, 2016-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2013, 2016-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * Author: John Wharington * Author: Sebastien Lorquet @@ -258,6 +258,7 @@ #include #include #include +#include #include #include #include @@ -267,6 +268,7 @@ #include #include #include +#include #include #include @@ -445,6 +447,10 @@ struct stm32l4_i2c_priv_s #endif uint32_t status; /* End of transfer SR2|SR1 status */ + +#ifdef CONFIG_PM + struct pm_callback_s pm_cb; /* PM callbacks */ +#endif }; /* I2C Device, Instance */ @@ -504,6 +510,10 @@ static int stm32l4_i2c_transfer(FAR struct i2c_master_s *dev, #ifdef CONFIG_I2C_RESET static int stm32l4_i2c_reset(FAR struct i2c_master_s *dev); #endif +#ifdef CONFIG_PM +static int stm32l4_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif /************************************************************************************ * Private Data @@ -534,7 +544,10 @@ static struct stm32l4_i2c_priv_s stm32l4_i2c1_priv = .frequency = 0, .dcnt = 0, .flags = 0, - .status = 0 + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32l4_i2c_pm_prepare, +#endif }; #endif @@ -563,7 +576,10 @@ static struct stm32l4_i2c_priv_s stm32l4_i2c2_priv = .frequency = 0, .dcnt = 0, .flags = 0, - .status = 0 + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32l4_i2c_pm_prepare, +#endif }; #endif @@ -592,7 +608,10 @@ static struct stm32l4_i2c_priv_s stm32l4_i2c3_priv = .frequency = 0, .dcnt = 0, .flags = 0, - .status = 0 + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32l4_i2c_pm_prepare, +#endif }; #endif @@ -621,7 +640,10 @@ static struct stm32l4_i2c_priv_s stm32l4_i2c4_priv = .frequency = 0, .dcnt = 0, .flags = 0, - .status = 0 + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32l4_i2c_pm_prepare, +#endif }; #endif @@ -2790,6 +2812,76 @@ out: } #endif /* CONFIG_I2C_RESET */ +/************************************************************************************ + * Name: stm32l4_i2c_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a + * warning that the system is about to enter into a new power state. The + * driver should begin whatever operations that may be required to enter + * power state. The driver may abort the state change mode by returning + * a non-zero value from the callback function. + * + * Input Parameters: + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state + * data at the end of the structure. + * domain - Identifies the activity domain of the state change + * pmstate - Identifies the new PM state + * + * Returned Value: + * 0 (OK) means the event was successfully processed and that the driver + * is prepared for the PM state change. Non-zero means that the driver + * is not prepared to perform the tasks needed achieve this power setting + * and will cause the state change to be aborted. NOTE: The prepare + * method will also be recalled when reverting from lower back to higher + * power consumption modes (say because another driver refused a lower + * power state change). Drivers are not permitted to return non-zero + * values when reverting back to higher power consumption modes! + * + ************************************************************************************/ + +#ifdef CONFIG_PM +static int stm32l4_i2c_pm_prepare(FAR struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + struct stm32l4_i2c_priv_s *priv = + (struct stm32l4_i2c_priv_s *)((char *)cb - + offsetof(struct stm32l4_i2c_priv_s, pm_cb)); + int sval; + + /* Logic to prepare for a reduced power state goes here. */ + + switch (pmstate) + { + case PM_NORMAL: + case PM_IDLE: + break; + + case PM_STANDBY: + case PM_SLEEP: + /* Check if exclusive lock for I2C bus is held. */ + + if (nxsem_getvalue(&priv->sem_excl, &sval) < 0) + { + DEBUGASSERT(false); + return -EINVAL; + } + + if (sval <= 0) + { + /* Exclusive lock is held, do not allow entry to deeper PM states. */ + + return -EBUSY; + } + + break; + } + + return OK; +} +#endif + /************************************************************************************ * Public Functions ************************************************************************************/ @@ -2806,7 +2898,10 @@ FAR struct i2c_master_s *stm32l4_i2cbus_initialize(int port) { struct stm32l4_i2c_priv_s * priv = NULL; /* private data of device with multiple instances */ struct stm32l4_i2c_inst_s * inst = NULL; /* device, single instance */ - int irqs; + irqstate_t irqs; +#ifdef CONFIG_PM + int ret; +#endif #if STM32L4_PCLK1_FREQUENCY != 80000000 # warning STM32_I2C_INIT: Peripheral clock is PCLK and it must be 80mHz or the speed/timing calculations need to be redone. @@ -2863,6 +2958,14 @@ FAR struct i2c_master_s *stm32l4_i2cbus_initialize(int port) { stm32l4_i2c_sem_init((struct i2c_master_s *)inst); stm32l4_i2c_init(priv); + +#ifdef CONFIG_PM + /* Register to receive power management callbacks */ + + ret = pm_register(&priv->pm_cb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif } leave_critical_section(irqs); @@ -2879,7 +2982,7 @@ FAR struct i2c_master_s *stm32l4_i2cbus_initialize(int port) int stm32l4_i2cbus_uninitialize(FAR struct i2c_master_s * dev) { - int irqs; + irqstate_t irqs; ASSERT(dev); @@ -2901,6 +3004,12 @@ int stm32l4_i2cbus_uninitialize(FAR struct i2c_master_s * dev) leave_critical_section(irqs); +#ifdef CONFIG_PM + /* Unregister power management callbacks */ + + pm_unregister(&((struct stm32l4_i2c_inst_s *)dev)->priv->pm_cb); +#endif + /* Disable power and other HW resource (GPIO's) */ stm32l4_i2c_deinit(((struct stm32l4_i2c_inst_s *)dev)->priv); diff --git a/arch/arm/src/stm32l4/stm32l4_spi.c b/arch/arm/src/stm32l4/stm32l4_spi.c index b98bd793e29..fa3fc299e5d 100644 --- a/arch/arm/src/stm32l4/stm32l4_spi.c +++ b/arch/arm/src/stm32l4/stm32l4_spi.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,7 @@ #include #include #include +#include #include "up_internal.h" #include "up_arch.h" @@ -166,6 +168,9 @@ struct stm32l4_spidev_s uint32_t actual; /* Actual clock frequency */ uint8_t nbits; /* Width of word in bits (4 through 16) */ uint8_t mode; /* Mode 0,1,2,3 */ +#ifdef CONFIG_PM + struct pm_callback_s pm_cb; /* PM callbacks */ +#endif }; /************************************************************************************ @@ -222,6 +227,13 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *rxbuffer, static void spi_bus_initialize(FAR struct stm32l4_spidev_s *priv); +/* PM interface */ + +#ifdef CONFIG_PM +static int spi_pm_prepare(FAR struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + /************************************************************************************ * Private Data ************************************************************************************/ @@ -268,6 +280,9 @@ static struct stm32l4_spidev_s g_spi1dev = .rxch = DMACHAN_SPI1_RX, .txch = DMACHAN_SPI1_TX, #endif +#ifdef CONFIG_PM + .pm_cb.prepare = spi_pm_prepare, +#endif }; #endif @@ -312,6 +327,9 @@ static struct stm32l4_spidev_s g_spi2dev = .rxch = DMACHAN_SPI2_RX, .txch = DMACHAN_SPI2_TX, #endif +#ifdef CONFIG_PM + .pm_cb.prepare = spi_pm_prepare, +#endif }; #endif @@ -356,6 +374,9 @@ static struct stm32l4_spidev_s g_spi3dev = .rxch = DMACHAN_SPI3_RX, .txch = DMACHAN_SPI3_TX, #endif +#ifdef CONFIG_PM + .pm_cb.prepare = spi_pm_prepare, +#endif }; #endif @@ -1475,6 +1496,76 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *rxbuffer, size_t } #endif +/************************************************************************************ + * Name: spi_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a + * warning that the system is about to enter into a new power state. The + * driver should begin whatever operations that may be required to enter + * power state. The driver may abort the state change mode by returning + * a non-zero value from the callback function. + * + * Input Parameters: + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state + * data at the end of the structure. + * domain - Identifies the activity domain of the state change + * pmstate - Identifies the new PM state + * + * Returned Value: + * 0 (OK) means the event was successfully processed and that the driver + * is prepared for the PM state change. Non-zero means that the driver + * is not prepared to perform the tasks needed achieve this power setting + * and will cause the state change to be aborted. NOTE: The prepare + * method will also be recalled when reverting from lower back to higher + * power consumption modes (say because another driver refused a lower + * power state change). Drivers are not permitted to return non-zero + * values when reverting back to higher power consumption modes! + * + ************************************************************************************/ + +#ifdef CONFIG_PM +static int spi_pm_prepare(FAR struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + struct stm32l4_spidev_s *priv = + (struct stm32l4_spidev_s *)((char *)cb - + offsetof(struct stm32l4_spidev_s, pm_cb)); + int sval; + + /* Logic to prepare for a reduced power state goes here. */ + + switch (pmstate) + { + case PM_NORMAL: + case PM_IDLE: + break; + + case PM_STANDBY: + case PM_SLEEP: + /* Check if exclusive lock for SPI bus is held. */ + + if (nxsem_getvalue(&priv->exclsem, &sval) < 0) + { + DEBUGASSERT(false); + return -EINVAL; + } + + if (sval <= 0) + { + /* Exclusive lock is held, do not allow entry to deeper PM states. */ + + return -EBUSY; + } + + break; + } + + return OK; +} +#endif + /************************************************************************************ * Name: spi_bus_initialize * @@ -1493,6 +1584,9 @@ static void spi_bus_initialize(FAR struct stm32l4_spidev_s *priv) { uint16_t setbits; uint16_t clrbits; +#ifdef CONFIG_PM + int ret; +#endif /* Configure CR1 and CR2. Default configuration: * Mode 0: CR1.CPHA=0 and CR1.CPOL=0 @@ -1559,6 +1653,14 @@ static void spi_bus_initialize(FAR struct stm32l4_spidev_s *priv) /* Enable spi */ spi_modifycr(STM32L4_SPI_CR1_OFFSET, priv, SPI_CR1_SPE, 0); + +#ifdef CONFIG_PM + /* Register to receive power management callbacks */ + + ret = pm_register(&priv->pm_cb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif } /************************************************************************************