ipq40xx: backport I2C QUP driver changes from 4.17
Backport below changes for I2C QUP driver from v4.17: 0668bc44a426 i2c: qup: fix copyrights and update to SPDX identifier 7239872fb340 i2c: qup: fixed releasing dma without flush operation completion eb422b539c1f i2c: qup: minor code reorganization for use_dma 6d5f37f166bb i2c: qup: remove redundant variables for BAM SG count c5adc0fa63a9 i2c: qup: schedule EOT and FLUSH tags at the end of transfer 7e6c35fe602d i2c: qup: fix the transfer length for BAM RX EOT FLUSH tags 3f450d3eea14 i2c: qup: proper error handling for i2c error in BAM mode 08f15963bc75 i2c: qup: use the complete transfer length to choose DMA mode ecb6e1e5f435 i2c: qup: change completion timeout according to transfer length 6f2f0f6465ac i2c: qup: fix buffer overflow for multiple msg of maximum xfer len f7714b4e451b i2c: qup: send NACK for last read sub transfers fbfab1ab0658 i2c: qup: reorganization of driver code to remove polling for qup v1 7545c7dba169 i2c: qup: reorganization of driver code to remove polling for qup v2 This fixes various I2C issues observed on AP120C-AC board equipped with Atmel/Microchip AT97SC3205T TPM module. Tested-by: Christian Lamparter <chunkeey@gmail.com> Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>v19.07.3_mercusys_ac12_duma
parent
ff8a8074b2
commit
24de7c29e5
@ -0,0 +1,36 @@
|
|||||||
|
From 0668bc44a42672626666e4f66aa1f2c22528e8a5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:50 +0530
|
||||||
|
Subject: [PATCH 01/13] i2c: qup: fix copyrights and update to SPDX identifier
|
||||||
|
|
||||||
|
The file has been updated from 2016 to 2018 so fixed the
|
||||||
|
copyright years.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 13 ++-----------
|
||||||
|
1 file changed, 2 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -1,17 +1,8 @@
|
||||||
|
+// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
|
||||||
|
+ * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2014, Sony Mobile Communications AB.
|
||||||
|
*
|
||||||
|
- *
|
||||||
|
- * 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
|
||||||
|
- * only version 2 as published by the Free Software Foundation.
|
||||||
|
- *
|
||||||
|
- * This program is distributed in the hope that it will be useful,
|
||||||
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
- * GNU General Public License for more details.
|
||||||
|
- *
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
@ -0,0 +1,44 @@
|
|||||||
|
From 7239872fb3400b21a8f5547257f9f86455867bd6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:51 +0530
|
||||||
|
Subject: [PATCH 02/13] i2c: qup: fixed releasing dma without flush operation
|
||||||
|
completion
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
The QUP BSLP BAM generates the following error sometimes if the
|
||||||
|
current I2C DMA transfer fails and the flush operation has been
|
||||||
|
scheduled
|
||||||
|
|
||||||
|
“bam-dma-engine 7884000.dma: Cannot free busy channel”
|
||||||
|
|
||||||
|
If any I2C error comes during BAM DMA transfer, then the QUP I2C
|
||||||
|
interrupt will be generated and the flush operation will be
|
||||||
|
carried out to make I2C consume all scheduled DMA transfer.
|
||||||
|
Currently, the same completion structure is being used for BAM
|
||||||
|
transfer which has already completed without reinit. It will make
|
||||||
|
flush operation wait_for_completion_timeout completed immediately
|
||||||
|
and will proceed for freeing the DMA resources where the
|
||||||
|
descriptors are still in process.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Acked-by: Sricharan R <sricharan@codeaurora.org>
|
||||||
|
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||||
|
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -835,6 +835,8 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret || qup->bus_err || qup->qup_err) {
|
||||||
|
+ reinit_completion(&qup->xfer);
|
||||||
|
+
|
||||||
|
if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
|
||||||
|
dev_err(qup->dev, "change to run state timed out");
|
||||||
|
goto desc_err;
|
@ -0,0 +1,76 @@
|
|||||||
|
From eb422b539c1f39faf576826b54be93e84d9cb32a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:52 +0530
|
||||||
|
Subject: [PATCH 03/13] i2c: qup: minor code reorganization for use_dma
|
||||||
|
|
||||||
|
1. Assigns use_dma in qup_dev structure itself which will
|
||||||
|
help in subsequent patches to determine the mode in IRQ handler.
|
||||||
|
2. Does minor code reorganization for loops to reduce the
|
||||||
|
unnecessary comparison and assignment.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||||
|
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 19 +++++++++++--------
|
||||||
|
1 file changed, 11 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -181,6 +181,8 @@ struct qup_i2c_dev {
|
||||||
|
|
||||||
|
/* dma parameters */
|
||||||
|
bool is_dma;
|
||||||
|
+ /* To check if the current transfer is using DMA */
|
||||||
|
+ bool use_dma;
|
||||||
|
struct dma_pool *dpool;
|
||||||
|
struct qup_i2c_tag start_tag;
|
||||||
|
struct qup_i2c_bam brx;
|
||||||
|
@@ -1288,7 +1290,7 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||||
|
int num)
|
||||||
|
{
|
||||||
|
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
|
||||||
|
- int ret, len, idx = 0, use_dma = 0;
|
||||||
|
+ int ret, len, idx = 0;
|
||||||
|
|
||||||
|
qup->bus_err = 0;
|
||||||
|
qup->qup_err = 0;
|
||||||
|
@@ -1317,13 +1319,12 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||||
|
len = (msgs[idx].len > qup->out_fifo_sz) ||
|
||||||
|
(msgs[idx].len > qup->in_fifo_sz);
|
||||||
|
|
||||||
|
- if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
|
||||||
|
- use_dma = 1;
|
||||||
|
- } else {
|
||||||
|
- use_dma = 0;
|
||||||
|
+ if (is_vmalloc_addr(msgs[idx].buf) || !len)
|
||||||
|
break;
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (idx == num)
|
||||||
|
+ qup->use_dma = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
@@ -1347,15 +1348,17 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||||
|
|
||||||
|
reinit_completion(&qup->xfer);
|
||||||
|
|
||||||
|
- if (use_dma) {
|
||||||
|
+ if (qup->use_dma) {
|
||||||
|
ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
|
||||||
|
+ qup->use_dma = false;
|
||||||
|
+ break;
|
||||||
|
} else {
|
||||||
|
if (msgs[idx].flags & I2C_M_RD)
|
||||||
|
ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
|
||||||
|
else
|
||||||
|
ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
|
||||||
|
}
|
||||||
|
- } while ((idx++ < (num - 1)) && !use_dma && !ret);
|
||||||
|
+ } while ((idx++ < (num - 1)) && !ret);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
|
@ -0,0 +1,174 @@
|
|||||||
|
From 6d5f37f166bb07b04b4d42e9d1f5427b7931cd3c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:53 +0530
|
||||||
|
Subject: [PATCH 04/13] i2c: qup: remove redundant variables for BAM SG count
|
||||||
|
|
||||||
|
The rx_nents and tx_nents are redundant. rx_buf and tx_buf can
|
||||||
|
be used for total number of SG entries. Since rx_buf and tx_buf
|
||||||
|
give the impression that it is buffer instead of count so rename
|
||||||
|
it to tx_cnt and rx_cnt for giving it more meaningful variable
|
||||||
|
name.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||||
|
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 42 ++++++++++++++++--------------------
|
||||||
|
1 file changed, 18 insertions(+), 24 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -683,8 +683,8 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
struct dma_async_tx_descriptor *txd, *rxd = NULL;
|
||||||
|
int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
|
||||||
|
dma_cookie_t cookie_rx, cookie_tx;
|
||||||
|
- u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
|
||||||
|
- u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
|
||||||
|
+ u32 len, blocks, rem;
|
||||||
|
+ u32 i, tlen, tx_len, tx_cnt = 0, rx_cnt = 0, off = 0;
|
||||||
|
u8 *tags;
|
||||||
|
|
||||||
|
while (idx < num) {
|
||||||
|
@@ -698,9 +698,6 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
rem = msg->len - (blocks - 1) * limit;
|
||||||
|
|
||||||
|
if (msg->flags & I2C_M_RD) {
|
||||||
|
- rx_nents += (blocks * 2) + 1;
|
||||||
|
- tx_nents += 1;
|
||||||
|
-
|
||||||
|
while (qup->blk.pos < blocks) {
|
||||||
|
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||||
|
tags = &qup->start_tag.start[off + len];
|
||||||
|
@@ -708,14 +705,14 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
qup->blk.data_len -= tlen;
|
||||||
|
|
||||||
|
/* scratch buf to read the start and len tags */
|
||||||
|
- ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
|
||||||
|
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||||
|
&qup->brx.tag.start[0],
|
||||||
|
2, qup, DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
- ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
|
||||||
|
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||||
|
&msg->buf[limit * i],
|
||||||
|
tlen, qup,
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
|
@@ -725,7 +722,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
i++;
|
||||||
|
qup->blk.pos = i;
|
||||||
|
}
|
||||||
|
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||||
|
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||||
|
&qup->start_tag.start[off],
|
||||||
|
len, qup, DMA_TO_DEVICE);
|
||||||
|
if (ret)
|
||||||
|
@@ -733,28 +730,26 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
|
||||||
|
off += len;
|
||||||
|
/* scratch buf to read the BAM EOT and FLUSH tags */
|
||||||
|
- ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
|
||||||
|
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||||
|
&qup->brx.tag.start[0],
|
||||||
|
2, qup, DMA_FROM_DEVICE);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
- tx_nents += (blocks * 2);
|
||||||
|
-
|
||||||
|
while (qup->blk.pos < blocks) {
|
||||||
|
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||||
|
tags = &qup->start_tag.start[off + tx_len];
|
||||||
|
len = qup_i2c_set_tags(tags, qup, msg, 1);
|
||||||
|
qup->blk.data_len -= tlen;
|
||||||
|
|
||||||
|
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||||
|
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||||
|
tags, len,
|
||||||
|
qup, DMA_TO_DEVICE);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
tx_len += len;
|
||||||
|
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||||
|
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||||
|
&msg->buf[limit * i],
|
||||||
|
tlen, qup, DMA_TO_DEVICE);
|
||||||
|
if (ret)
|
||||||
|
@@ -766,26 +761,25 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
|
||||||
|
if (idx == (num - 1)) {
|
||||||
|
len = 1;
|
||||||
|
- if (rx_nents) {
|
||||||
|
+ if (rx_cnt) {
|
||||||
|
qup->btx.tag.start[0] =
|
||||||
|
QUP_BAM_INPUT_EOT;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
qup->btx.tag.start[len - 1] =
|
||||||
|
QUP_BAM_FLUSH_STOP;
|
||||||
|
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||||
|
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||||
|
&qup->btx.tag.start[0],
|
||||||
|
len, qup, DMA_TO_DEVICE);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
- tx_nents += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
msg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
- txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_nents,
|
||||||
|
+ txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_cnt,
|
||||||
|
DMA_MEM_TO_DEV,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
|
||||||
|
if (!txd) {
|
||||||
|
@@ -794,7 +788,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
goto desc_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!rx_nents) {
|
||||||
|
+ if (!rx_cnt) {
|
||||||
|
txd->callback = qup_i2c_bam_cb;
|
||||||
|
txd->callback_param = qup;
|
||||||
|
}
|
||||||
|
@@ -807,9 +801,9 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
|
||||||
|
dma_async_issue_pending(qup->btx.dma);
|
||||||
|
|
||||||
|
- if (rx_nents) {
|
||||||
|
+ if (rx_cnt) {
|
||||||
|
rxd = dmaengine_prep_slave_sg(qup->brx.dma, qup->brx.sg,
|
||||||
|
- rx_nents, DMA_DEV_TO_MEM,
|
||||||
|
+ rx_cnt, DMA_DEV_TO_MEM,
|
||||||
|
DMA_PREP_INTERRUPT);
|
||||||
|
if (!rxd) {
|
||||||
|
dev_err(qup->dev, "failed to get rx desc\n");
|
||||||
|
@@ -844,7 +838,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
goto desc_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (rx_nents)
|
||||||
|
+ if (rx_cnt)
|
||||||
|
writel(QUP_BAM_INPUT_EOT,
|
||||||
|
qup->base + QUP_OUT_FIFO_BASE);
|
||||||
|
|
||||||
|
@@ -862,10 +856,10 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
}
|
||||||
|
|
||||||
|
desc_err:
|
||||||
|
- dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE);
|
||||||
|
+ dma_unmap_sg(qup->dev, qup->btx.sg, tx_cnt, DMA_TO_DEVICE);
|
||||||
|
|
||||||
|
- if (rx_nents)
|
||||||
|
- dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents,
|
||||||
|
+ if (rx_cnt)
|
||||||
|
+ dma_unmap_sg(qup->dev, qup->brx.sg, rx_cnt,
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
return ret;
|
@ -0,0 +1,126 @@
|
|||||||
|
From c5adc0fa63a930e3313c74bb7c1d4d158130eb41 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:54 +0530
|
||||||
|
Subject: [PATCH 05/13] i2c: qup: schedule EOT and FLUSH tags at the end of
|
||||||
|
transfer
|
||||||
|
|
||||||
|
The role of FLUSH and EOT tag is to flush already scheduled
|
||||||
|
descriptors in BAM HW in case of error. EOT is required only
|
||||||
|
when descriptors are scheduled in RX FIFO. If all the messages
|
||||||
|
are WRITE, then only FLUSH tag will be used.
|
||||||
|
|
||||||
|
A single BAM transfer can have multiple read and write messages.
|
||||||
|
The EOT and FLUSH tags should be scheduled at the end of BAM HW
|
||||||
|
descriptors. Since the READ and WRITE can be present in any order
|
||||||
|
so for some of the cases, these tags are not being written
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
Following is one of the example
|
||||||
|
|
||||||
|
READ, READ, READ, READ
|
||||||
|
|
||||||
|
Currently EOT and FLUSH tags are being written after each READ.
|
||||||
|
If QUP gets NACK for first READ itself, then flush will be
|
||||||
|
triggered. It will look for first FLUSH tag in TX FIFO and will
|
||||||
|
stop there so only descriptors for first READ descriptors be
|
||||||
|
flushed. All the scheduled descriptors should be cleared to
|
||||||
|
generate BAM DMA completion.
|
||||||
|
|
||||||
|
Now this patch is scheduling FLUSH and EOT only once after all the
|
||||||
|
descriptors. So, flush will clear all the scheduled descriptors and
|
||||||
|
BAM will generate the completion interrupt.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Reviewed-by: Sricharan R <sricharan@codeaurora.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 39 ++++++++++++++++++++++--------------
|
||||||
|
1 file changed, 24 insertions(+), 15 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -551,7 +551,7 @@ static int qup_i2c_set_tags_smb(u16 addr
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
|
||||||
|
- struct i2c_msg *msg, int is_dma)
|
||||||
|
+ struct i2c_msg *msg)
|
||||||
|
{
|
||||||
|
u16 addr = i2c_8bit_addr_from_msg(msg);
|
||||||
|
int len = 0;
|
||||||
|
@@ -592,11 +592,6 @@ static int qup_i2c_set_tags(u8 *tags, st
|
||||||
|
else
|
||||||
|
tags[len++] = data_len;
|
||||||
|
|
||||||
|
- if ((msg->flags & I2C_M_RD) && last && is_dma) {
|
||||||
|
- tags[len++] = QUP_BAM_INPUT_EOT;
|
||||||
|
- tags[len++] = QUP_BAM_FLUSH_STOP;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -605,7 +600,7 @@ static int qup_i2c_issue_xfer_v2(struct
|
||||||
|
int data_len = 0, tag_len, index;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg, 0);
|
||||||
|
+ tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
|
||||||
|
index = msg->len - qup->blk.data_len;
|
||||||
|
|
||||||
|
/* only tags are written for read */
|
||||||
|
@@ -701,7 +696,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
while (qup->blk.pos < blocks) {
|
||||||
|
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||||
|
tags = &qup->start_tag.start[off + len];
|
||||||
|
- len += qup_i2c_set_tags(tags, qup, msg, 1);
|
||||||
|
+ len += qup_i2c_set_tags(tags, qup, msg);
|
||||||
|
qup->blk.data_len -= tlen;
|
||||||
|
|
||||||
|
/* scratch buf to read the start and len tags */
|
||||||
|
@@ -729,17 +724,11 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
off += len;
|
||||||
|
- /* scratch buf to read the BAM EOT and FLUSH tags */
|
||||||
|
- ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||||
|
- &qup->brx.tag.start[0],
|
||||||
|
- 2, qup, DMA_FROM_DEVICE);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
} else {
|
||||||
|
while (qup->blk.pos < blocks) {
|
||||||
|
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||||
|
tags = &qup->start_tag.start[off + tx_len];
|
||||||
|
- len = qup_i2c_set_tags(tags, qup, msg, 1);
|
||||||
|
+ len = qup_i2c_set_tags(tags, qup, msg);
|
||||||
|
qup->blk.data_len -= tlen;
|
||||||
|
|
||||||
|
ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||||
|
@@ -779,6 +768,26 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
msg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* schedule the EOT and FLUSH I2C tags */
|
||||||
|
+ len = 1;
|
||||||
|
+ if (rx_cnt) {
|
||||||
|
+ qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
|
||||||
|
+ len++;
|
||||||
|
+
|
||||||
|
+ /* scratch buf to read the BAM EOT and FLUSH tags */
|
||||||
|
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||||
|
+ &qup->brx.tag.start[0],
|
||||||
|
+ 2, qup, DMA_FROM_DEVICE);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP;
|
||||||
|
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], &qup->btx.tag.start[0],
|
||||||
|
+ len, qup, DMA_TO_DEVICE);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_cnt,
|
||||||
|
DMA_MEM_TO_DEV,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
|
@ -0,0 +1,33 @@
|
|||||||
|
From 7e6c35fe602df6821b3e7db5b1ba656162750fda Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:55 +0530
|
||||||
|
Subject: [PATCH 06/13] i2c: qup: fix the transfer length for BAM RX EOT FLUSH
|
||||||
|
tags
|
||||||
|
|
||||||
|
In case of FLUSH operation, BAM copies INPUT EOT FLUSH (0x94)
|
||||||
|
instead of normal EOT (0x93) tag in input data stream when an
|
||||||
|
input EOT tag is received during flush operation. So only one tag
|
||||||
|
will be written instead of 2 separate tags.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -774,10 +774,10 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
|
||||||
|
len++;
|
||||||
|
|
||||||
|
- /* scratch buf to read the BAM EOT and FLUSH tags */
|
||||||
|
+ /* scratch buf to read the BAM EOT FLUSH tags */
|
||||||
|
ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||||
|
&qup->brx.tag.start[0],
|
||||||
|
- 2, qup, DMA_FROM_DEVICE);
|
||||||
|
+ 1, qup, DMA_FROM_DEVICE);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
From 08f15963bc751bc818294c0f75a9aaca299c4052 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:57 +0530
|
||||||
|
Subject: [PATCH 08/13] i2c: qup: use the complete transfer length to choose
|
||||||
|
DMA mode
|
||||||
|
|
||||||
|
Currently each message length in complete transfer is being
|
||||||
|
checked for determining DMA mode and if any of the message length
|
||||||
|
is less than FIFO length then non DMA mode is being used which
|
||||||
|
will increase overhead. DMA can be used for any length and it
|
||||||
|
should be determined with complete transfer length. Now, this
|
||||||
|
patch selects DMA mode if the total length is greater than FIFO
|
||||||
|
length.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||||
|
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 13 +++++++------
|
||||||
|
1 file changed, 7 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -1300,7 +1300,8 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||||
|
int num)
|
||||||
|
{
|
||||||
|
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
|
||||||
|
- int ret, len, idx = 0;
|
||||||
|
+ int ret, idx = 0;
|
||||||
|
+ unsigned int total_len = 0;
|
||||||
|
|
||||||
|
qup->bus_err = 0;
|
||||||
|
qup->qup_err = 0;
|
||||||
|
@@ -1326,14 +1327,14 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
- len = (msgs[idx].len > qup->out_fifo_sz) ||
|
||||||
|
- (msgs[idx].len > qup->in_fifo_sz);
|
||||||
|
-
|
||||||
|
- if (is_vmalloc_addr(msgs[idx].buf) || !len)
|
||||||
|
+ if (is_vmalloc_addr(msgs[idx].buf))
|
||||||
|
break;
|
||||||
|
+
|
||||||
|
+ total_len += msgs[idx].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (idx == num)
|
||||||
|
+ if (idx == num && (total_len > qup->out_fifo_sz ||
|
||||||
|
+ total_len > qup->in_fifo_sz))
|
||||||
|
qup->use_dma = true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
|||||||
|
From ecb6e1e5f4352055a5761b945a833a925d51bf8d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:44:58 +0530
|
||||||
|
Subject: [PATCH 09/13] i2c: qup: change completion timeout according to
|
||||||
|
transfer length
|
||||||
|
|
||||||
|
Currently the completion timeout is being taken according to
|
||||||
|
maximum transfer length which is too high if SCL is operating in
|
||||||
|
high frequency. This patch calculates timeout on the basis of
|
||||||
|
one-byte transfer time and uses the same for completion timeout.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 13 ++++++++++---
|
||||||
|
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -121,8 +121,12 @@
|
||||||
|
#define MX_TX_RX_LEN SZ_64K
|
||||||
|
#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT)
|
||||||
|
|
||||||
|
-/* Max timeout in ms for 32k bytes */
|
||||||
|
-#define TOUT_MAX 300
|
||||||
|
+/*
|
||||||
|
+ * Minimum transfer timeout for i2c transfers in seconds. It will be added on
|
||||||
|
+ * the top of maximum transfer time calculated from i2c bus speed to compensate
|
||||||
|
+ * the overheads.
|
||||||
|
+ */
|
||||||
|
+#define TOUT_MIN 2
|
||||||
|
|
||||||
|
/* Default values. Use these if FW query fails */
|
||||||
|
#define DEFAULT_CLK_FREQ 100000
|
||||||
|
@@ -163,6 +167,7 @@ struct qup_i2c_dev {
|
||||||
|
int in_blk_sz;
|
||||||
|
|
||||||
|
unsigned long one_byte_t;
|
||||||
|
+ unsigned long xfer_timeout;
|
||||||
|
struct qup_i2c_block blk;
|
||||||
|
|
||||||
|
struct i2c_msg *msg;
|
||||||
|
@@ -849,7 +854,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||||
|
dma_async_issue_pending(qup->brx.dma);
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
|
||||||
|
+ if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) {
|
||||||
|
dev_err(qup->dev, "normal trans timed out\n");
|
||||||
|
ret = -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
@@ -1605,6 +1610,8 @@ nodma:
|
||||||
|
*/
|
||||||
|
one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
|
||||||
|
qup->one_byte_t = one_bit_t * 9;
|
||||||
|
+ qup->xfer_timeout = TOUT_MIN * HZ +
|
||||||
|
+ usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
|
||||||
|
|
||||||
|
dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
|
||||||
|
qup->in_blk_sz, qup->in_fifo_sz,
|
@ -0,0 +1,43 @@
|
|||||||
|
From f7714b4e451bdcb7918b9aad14af22684ceac638 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Date: Mon, 12 Mar 2018 18:45:00 +0530
|
||||||
|
Subject: [PATCH 11/13] i2c: qup: send NACK for last read sub transfers
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
According to I2c specification, “If a master-receiver sends a
|
||||||
|
repeated START condition, it sends a not-acknowledge (A) just
|
||||||
|
before the repeated START condition”. QUP v2 supports sending
|
||||||
|
of NACK without stop with QUP_TAG_V2_DATARD_NACK so added the
|
||||||
|
same.
|
||||||
|
|
||||||
|
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||||
|
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||||
|
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||||
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
---
|
||||||
|
drivers/i2c/busses/i2c-qup.c | 5 ++++-
|
||||||
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/i2c/busses/i2c-qup.c
|
||||||
|
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||||
|
@@ -104,6 +104,7 @@
|
||||||
|
#define QUP_TAG_V2_DATAWR 0x82
|
||||||
|
#define QUP_TAG_V2_DATAWR_STOP 0x83
|
||||||
|
#define QUP_TAG_V2_DATARD 0x85
|
||||||
|
+#define QUP_TAG_V2_DATARD_NACK 0x86
|
||||||
|
#define QUP_TAG_V2_DATARD_STOP 0x87
|
||||||
|
|
||||||
|
/* Status, Error flags */
|
||||||
|
@@ -606,7 +607,9 @@ static int qup_i2c_set_tags(u8 *tags, st
|
||||||
|
tags[len++] = QUP_TAG_V2_DATAWR_STOP;
|
||||||
|
} else {
|
||||||
|
if (msg->flags & I2C_M_RD)
|
||||||
|
- tags[len++] = QUP_TAG_V2_DATARD;
|
||||||
|
+ tags[len++] = qup->blk.pos == (qup->blk.count - 1) ?
|
||||||
|
+ QUP_TAG_V2_DATARD_NACK :
|
||||||
|
+ QUP_TAG_V2_DATARD;
|
||||||
|
else
|
||||||
|
tags[len++] = QUP_TAG_V2_DATAWR;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue