[PATCH v3 1/7] i2c: qcom-cci: Factor out write command queue programming
From: Loic Poulain
Date: Fri Oct 16 2026 - 04:04:15 EST
Factor out write-command queueing into a dedicated helper and replace
the manual byte-to-word packing code with iowrite32_rep().
The resulting code is easier to follow and will be reused by
upcoming burst-write support.
A command can only carry as many data bytes as fit in its words, so
validate the length before building one, and do so where an error can
still be returned. The I2C core already rejects a transfer longer than
the limit advertised through the adapter quirks, so this is only a
guard against building a command that would corrupt the queue.
Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxxxxxxxx>
---
drivers/i2c/busses/i2c-qcom-cci.c | 44 ++++++++++++++++++++++-----------------
1 file changed, 25 insertions(+), 19 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index d509dc1c14700d9c199d67df19082bae4f1ae470..5bec317c15deddc01d3f3a6418af4164c0d56fd9 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -77,6 +77,9 @@
#define CCI_I2C_WRITE 9
#define CCI_I2C_READ 10
+#define CCI_I2C_WRITE_WC 3
+#define CCI_I2C_WRITE_NWORDS(len) DIV_ROUND_UP((len) + 1, sizeof(u32))
+
#define CCI_I2C_REPORT_IRQ_EN BIT(8)
enum {
@@ -485,42 +488,45 @@ static int cci_i2c_read(struct cci *cci, u16 master,
return 0;
}
+static void cci_i2c_load_write(u8 *buf, u16 len, void __iomem *loadq)
+{
+ u32 cmd[CCI_I2C_WRITE_WC] = { };
+
+ cmd[0] = CCI_I2C_WRITE | len << 4;
+ memcpy((u8 *)cmd + 1, buf, len);
+ iowrite32_rep(loadq, cmd, CCI_I2C_WRITE_NWORDS(len));
+}
+
static int cci_i2c_write(struct cci *cci, u16 master,
u16 addr, u8 *buf, u16 len)
{
- u8 queue = QUEUE_0;
- u8 load[12] = { 0 };
- int i = 0, j, ret;
+ void __iomem *loadq = cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, QUEUE_0);
+ int ret;
u32 val;
+ dev_dbg(cci->dev, "master %d write: len=%u\n", master, len);
+
+ /* This condition should be guaranteed by the caller (i2c core) */
+ if (WARN_ON(len > cci->data->quirks.max_write_len))
+ return -EOPNOTSUPP;
+
/*
* Call validate queue to make sure queue is empty before starting.
* This is to avoid overflow / underflow of queue.
*/
- ret = cci_validate_queue(cci, master, queue);
+ ret = cci_validate_queue(cci, master, QUEUE_0);
if (ret < 0)
return ret;
val = CCI_I2C_SET_PARAM | (addr & 0x7f) << 4;
- writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
+ writel(val, loadq);
- load[i++] = CCI_I2C_WRITE | len << 4;
-
- for (j = 0; j < len; j++)
- load[i++] = buf[j];
-
- for (j = 0; j < i; j += 4) {
- val = load[j];
- val |= load[j + 1] << 8;
- val |= load[j + 2] << 16;
- val |= load[j + 3] << 24;
- writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
- }
+ cci_i2c_load_write(buf, len, loadq);
val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN;
- writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
+ writel(val, loadq);
- return cci_run_queue(cci, master, queue);
+ return cci_run_queue(cci, master, QUEUE_0);
}
static int cci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
--
2.34.1