mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-23 01:56:43 +08:00
i2c: i2c-qcom-geni: Parse Error correctly in i2c GSI mode
I2C driver currently reports "DMA txn failed" error even though it's NACK OR BUS_PROTO OR ARB_LOST. Detect NACK error when no device ACKs on the bus instead of generic transfer failure which doesn't give any specific clue. Make Changes inside i2c driver callback handler function i2c_gpi_cb_result() to parse these errors and make sure GSI driver stores the error status during error interrupt. Co-developed-by: Viken Dadhaniya <quic_vdadhani@quicinc.com> Signed-off-by: Viken Dadhaniya <quic_vdadhani@quicinc.com> Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
This commit is contained in:
parent
fa0327cd1b
commit
add2afca3e
@ -1076,7 +1076,17 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan,
|
||||
dev_dbg(gpii->gpi_dev->dev, "Residue %d\n", result.residue);
|
||||
|
||||
dma_cookie_complete(&vd->tx);
|
||||
dmaengine_desc_get_callback_invoke(&vd->tx, &result);
|
||||
if (gchan->protocol == QCOM_GPI_I2C) {
|
||||
struct dmaengine_desc_callback cb;
|
||||
struct gpi_i2c_result *i2c;
|
||||
|
||||
dmaengine_desc_get_callback(&vd->tx, &cb);
|
||||
i2c = cb.callback_param;
|
||||
i2c->status = compl_event->status;
|
||||
dmaengine_desc_callback_invoke(&cb, &result);
|
||||
} else {
|
||||
dmaengine_desc_get_callback_invoke(&vd->tx, &result);
|
||||
}
|
||||
|
||||
gpi_free_desc:
|
||||
spin_lock_irqsave(&gchan->vc.lock, flags);
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
@ -66,6 +67,7 @@ enum geni_i2c_err_code {
|
||||
GENI_TIMEOUT,
|
||||
};
|
||||
|
||||
#define I2C_DMA_TX_IRQ_MASK GENMASK(12, 5)
|
||||
#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
|
||||
<< 5)
|
||||
|
||||
@ -99,6 +101,7 @@ struct geni_i2c_dev {
|
||||
struct dma_chan *rx_c;
|
||||
bool gpi_mode;
|
||||
bool abort_done;
|
||||
struct gpi_i2c_result i2c_result;
|
||||
};
|
||||
|
||||
struct geni_i2c_desc {
|
||||
@ -484,9 +487,18 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
||||
|
||||
static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c = cb;
|
||||
struct gpi_i2c_result *i2c_res = cb;
|
||||
struct geni_i2c_dev *gi2c = container_of(i2c_res, struct geni_i2c_dev, i2c_result);
|
||||
u32 status;
|
||||
|
||||
if (result->result != DMA_TRANS_NOERROR) {
|
||||
status = FIELD_GET(I2C_DMA_TX_IRQ_MASK, i2c_res->status);
|
||||
if (status == BIT(NACK)) {
|
||||
geni_i2c_err(gi2c, NACK);
|
||||
} else if (status == BIT(BUS_PROTO)) {
|
||||
geni_i2c_err(gi2c, BUS_PROTO);
|
||||
} else if (status == BIT(ARB_LOST)) {
|
||||
geni_i2c_err(gi2c, ARB_LOST);
|
||||
} else if (result->result != DMA_TRANS_NOERROR) {
|
||||
dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result);
|
||||
gi2c->err = -EIO;
|
||||
} else if (result->residue) {
|
||||
@ -568,7 +580,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
||||
}
|
||||
|
||||
desc->callback_result = i2c_gpi_cb_result;
|
||||
desc->callback_param = gi2c;
|
||||
desc->callback_param = &gi2c->i2c_result;
|
||||
|
||||
dmaengine_submit(desc);
|
||||
*buf = dma_buf;
|
||||
|
@ -80,4 +80,14 @@ struct gpi_i2c_config {
|
||||
bool multi_msg;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gpi_i2c_result - i2c transfer status result in GSI mode
|
||||
*
|
||||
* @status: store txfer status value as part of callback
|
||||
*
|
||||
*/
|
||||
struct gpi_i2c_result {
|
||||
u32 status;
|
||||
};
|
||||
|
||||
#endif /* QCOM_GPI_DMA_H */
|
||||
|
Loading…
Reference in New Issue
Block a user