From: supriya karanth <supriya.kara...@stericsson.com>

Added pause, resume, tx_status and check_status functions
RNDIS and ECM require 2 byte aligned addresses, change
bus width of the DMA slave to 2 bytes.

Signed-off-by: supriya karanth <supriya.kara...@stericsson.com>
Signed-off-by: Praveena NADAHALLY <praveen.nadaha...@stericsson.com>
Acked-by: Linus Walleij <linus.wall...@linaro.org>
---
 drivers/usb/musb/ux500_dma.c |  183 +++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 180 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 039e567..aefb606 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -106,7 +106,8 @@ static bool ux500_configure_channel(struct dma_channel 
*channel,
 
        direction = ux500_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
        addr_width = (len & 0x3) ? DMA_SLAVE_BUSWIDTH_1_BYTE :
-                                       DMA_SLAVE_BUSWIDTH_4_BYTES;
+                               ((dma_addr & 0x2) ? DMA_SLAVE_BUSWIDTH_2_BYTES :
+                                       DMA_SLAVE_BUSWIDTH_4_BYTES);
 
        slave_conf.direction = direction;
        slave_conf.src_addr = usb_fifo_addr;
@@ -134,6 +135,15 @@ static bool ux500_configure_channel(struct dma_channel 
*channel,
        return true;
 }
 
+/**
+ * ux500_dma_controller_allocate() - allocates the DMA channels
+ * @c: pointer to DMA controller
+ * @hw_ep: pointer to endpoint
+ * @is_tx: transmit or receive direction
+ *
+ * This function allocates the DMA channel and initializes
+ * the channel
+*/
 static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c,
                                struct musb_hw_ep *hw_ep, u8 is_tx)
 {
@@ -173,6 +183,13 @@ static struct dma_channel 
*ux500_dma_channel_allocate(struct dma_controller *c,
        return &(ux500_channel->channel);
 }
 
+/**
+ * ux500_dma_channel_release() - releases the DMA channel
+ * @channel:   channel to be released
+ *
+ * This function releases the DMA channel
+ *
+*/
 static void ux500_dma_channel_release(struct dma_channel *channel)
 {
        struct ux500_dma_channel *ux500_channel = channel->private_data;
@@ -192,13 +209,22 @@ static int ux500_dma_is_compatible(struct dma_channel 
*channel,
 {
        if ((maxpacket & 0x3)           ||
                ((int)buf & 0x3)        ||
-               (length < 512)          ||
-               (length & 0x3))
+               (length < 512))
                return false;
        else
                return true;
 }
 
+/**
+ * ux500_dma_channel_program() - Configures the channel and initiates transfer
+ * @channel:   pointer to DMA channel
+ * @packet_sz: packet size
+ * @mode: mode
+ * @dma_addr: physical address of memory
+ * @len: length
+ *
+ * This function configures the channel and initiates the DMA transfer
+*/
 static int ux500_dma_channel_program(struct dma_channel *channel,
                                u16 packet_sz, u8 mode,
                                dma_addr_t dma_addr, u32 len)
@@ -220,6 +246,12 @@ static int ux500_dma_channel_program(struct dma_channel 
*channel,
        return ret;
 }
 
+/**
+ * ux500_dma_channel_abort() - aborts the DMA transfer
+ * @channel:   pointer to DMA channel.
+ *
+ * This function aborts the DMA transfer.
+*/
 static int ux500_dma_channel_abort(struct dma_channel *channel)
 {
        struct ux500_dma_channel *ux500_channel = channel->private_data;
@@ -254,6 +286,124 @@ static int ux500_dma_channel_abort(struct dma_channel 
*channel)
        return 0;
 }
 
+/**
+ * ux500_dma_channel_pause() - pauses the DMA transfer
+ * @channel:   pointer to DMA channel.
+ *
+ * This function pauses the DMA transfer. This is needed to get
+ * the correct residue of an ongoing DMA transfer
+*/
+static int ux500_dma_channel_pause(struct dma_channel *channel)
+{
+       struct ux500_dma_channel *ux500_channel = channel->private_data;
+       struct ux500_dma_controller *controller = ux500_channel->controller;
+       struct musb *musb = controller->private_data;
+       int status;
+
+       status = ux500_channel->dma_chan->device->
+                       device_control(ux500_channel->dma_chan,
+                       DMA_PAUSE, 0);
+
+       dev_dbg(musb->controller,
+               "%s channel=%d, is_tx=%d, status=%d\n",
+               __func__, ux500_channel->ch_num, ux500_channel->is_tx
+               , status);
+       return status;
+}
+
+/**
+ * ux500_dma_channel_resume() - resumes the DMA transfer
+ * @channel:   pointer to DMA channel.
+ *
+ * This function resumes a paused DMA transfer.
+*/
+static int ux500_dma_channel_resume(struct dma_channel *channel)
+{
+       struct ux500_dma_channel *ux500_channel = channel->private_data;
+       struct ux500_dma_controller *controller = ux500_channel->controller;
+       struct musb *musb = controller->private_data;
+       int status;
+
+       status = ux500_channel->dma_chan->device->
+                       device_control(ux500_channel->dma_chan,
+                       DMA_RESUME, 0);
+       dev_dbg(musb->controller,
+               "%s channel=%d, is_tx=%d, status=%d\n",
+               __func__, ux500_channel->ch_num, ux500_channel->is_tx
+               , status);
+       return status;
+}
+
+/**
+ * ux500_dma_tx_status() - Gets the residue of an ongoing DMA transfer
+ * @channel:    pointer to DMA channel
+ *
+ * This function will get the number of bytes left to be transferred
+ * over the DMA
+ */
+static int ux500_dma_tx_status(struct dma_channel *channel)
+{
+       struct ux500_dma_channel *ux500_channel = channel->private_data;
+       struct ux500_dma_controller *controller = ux500_channel->controller;
+       struct musb *musb = controller->private_data;
+       struct dma_tx_state txstate;
+
+       ux500_channel->dma_chan->device->
+                       device_tx_status(ux500_channel->dma_chan,
+                                       ux500_channel->cookie, &txstate);
+       dev_dbg(musb->controller,
+               "%s channel=%d, is_tx=%d, residue=%d\n",
+               __func__, ux500_channel->ch_num, ux500_channel->is_tx
+               , txstate.residue);
+       return txstate.residue;
+}
+
+/**
+ * ux500_dma_check_residue() - Checks if the DMA transfer residue is valid
+ * @channel:    pointer to DMA channel
+ */
+static int ux500_dma_check_residue(struct dma_channel *channel, u32 residue)
+{
+       struct ux500_dma_channel *ux500_channel = channel->private_data;
+       struct ux500_dma_controller *controller = ux500_channel->controller;
+       struct musb *musb = controller->private_data;
+       int status;
+
+       dev_dbg(musb->controller,
+               "%s channel=%d, is_tx=%d, residue=%d\n",
+               __func__, ux500_channel->ch_num, ux500_channel->is_tx
+               , residue);
+
+       /* In cases where we know the transfer length and were expecting
+        * a DMA completion we could get into the DMA busy condition
+        * here if the next packet is short and the EP interrupt occurs
+        * before we recieve dma_completion interrupt for current transfer
+        * Wait for dma_completion. MUSB will interrupt us again for this
+        * short packet when we clear the DMA bits
+        */
+       if (!residue) {
+               dev_dbg(musb->controller,
+                     "%s: Wait for DMA completion\n",
+                     __func__);
+               status = -EINPROGRESS;
+       } else if (residue == ux500_channel->channel.prog_len) {
+               /* Nothing transferred over DMA? */
+               WARN_ON(1);
+               status = -EINVAL;
+       } else {
+               /* residue looks OK */
+               status = 0;
+       }
+
+       return status;
+}
+
+/**
+ * ux500_dma_controller_stop() - releases all the channels and frees the DMA 
pipes
+ * @c: pointer to DMA controller
+ *
+ * This function frees all of the logical channels and frees the DMA pipes
+*/
 static int ux500_dma_controller_stop(struct dma_controller *c)
 {
        struct ux500_dma_controller *controller = container_of(c,
@@ -285,6 +435,14 @@ static int ux500_dma_controller_stop(struct dma_controller 
*c)
        return 0;
 }
 
+/**
+ * ux500_dma_controller_start() - creates the logical channels pool and 
registers callbacks
+ * @c: pointer to DMA Controller
+ *
+ * This function requests the logical channels from the DMA driver and creates
+ * logical channels based on event lines and also registers the callbacks which
+ * are invoked after data transfer in the transmit or receive direction.
+*/
 static int ux500_dma_controller_start(struct dma_controller *c)
 {
        struct ux500_dma_controller *controller = container_of(c,
@@ -356,6 +514,12 @@ static int ux500_dma_controller_start(struct 
dma_controller *c)
        return 0;
 }
 
+/**
+ * dma_controller_destroy() - deallocates the DMA controller
+ * @c: pointer to dma controller.
+ *
+ * This function deallocates the DMA controller.
+*/
 void dma_controller_destroy(struct dma_controller *c)
 {
        struct ux500_dma_controller *controller = container_of(c,
@@ -364,6 +528,15 @@ void dma_controller_destroy(struct dma_controller *c)
        kfree(controller);
 }
 
+/**
+ * dma_controller_create() - creates the dma controller and initializes 
callbacks
+ *
+ * @musb:      pointer to mentor core driver data instance|
+ * @base:      base address of musb registers.
+ *
+ * This function creates the DMA controller and initializes the callbacks
+ * that are invoked from the Mentor IP core.
+*/
 struct dma_controller *dma_controller_create(struct musb *musb, void __iomem 
*base)
 {
        struct ux500_dma_controller *controller;
@@ -386,6 +559,10 @@ struct dma_controller *dma_controller_create(struct musb 
*musb, void __iomem *ba
        controller->controller.channel_release = ux500_dma_channel_release;
        controller->controller.channel_program = ux500_dma_channel_program;
        controller->controller.channel_abort = ux500_dma_channel_abort;
+       controller->controller.channel_pause = ux500_dma_channel_pause;
+       controller->controller.channel_resume = ux500_dma_channel_resume;
+       controller->controller.tx_status = ux500_dma_tx_status;
+       controller->controller.check_residue = ux500_dma_check_residue;
        controller->controller.is_compatible = ux500_dma_is_compatible;
 
        return &controller->controller;
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to