diff --git a/drivers/dma/dma_silabs_siwx91x.c b/drivers/dma/dma_silabs_siwx91x.c index 7cd1290d336c0..385e33295a8a8 100644 --- a/drivers/dma/dma_silabs_siwx91x.c +++ b/drivers/dma/dma_silabs_siwx91x.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include "rsi_rom_udma.h" #include "rsi_rom_udma_wrapper.h" @@ -60,6 +62,18 @@ struct dma_siwx91x_data { */ }; +static void siwx91x_dma_pm_policy_state_lock_get(const struct device *dev) +{ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +} + +static void siwx91x_dma_pm_policy_state_lock_put(const struct device *dev) +{ + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +} + static enum dma_xfer_dir siwx91x_transfer_direction(uint32_t dir) { if (dir == MEMORY_TO_MEMORY) { @@ -482,7 +496,11 @@ static int siwx91x_dma_start(const struct device *dev, uint32_t channel) return -EINVAL; } + /* Get the power management policy state lock */ + siwx91x_dma_pm_policy_state_lock_get(dev); + if (RSI_UDMA_ChannelEnable(udma_handle, channel) != 0) { + siwx91x_dma_pm_policy_state_lock_put(dev); return -EINVAL; } @@ -510,6 +528,8 @@ static int siwx91x_dma_stop(const struct device *dev, uint32_t channel) return -EIO; } + siwx91x_dma_pm_policy_state_lock_put(dev); + return 0; } @@ -560,8 +580,7 @@ bool siwx91x_dma_chan_filter(const struct device *dev, int channel, void *filter } } -/* Function to initialize DMA peripheral */ -static int siwx91x_dma_init(const struct device *dev) +static int dma_siwx91x_pm_action(const struct device *dev, enum pm_device_action action) { const struct dma_siwx91x_config *cfg = dev->config; struct dma_siwx91x_data *data = dev->data; @@ -573,25 +592,49 @@ static int siwx91x_dma_init(const struct device *dev) }; int ret; - ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys); - if (ret) { - return ret; - } + switch (action) { + case PM_DEVICE_ACTION_RESUME: + break; + case PM_DEVICE_ACTION_SUSPEND: + break; + case PM_DEVICE_ACTION_TURN_ON: + ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys); + if (ret < 0 && ret != -EALREADY) { + return ret; + } - udma_handle = UDMAx_Initialize(&udma_resources, udma_resources.desc, NULL, - (uint32_t *)&data->udma_handle); - if (udma_handle != &data->udma_handle) { - return -EINVAL; + udma_handle = UDMAx_Initialize(&udma_resources, udma_resources.desc, NULL, + (uint32_t *)&data->udma_handle); + if (udma_handle != &data->udma_handle) { + return -EINVAL; + } + + if (UDMAx_DMAEnable(&udma_resources, udma_handle) != 0) { + return -EBUSY; + } + break; + case PM_DEVICE_ACTION_TURN_OFF: + ret = clock_control_off(cfg->clock_dev, cfg->clock_subsys); + if (ret < 0 && ret != -EALREADY) { + return ret; + } + break; + default: + return -ENOTSUP; } + return 0; +} + +/* Function to initialize DMA peripheral */ +static int siwx91x_dma_init(const struct device *dev) +{ + const struct dma_siwx91x_config *cfg = dev->config; + /* Connect the DMA interrupt */ cfg->irq_configure(); - if (UDMAx_DMAEnable(&udma_resources, udma_handle) != 0) { - return -EBUSY; - } - - return 0; + return pm_device_driver_init(dev, dma_siwx91x_pm_action); } static void siwx91x_dma_isr(const struct device *dev) @@ -639,6 +682,7 @@ static void siwx91x_dma_isr(const struct device *dev) dev, data->zephyr_channel_info[channel].cb_data, channel, 0); } sys_write32(BIT(channel), (mem_addr_t)&cfg->reg->UDMA_DONE_STATUS_REG); + siwx91x_dma_pm_policy_state_lock_put(dev); } else { /* Call UDMA ROM IRQ handler. */ ROMAPI_UDMA_WRAPPER_API->uDMAx_IRQHandler(&udma_resources, udma_resources.desc, @@ -701,7 +745,10 @@ static DEVICE_API(dma, siwx91x_dma_api) = { (siwx91x_dma_chan_desc##inst)), \ .irq_configure = siwx91x_dma_irq_configure_##inst, \ }; \ - DEVICE_DT_INST_DEFINE(inst, siwx91x_dma_init, NULL, &dma_data_##inst, &dma_cfg_##inst, \ - POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, &siwx91x_dma_api); + PM_DEVICE_DT_INST_DEFINE(inst, dma_siwx91x_pm_action); \ + DEVICE_DT_INST_DEFINE(inst, siwx91x_dma_init, PM_DEVICE_DT_INST_GET(inst), \ + &dma_data_##inst, &dma_cfg_##inst, POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, \ + &siwx91x_dma_api); DT_INST_FOREACH_STATUS_OKAY(SIWX91X_DMA_INIT) diff --git a/dts/arm/silabs/siwg917.dtsi b/dts/arm/silabs/siwg917.dtsi index 1ccb7ee235094..af1d5738d936c 100644 --- a/dts/arm/silabs/siwg917.dtsi +++ b/dts/arm/silabs/siwg917.dtsi @@ -304,6 +304,8 @@ clocks = <&clock0 SIWX91X_CLK_DMA0>; #dma-cells = <1>; dma-channels = <32>; + power-domains = <&siwx91x_soc_pd>; + zephyr,pm-device-runtime-auto; status = "disabled"; }; @@ -318,6 +320,8 @@ silabs,sram-region = <&sram_dma1>; #dma-cells = <1>; dma-channels = <12>; + power-domains = <&siwx91x_soc_pd>; + zephyr,pm-device-runtime-auto; status = "disabled"; };