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