#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/log2.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 }
 EXPORT_SYMBOL_GPL(dw_dma_filter);
 
+static int dwc_verify_p_buswidth(struct dma_chan *chan)
+{
+       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+       struct dw_dma *dw = to_dw_dma(chan->device);
+       u32 reg_width, max_width;
+
+       if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
+               reg_width = dwc->dma_sconfig.dst_addr_width;
+       else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM)
+               reg_width = dwc->dma_sconfig.src_addr_width;
+       else /* DMA_MEM_TO_MEM */
+               return 0;
+
+       max_width = dw->pdata->data_width[dwc->dws.p_master];
+
+       /* Fall-back to 1-byte transfer width if undefined */
+       if (reg_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+               reg_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       else if (!is_power_of_2(reg_width) || reg_width > max_width)
+               return -EINVAL;
+       else /* bus width is valid */
+               return 0;
+
+       /* Update undefined addr width value */
+       if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
+               dwc->dma_sconfig.dst_addr_width = reg_width;
+       else /* DMA_DEV_TO_MEM */
+               dwc->dma_sconfig.src_addr_width = reg_width;
+
+       return 0;
+}
+
 static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 {
        struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
        struct dw_dma *dw = to_dw_dma(chan->device);
+       int ret;
 
        memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
 
        dwc->dma_sconfig.dst_maxburst =
                clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst);
 
+       ret = dwc_verify_p_buswidth(chan);
+       if (ret)
+               return ret;
+
        dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
        dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);