diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index 258fe320393..967092ba303 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright (c) 2017,2019, NXP + * Copyright 2017, 2019, 2025, NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,12 +21,16 @@ #include #include +#include +#include + LOG_MODULE_REGISTER(spi_mcux_flexcomm, CONFIG_SPI_LOG_LEVEL); #include "spi_context.h" #define SPI_CHIP_SELECT_COUNT 4 #define SPI_MAX_DATA_WIDTH 16 +#define SPI_MIN_DATA_WIDTH 4 struct spi_mcux_config { SPI_Type *base; @@ -74,6 +78,8 @@ struct spi_mcux_data { #endif }; +static bool force_reconfig; + static void spi_mcux_transfer_next_packet(const struct device *dev) { const struct spi_mcux_config *config = dev->config; @@ -87,6 +93,8 @@ static void spi_mcux_transfer_next_packet(const struct device *dev) /* nothing left to rx or tx, we're done! */ spi_context_cs_control(&data->ctx, false); spi_context_complete(&data->ctx, dev, 0); + spi_context_release(&data->ctx, 0); + pm_policy_device_power_lock_put(dev); return; } @@ -177,23 +185,33 @@ static int spi_mcux_configure(const struct device *dev, uint32_t clock_freq; uint32_t word_size; - if (spi_context_configured(&data->ctx, spi_cfg)) { + + if ((spi_context_configured(&data->ctx, spi_cfg)) && (!force_reconfig)) { /* This configuration is already in use */ return 0; } + force_reconfig = false; + if (spi_cfg->operation & SPI_HALF_DUPLEX) { LOG_ERR("Half-duplex not supported"); return -ENOTSUP; } word_size = SPI_WORD_SIZE_GET(spi_cfg->operation); + if (word_size > SPI_MAX_DATA_WIDTH) { LOG_ERR("Word size %d is greater than %d", word_size, SPI_MAX_DATA_WIDTH); return -EINVAL; } + if (word_size < SPI_MIN_DATA_WIDTH) { + LOG_ERR("Word size %d is less than %d", + word_size, SPI_MIN_DATA_WIDTH); + return -EINVAL; + } + /* * Do master or slave initialisation, depending on the * mode requested. @@ -606,6 +624,8 @@ static int transceive_dma(const struct device *dev, uint32_t word_size; uint16_t data_size; + pm_policy_device_power_lock_get(dev); + spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg); ret = spi_mcux_configure(dev, spi_cfg); @@ -703,6 +723,8 @@ static int transceive_dma(const struct device *dev, out: spi_context_release(&data->ctx, ret); + pm_policy_device_power_lock_put(dev); + return ret; } @@ -719,6 +741,8 @@ static int transceive(const struct device *dev, struct spi_mcux_data *data = dev->data; int ret; + pm_policy_device_power_lock_get(dev); + spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg); ret = spi_mcux_configure(dev, spi_cfg); @@ -732,10 +756,12 @@ static int transceive(const struct device *dev, spi_mcux_transfer_next_packet(dev); - ret = spi_context_wait_for_completion(&data->ctx); + return spi_context_wait_for_completion(&data->ctx); out: spi_context_release(&data->ctx, ret); + pm_policy_device_power_lock_put(dev); + return ret; } @@ -776,7 +802,7 @@ static int spi_mcux_release(const struct device *dev, return 0; } -static int spi_mcux_init(const struct device *dev) +static int spi_mcux_init_common(const struct device *dev) { const struct spi_mcux_config *config = dev->config; struct spi_mcux_data *data = dev->data; @@ -824,6 +850,36 @@ static int spi_mcux_init(const struct device *dev) return 0; } +static int spi_mcux_flexcomm_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_RESUME: + break; + case PM_DEVICE_ACTION_SUSPEND: + break; + case PM_DEVICE_ACTION_TURN_OFF: + /*This flag is used to prevent configuration optimiztions + * after exiting PM3 on spi_mcux_configure() + */ + force_reconfig = true; + break; + case PM_DEVICE_ACTION_TURN_ON: + spi_mcux_init_common(dev); + break; + default: + return -ENOTSUP; + } + return 0; +} + +static int spi_mcux_init(const struct device *dev) +{ + /* Rest of the init is done from the PM_DEVICE_TURN_ON action + * which is invoked by pm_device_driver_init(). + */ + return pm_device_driver_init(dev, spi_mcux_flexcomm_pm_action); +} + static DEVICE_API(spi, spi_mcux_driver_api) = { .transceive = spi_mcux_transceive, #ifdef CONFIG_SPI_ASYNC @@ -901,9 +957,10 @@ static void spi_mcux_config_func_##id(const struct device *dev) \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx) \ SPI_DMA_CHANNELS(id) \ }; \ + PM_DEVICE_DT_INST_DEFINE(id, spi_mcux_flexcomm_pm_action); \ SPI_DEVICE_DT_INST_DEFINE(id, \ spi_mcux_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(id), \ &spi_mcux_data_##id, \ &spi_mcux_config_##id, \ POST_KERNEL, \