diff options
-rw-r--r-- | drivers/i2c/busses/i2c-msm-v2.c | 27 | ||||
-rw-r--r-- | include/linux/i2c/i2c-msm-v2.h | 3 |
2 files changed, 24 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index bf2a1dd7cf15..7f98d9f527b9 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -1151,12 +1151,20 @@ static void i2c_msm_dma_xfer_unprepare(struct i2c_msm_ctrl *ctrl) buf_itr->dma_dir); } -static void i2c_msm_dma_callback_xfer_complete(void *dma_async_param) +static void i2c_msm_dma_callback_tx_complete(void *dma_async_param) { struct i2c_msm_ctrl *ctrl = dma_async_param; + complete(&ctrl->xfer.complete); } +static void i2c_msm_dma_callback_rx_complete(void *dma_async_param) +{ + struct i2c_msm_ctrl *ctrl = dma_async_param; + + complete(&ctrl->xfer.rx_complete); +} + /* * i2c_msm_dma_xfer_process: Queue transfers to DMA * @pre 1)QUP is in run state. 2) i2c_msm_dma_xfer_prepare() was called. @@ -1269,14 +1277,16 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) } /* callback defined for tx dma desc */ - dma_desc_tx->callback = i2c_msm_dma_callback_xfer_complete; + dma_desc_tx->callback = i2c_msm_dma_callback_tx_complete; dma_desc_tx->callback_param = ctrl; dmaengine_submit(dma_desc_tx); dma_async_issue_pending(tx->dma_chan); /* queue the rx dma desc */ dma_desc_rx = dmaengine_prep_slave_sg(rx->dma_chan, sg_rx, - sg_rx_itr - sg_rx, rx->dir, 0); + sg_rx_itr - sg_rx, rx->dir, + (SPS_IOVEC_FLAG_EOT | + SPS_IOVEC_FLAG_NWD)); if (dma_desc_rx < 0) { dev_err(ctrl->dev, "error dmaengine_prep_slave_sg rx:%ld\n", @@ -1285,6 +1295,8 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) goto dma_xfer_end; } + dma_desc_rx->callback = i2c_msm_dma_callback_rx_complete; + dma_desc_rx->callback_param = ctrl; dmaengine_submit(dma_desc_rx); dma_async_issue_pending(rx->dma_chan); @@ -1297,6 +1309,8 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) } ret = i2c_msm_xfer_wait_for_completion(ctrl, &ctrl->xfer.complete); + if (!ret && ctrl->xfer.rx_cnt) + i2c_msm_xfer_wait_for_completion(ctrl, &ctrl->xfer.rx_complete); dma_xfer_end: /* free scatter-gather lists */ @@ -2054,13 +2068,14 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl, long time_left; int ret = 0; - time_left = wait_for_completion_timeout(complete, xfer->timeout); + time_left = wait_for_completion_timeout(complete, + xfer->timeout); if (!time_left) { xfer->err = I2C_MSM_ERR_TIMEOUT; i2c_msm_dbg_dump_diag(ctrl, false, 0, 0); ret = -EIO; i2c_msm_prof_evnt_add(ctrl, MSM_ERR, I2C_MSM_COMPLT_FL, - xfer->timeout, time_left, 0); + xfer->timeout, time_left, 0); } else { /* return an error if one detected by ISR */ if (xfer->err) @@ -2327,6 +2342,8 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) xfer->tx_ovrhd_cnt = 0; atomic_set(&xfer->event_cnt, 0); init_completion(&xfer->complete); + init_completion(&xfer->rx_complete); + xfer->cur_buf.is_init = false; xfer->cur_buf.msg_idx = 0; diff --git a/include/linux/i2c/i2c-msm-v2.h b/include/linux/i2c/i2c-msm-v2.h index 54974c02725d..468a1d6fa58d 100644 --- a/include/linux/i2c/i2c-msm-v2.h +++ b/include/linux/i2c/i2c-msm-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015,2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -552,6 +552,7 @@ struct i2c_msm_xfer { int msg_cnt; enum i2c_msm_xfer_mode_id mode_id; struct completion complete; + struct completion rx_complete; size_t rx_cnt; size_t tx_cnt; size_t rx_ovrhd_cnt; |