Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/releases/migration-guide-4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=======

Expand Down
19 changes: 9 additions & 10 deletions drivers/flash/Kconfig.nor
Original file line number Diff line number Diff line change
Expand Up @@ -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
88 changes: 57 additions & 31 deletions drivers/flash/spi_nor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand All @@ -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*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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) {
Expand All @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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;
Expand Down
10 changes: 0 additions & 10 deletions samples/drivers/spi_flash/sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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