drivers: dma: dma_mcux_lpc: Add register backup and restore

Add for the case that the registers are not kept in some
low power modes.

Signed-off-by: Jason Yu <zejiang.yu@nxp.com>
This commit is contained in:
Jason Yu
2025-11-14 15:56:58 +08:00
committed by Benjamin Cabé
parent ed2af53f59
commit 24f8ed75cb

View File

@@ -29,6 +29,28 @@
LOG_MODULE_REGISTER(dma_mcux_lpc, CONFIG_DMA_LOG_LEVEL);
#if CONFIG_PM_DEVICE
/*
* Data structures to backup DMA registers when the
* register content lost in low power modes.
*/
struct dma_backup_reg {
/*
* Backup the control registers.
* Don't need to backup CTRL and SRAMBASE, they
* are configured in function DMA_Init.
*/
uint32_t enableset; /* Register ENABLESET */
uint32_t intenset; /* Register INTENSET */
};
struct dma_ch_backup_reg {
/* Don't need to backup status register CTLSTAT. */
uint32_t cfg; /* Register CFG */
uint32_t xfercfg; /* Register XFERCFG */
};
#endif /* CONFIG_PM_DEVICE */
struct dma_mcux_lpc_config {
DMA_Type *base;
uint32_t otrig_base_address;
@@ -54,6 +76,9 @@ struct channel_data {
uint8_t num_of_descriptors;
bool descriptors_queued;
bool busy;
#if CONFIG_PM_DEVICE
struct dma_ch_backup_reg backup_reg;
#endif /* CONFIG_PM_DEVICE */
};
struct dma_otrig {
@@ -68,6 +93,9 @@ struct dma_mcux_lpc_dma_data {
struct dma_otrig *otrig_array;
int8_t *channel_index;
uint8_t num_channels_used;
#if CONFIG_PM_DEVICE
struct dma_backup_reg backup_reg;
#endif /* CONFIG_PM_DEVICE */
};
struct k_spinlock configuring_otrigs;
@@ -948,6 +976,69 @@ static int dma_mcux_lpc_get_attribute(const struct device *dev, uint32_t type, u
return 0;
}
#if CONFIG_PM_DEVICE
static void dma_mcux_lpc_backup_reg(const struct device *dev)
{
struct dma_mcux_lpc_dma_data *dma_data = dev->data;
const struct dma_mcux_lpc_config *config = dev->config;
struct channel_data *p_channel_data;
uint32_t virtual_channel;
DMA_Type *dma_base = DEV_BASE(dev);
dma_data->backup_reg.enableset = dma_base->COMMON[0].ENABLESET;
dma_data->backup_reg.intenset = dma_base->COMMON[0].INTENSET;
/* Only backup the used channels */
virtual_channel = 0;
for (uint32_t channel = 0; channel < config->num_of_channels; channel++) {
if (dma_data->channel_index[channel] != -1) {
p_channel_data = &dma_data->channel_data[virtual_channel];
p_channel_data->backup_reg.xfercfg = dma_base->CHANNEL[channel].XFERCFG;
p_channel_data->backup_reg.cfg = dma_base->CHANNEL[channel].CFG;
virtual_channel++;
}
}
}
static void dma_mcux_lpc_restore_reg(const struct device *dev)
{
struct dma_mcux_lpc_dma_data *dma_data = dev->data;
const struct dma_mcux_lpc_config *config = dev->config;
struct channel_data *p_channel_data;
uint32_t virtual_channel;
DMA_Type *dma_base = DEV_BASE(dev);
dma_base->COMMON[0].ENABLESET = dma_data->backup_reg.enableset;
dma_base->COMMON[0].INTENSET = dma_data->backup_reg.intenset;
/* Only backup the used channels */
virtual_channel = 0;
for (uint32_t channel = 0; channel < config->num_of_channels; channel++) {
if (dma_data->channel_index[channel] != -1) {
p_channel_data = &dma_data->channel_data[virtual_channel];
dma_base->CHANNEL[channel].XFERCFG = p_channel_data->backup_reg.xfercfg;
dma_base->CHANNEL[channel].CFG = p_channel_data->backup_reg.cfg;
virtual_channel++;
}
}
}
#else /* !CONFIG_PM_DEVICE */
static inline void dma_mcux_lpc_backup_reg(const struct device *dev)
{
ARG_UNUSED(dev);
}
static inline void dma_mcux_lpc_restore_reg(const struct device *dev)
{
ARG_UNUSED(dev);
}
#endif /* CONFIG_PM_DEVICE */
static int dma_mcux_lpc_pm_action(const struct device *dev, enum pm_device_action action)
{
switch (action) {
@@ -956,9 +1047,11 @@ static int dma_mcux_lpc_pm_action(const struct device *dev, enum pm_device_actio
case PM_DEVICE_ACTION_SUSPEND:
break;
case PM_DEVICE_ACTION_TURN_OFF:
dma_mcux_lpc_backup_reg(dev);
break;
case PM_DEVICE_ACTION_TURN_ON:
DMA_Init(DEV_BASE(dev));
dma_mcux_lpc_restore_reg(dev);
break;
default:
return -ENOTSUP;