flash: spi_nor: automatically run device runtime PM
Automatically handle device runtime PM for all flash API calls. Asynchronously release the device after a small delay to minimise power state transitions under multiple sequential API calls (e.g. NVS). Signed-off-by: Jordan Yates <jordan@embeint.com>
This commit is contained in:
parent
6487a2a663
commit
986fd88416
3 changed files with 63 additions and 0 deletions
|
@ -196,6 +196,11 @@ Other Subsystems
|
|||
Flash map
|
||||
=========
|
||||
|
||||
* ``CONFIG_SPI_NOR_IDLE_IN_DPD`` has been removed from the :kconfig:option:`CONFIG_SPI_NOR`
|
||||
driver. An enhanced version of this functionality can be obtained by enabling
|
||||
:ref:`pm-device-runtime` on the device (Tunable with
|
||||
:kconfig:option:`CONFIG_SPI_NOR_ACTIVE_DWELL_MS`).
|
||||
|
||||
hawkBit
|
||||
=======
|
||||
|
||||
|
|
|
@ -78,4 +78,15 @@ config SPI_NOR_FLASH_LAYOUT_PAGE_SIZE
|
|||
(32768), the sector size (4096), or any non-zero multiple of the
|
||||
sector size.
|
||||
|
||||
config SPI_NOR_ACTIVE_DWELL_MS
|
||||
int "Dwell period (ms) after last use to stay in active mode"
|
||||
depends on PM_DEVICE_RUNTIME
|
||||
default 10
|
||||
help
|
||||
Flash accesses commonly occur in bursts, where entering and exiting DPD
|
||||
mode between each access adds significantly to the total operation time.
|
||||
This option controls how long to remain in active mode after each API
|
||||
call, eliminating the active->idle->active transition sequence if another
|
||||
transaction occurs before the dwell period expires.
|
||||
|
||||
endif # SPI_NOR
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys_clock.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/pm/device_runtime.h>
|
||||
|
||||
#include "spi_nor.h"
|
||||
#include "jesd216.h"
|
||||
|
@ -65,6 +66,12 @@ LOG_MODULE_REGISTER(spi_nor, CONFIG_FLASH_LOG_LEVEL);
|
|||
#define ANY_INST_HAS_WP_GPIOS ANY_INST_HAS_PROP(wp_gpios)
|
||||
#define ANY_INST_HAS_HOLD_GPIOS ANY_INST_HAS_PROP(hold_gpios)
|
||||
|
||||
#ifdef CONFIG_SPI_NOR_ACTIVE_DWELL_MS
|
||||
#define ACTIVE_DWELL_MS CONFIG_SPI_NOR_ACTIVE_DWELL_MS
|
||||
#else
|
||||
#define ACTIVE_DWELL_MS 0
|
||||
#endif
|
||||
|
||||
#define DEV_CFG(_dev_) ((const struct spi_nor_config * const) (_dev_)->config)
|
||||
|
||||
/* MXICY Related defines*/
|
||||
|
@ -762,11 +769,19 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ensure flash is powered before read */
|
||||
if (pm_device_runtime_get(dev) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
acquire_device(dev);
|
||||
|
||||
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
|
||||
|
||||
release_device(dev);
|
||||
|
||||
/* Release flash power requirement */
|
||||
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -779,6 +794,10 @@ static int flash_spi_nor_ex_op(const struct device *dev, uint16_t code,
|
|||
ARG_UNUSED(in);
|
||||
ARG_UNUSED(out);
|
||||
|
||||
if (pm_device_runtime_get(dev) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
acquire_device(dev);
|
||||
|
||||
switch (code) {
|
||||
|
@ -794,6 +813,7 @@ static int flash_spi_nor_ex_op(const struct device *dev, uint16_t code,
|
|||
}
|
||||
|
||||
release_device(dev);
|
||||
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
@ -811,6 +831,11 @@ static int spi_nor_write(const struct device *dev, off_t addr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ensure flash is powered before write */
|
||||
if (pm_device_runtime_get(dev) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
acquire_device(dev);
|
||||
ret = spi_nor_write_protection_set(dev, false);
|
||||
if (ret == 0) {
|
||||
|
@ -858,6 +883,9 @@ static int spi_nor_write(const struct device *dev, off_t addr,
|
|||
}
|
||||
|
||||
release_device(dev);
|
||||
|
||||
/* Release flash power requirement */
|
||||
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -881,6 +909,11 @@ static int spi_nor_erase(const struct device *dev, off_t addr, size_t size)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ensure flash is powered before erase */
|
||||
if (pm_device_runtime_get(dev) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
acquire_device(dev);
|
||||
ret = spi_nor_write_protection_set(dev, false);
|
||||
|
||||
|
@ -936,6 +969,8 @@ static int spi_nor_erase(const struct device *dev, off_t addr, size_t size)
|
|||
|
||||
release_device(dev);
|
||||
|
||||
/* Release flash power requirement */
|
||||
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -977,12 +1012,18 @@ static int spi_nor_write_protection_set(const struct device *dev,
|
|||
static int spi_nor_sfdp_read(const struct device *dev, off_t addr,
|
||||
void *dest, size_t size)
|
||||
{
|
||||
if (pm_device_runtime_get(dev) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
acquire_device(dev);
|
||||
|
||||
int ret = read_sfdp(dev, addr, dest, size);
|
||||
|
||||
release_device(dev);
|
||||
|
||||
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -995,12 +1036,18 @@ static int spi_nor_read_jedec_id(const struct device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pm_device_runtime_get(dev) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
acquire_device(dev);
|
||||
|
||||
int ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDID, id, SPI_NOR_MAX_ID_LEN);
|
||||
|
||||
release_device(dev);
|
||||
|
||||
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue