diff --git a/doc/releases/migration-guide-4.0.rst b/doc/releases/migration-guide-4.0.rst index 4e5ae29a09d08..95959ec840b38 100644 --- a/doc/releases/migration-guide-4.0.rst +++ b/doc/releases/migration-guide-4.0.rst @@ -113,6 +113,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 ======= diff --git a/drivers/flash/Kconfig.nor b/drivers/flash/Kconfig.nor index eed33c8e1807f..46ea130efbfef 100644 --- a/drivers/flash/Kconfig.nor +++ b/drivers/flash/Kconfig.nor @@ -78,16 +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_IDLE_IN_DPD - bool "Use Deep Power-Down mode when flash is not being accessed." +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 - Where supported deep power-down mode can reduce current draw - to as little as 0.1% of standby current. However it takes - some milliseconds to enter and exit from this mode. - - Select this option for applications where device power - management is not enabled, the flash remains inactive for - long periods, and when used the impact of waiting for mode - enter and exit delays is acceptable. + 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 diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index 88d3ad5c30454..236955887ab1f 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "spi_nor.h" #include "jesd216.h" @@ -35,15 +36,10 @@ LOG_MODULE_REGISTER(spi_nor, CONFIG_FLASH_LOG_LEVEL); * * Some devices support a Deep Power-Down mode which reduces current * to as little as 0.1% of standby. * - * The power reduction from DPD is sufficient to warrant allowing its - * use even in cases where Zephyr's device power management is not - * available. This is selected through the SPI_NOR_IDLE_IN_DPD - * Kconfig option. - * * When mapped to the Zephyr Device Power Management states: * * PM_DEVICE_STATE_ACTIVE covers both active and standby modes; - * * PM_DEVICE_STATE_SUSPENDED, and PM_DEVICE_STATE_OFF all correspond to - * deep-power-down mode. + * * PM_DEVICE_STATE_SUSPENDED corresponds to deep-power-down mode; + * * PM_DEVICE_STATE_OFF covers the powered off state; */ #define SPI_NOR_MAX_ADDR_WIDTH 4 @@ -70,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*/ @@ -552,34 +554,26 @@ static int exit_dpd(const struct device *const dev) return ret; } -/* Everything necessary to acquire owning access to the device. - * - * This means taking the lock and, if necessary, waking the device - * from deep power-down mode. - */ +/* Everything necessary to acquire owning access to the device. */ static void acquire_device(const struct device *dev) { + const struct spi_nor_config *cfg = dev->config; + if (IS_ENABLED(CONFIG_MULTITHREADING)) { struct spi_nor_data *const driver_data = dev->data; k_sem_take(&driver_data->sem, K_FOREVER); } - if (IS_ENABLED(CONFIG_SPI_NOR_IDLE_IN_DPD)) { - exit_dpd(dev); - } + (void)pm_device_runtime_get(cfg->spi.bus); } -/* Everything necessary to release access to the device. - * - * This means (optionally) putting the device into deep power-down - * mode, and releasing the lock. - */ +/* Everything necessary to release access to the device. */ static void release_device(const struct device *dev) { - if (IS_ENABLED(CONFIG_SPI_NOR_IDLE_IN_DPD)) { - enter_dpd(dev); - } + const struct spi_nor_config *cfg = dev->config; + + (void)pm_device_runtime_put(cfg->spi.bus); if (IS_ENABLED(CONFIG_MULTITHREADING)) { struct spi_nor_data *const driver_data = dev->data; @@ -783,11 +777,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; } @@ -800,6 +802,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) { @@ -815,6 +821,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 @@ -832,6 +839,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) { @@ -879,6 +891,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; } @@ -902,6 +917,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); @@ -957,6 +977,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; } @@ -998,12 +1020,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; } @@ -1016,12 +1044,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; } @@ -1439,11 +1473,6 @@ static int spi_nor_pm_control(const struct device *dev, enum pm_device_action ac int rc = 0; switch (action) { -#ifdef CONFIG_SPI_NOR_IDLE_IN_DPD - case PM_DEVICE_ACTION_SUSPEND: - case PM_DEVICE_ACTION_RESUME: - break; -#else case PM_DEVICE_ACTION_SUSPEND: acquire_device(dev); rc = enter_dpd(dev); @@ -1454,11 +1483,9 @@ static int spi_nor_pm_control(const struct device *dev, enum pm_device_action ac rc = exit_dpd(dev); release_device(dev); break; -#endif /* CONFIG_SPI_NOR_IDLE_IN_DPD */ case PM_DEVICE_ACTION_TURN_ON: /* Coming out of power off */ rc = spi_nor_configure(dev); -#ifndef CONFIG_SPI_NOR_IDLE_IN_DPD if (rc == 0) { /* Move to DPD, the correct device state * for PM_DEVICE_STATE_SUSPENDED @@ -1467,7 +1494,6 @@ static int spi_nor_pm_control(const struct device *dev, enum pm_device_action ac rc = enter_dpd(dev); release_device(dev); } -#endif /* CONFIG_SPI_NOR_IDLE_IN_DPD */ break; case PM_DEVICE_ACTION_TURN_OFF: break; diff --git a/samples/drivers/spi_flash/sample.yaml b/samples/drivers/spi_flash/sample.yaml index b7c7a06924386..377c5ccec6ef3 100644 --- a/samples/drivers/spi_flash/sample.yaml +++ b/samples/drivers/spi_flash/sample.yaml @@ -20,13 +20,3 @@ tests: - "Attempting to write 4 bytes" - "Data read matches data written. Good!!" depends_on: spi - sample.drivers.spi.flash_dpd: - tags: - - spi - - flash - filter: dt_compat_enabled("jedec,spi-nor") - platform_exclude: hifive_unmatched - build_only: true - extra_configs: - - CONFIG_SPI_NOR_IDLE_IN_DPD=y - depends_on: spi