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
|
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
|
hawkBit
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
@ -78,4 +78,15 @@ config SPI_NOR_FLASH_LAYOUT_PAGE_SIZE
|
||||||
(32768), the sector size (4096), or any non-zero multiple of the
|
(32768), the sector size (4096), or any non-zero multiple of the
|
||||||
sector size.
|
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
|
endif # SPI_NOR
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
#include <zephyr/sys_clock.h>
|
#include <zephyr/sys_clock.h>
|
||||||
#include <zephyr/pm/device.h>
|
#include <zephyr/pm/device.h>
|
||||||
|
#include <zephyr/pm/device_runtime.h>
|
||||||
|
|
||||||
#include "spi_nor.h"
|
#include "spi_nor.h"
|
||||||
#include "jesd216.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_WP_GPIOS ANY_INST_HAS_PROP(wp_gpios)
|
||||||
#define ANY_INST_HAS_HOLD_GPIOS ANY_INST_HAS_PROP(hold_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)
|
#define DEV_CFG(_dev_) ((const struct spi_nor_config * const) (_dev_)->config)
|
||||||
|
|
||||||
/* MXICY Related defines*/
|
/* MXICY Related defines*/
|
||||||
|
@ -762,11 +769,19 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure flash is powered before read */
|
||||||
|
if (pm_device_runtime_get(dev) < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
acquire_device(dev);
|
acquire_device(dev);
|
||||||
|
|
||||||
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
|
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
|
||||||
|
|
||||||
release_device(dev);
|
release_device(dev);
|
||||||
|
|
||||||
|
/* Release flash power requirement */
|
||||||
|
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||||
return ret;
|
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(in);
|
||||||
ARG_UNUSED(out);
|
ARG_UNUSED(out);
|
||||||
|
|
||||||
|
if (pm_device_runtime_get(dev) < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
acquire_device(dev);
|
acquire_device(dev);
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
@ -794,6 +813,7 @@ static int flash_spi_nor_ex_op(const struct device *dev, uint16_t code,
|
||||||
}
|
}
|
||||||
|
|
||||||
release_device(dev);
|
release_device(dev);
|
||||||
|
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -811,6 +831,11 @@ static int spi_nor_write(const struct device *dev, off_t addr,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure flash is powered before write */
|
||||||
|
if (pm_device_runtime_get(dev) < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
acquire_device(dev);
|
acquire_device(dev);
|
||||||
ret = spi_nor_write_protection_set(dev, false);
|
ret = spi_nor_write_protection_set(dev, false);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
@ -858,6 +883,9 @@ static int spi_nor_write(const struct device *dev, off_t addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
release_device(dev);
|
release_device(dev);
|
||||||
|
|
||||||
|
/* Release flash power requirement */
|
||||||
|
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,6 +909,11 @@ static int spi_nor_erase(const struct device *dev, off_t addr, size_t size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure flash is powered before erase */
|
||||||
|
if (pm_device_runtime_get(dev) < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
acquire_device(dev);
|
acquire_device(dev);
|
||||||
ret = spi_nor_write_protection_set(dev, false);
|
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_device(dev);
|
||||||
|
|
||||||
|
/* Release flash power requirement */
|
||||||
|
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||||
return ret;
|
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,
|
static int spi_nor_sfdp_read(const struct device *dev, off_t addr,
|
||||||
void *dest, size_t size)
|
void *dest, size_t size)
|
||||||
{
|
{
|
||||||
|
if (pm_device_runtime_get(dev) < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
acquire_device(dev);
|
acquire_device(dev);
|
||||||
|
|
||||||
int ret = read_sfdp(dev, addr, dest, size);
|
int ret = read_sfdp(dev, addr, dest, size);
|
||||||
|
|
||||||
release_device(dev);
|
release_device(dev);
|
||||||
|
|
||||||
|
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -995,12 +1036,18 @@ static int spi_nor_read_jedec_id(const struct device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pm_device_runtime_get(dev) < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
acquire_device(dev);
|
acquire_device(dev);
|
||||||
|
|
||||||
int ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDID, id, SPI_NOR_MAX_ID_LEN);
|
int ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDID, id, SPI_NOR_MAX_ID_LEN);
|
||||||
|
|
||||||
release_device(dev);
|
release_device(dev);
|
||||||
|
|
||||||
|
(void)pm_device_runtime_put_async(dev, K_MSEC(ACTIVE_DWELL_MS));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue