diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index e4b8367dce6a0611ba11c80cde27aa0ebac2f958..c083510ef4405bcbc6f76f950cb5a7d2ceec6fbb 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -193,6 +193,7 @@ struct udma_dev { int rchan_cnt; int rflow_cnt; int tflow_cnt; + int ch_count; unsigned long *bchan_map; unsigned long *tchan_map; unsigned long *rchan_map; @@ -302,6 +303,8 @@ struct udma_chan { /* Channel configuration parameters */ struct udma_chan_config config; + /* Channel configuration parameters (backup) */ + struct udma_chan_config backup_config; /* dmapool for packet mode descriptors */ bool use_dma_pool; @@ -4943,6 +4946,7 @@ static int setup_resources(struct udma_dev *ud) if (!ch_count) return -ENODEV; + ud->ch_count = ch_count; ud->channels = devm_kcalloc(dev, ch_count, sizeof(*ud->channels), GFP_KERNEL); if (!ud->channels) @@ -5439,11 +5443,62 @@ static int udma_probe(struct platform_device *pdev) return ret; } +static int udma_pm_suspend(struct device *dev) +{ + struct udma_dev *ud = dev_get_drvdata(dev); + struct dma_chan *chan; + int i; + + for (i = 0; i < ud->ch_count; i++) { + chan = &ud->channels[i].vc.chan; + if (chan->client_count) { + /* backup the channel configuration */ + memcpy(&ud->channels[i].backup_config, + &ud->channels[i].config, + sizeof(struct udma_chan_config)); + dev_dbg(dev, "Suspending channel %s\n", + dma_chan_name(chan)); + ud->ddev.device_free_chan_resources(chan); + } + } + + return 0; +} + +static int udma_pm_resume(struct device *dev) +{ + struct udma_dev *ud = dev_get_drvdata(dev); + struct dma_chan *chan; + int ret, i; + + for (i = 0; i < ud->ch_count; i++) { + chan = &ud->channels[i].vc.chan; + if (chan->client_count) { + /* restore the channel configuration */ + memcpy(&ud->channels[i].config, + &ud->channels[i].backup_config, + sizeof(struct udma_chan_config)); + dev_dbg(dev, "Resuming channel %s\n", + dma_chan_name(chan)); + ret = ud->ddev.device_alloc_chan_resources(chan); + if (ret) + return ret; + } + } + + return 0; +} + +static const struct dev_pm_ops udma_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(udma_pm_suspend, udma_pm_resume) +}; + static struct platform_driver udma_driver = { .driver = { .name = "ti-udma", .of_match_table = udma_of_match, .suppress_bind_attrs = true, + .pm = &udma_pm_ops, }, .probe = udma_probe, }; @@ -5454,6 +5509,7 @@ static struct platform_driver bcdma_driver = { .name = "ti-bcdma", .of_match_table = bcdma_of_match, .suppress_bind_attrs = true, + .pm = &udma_pm_ops, }, .probe = udma_probe, }; @@ -5464,6 +5520,7 @@ static struct platform_driver pktdma_driver = { .name = "ti-pktdma", .of_match_table = pktdma_of_match, .suppress_bind_attrs = true, + .pm = &udma_pm_ops, }, .probe = udma_probe, };