[PATCH 4/4] usb: musb: ux500: Enable DMA Mode1 for device mode RX

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: supriya karanth <supriya.karanth@xxxxxxxxxxxxxx>

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.karanth@xxxxxxxxxxxxxx>
Signed-off-by: Praveena NADAHALLY <praveen.nadahally@xxxxxxxxxxxxxx>
Acked-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux