Skip to content

Commit e1d9326

Browse files
committed
Merge tag 'i2c-for-6.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang: - IMX: fix stop condition in single master mode and add compatible string for errata adherence - Microchip: Add support for proper repeated sends and fix unnecessary NAKs on empty messages, which caused false bus detection * tag 'i2c-for-6.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: i2c: microchip-core: fix "ghost" detections i2c: microchip-core: actually use repeated sends i2c: imx: add imx7d compatible string for applying erratum ERR007805 i2c: imx: fix missing stop condition in single-master mode
2 parents 059dd50 + f802f11 commit e1d9326

File tree

2 files changed

+98
-33
lines changed

2 files changed

+98
-33
lines changed

drivers/i2c/busses/i2c-imx.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
335335
{ .compatible = "fsl,imx6sll-i2c", .data = &imx6_i2c_hwdata, },
336336
{ .compatible = "fsl,imx6sx-i2c", .data = &imx6_i2c_hwdata, },
337337
{ .compatible = "fsl,imx6ul-i2c", .data = &imx6_i2c_hwdata, },
338+
{ .compatible = "fsl,imx7d-i2c", .data = &imx6_i2c_hwdata, },
338339
{ .compatible = "fsl,imx7s-i2c", .data = &imx6_i2c_hwdata, },
339340
{ .compatible = "fsl,imx8mm-i2c", .data = &imx6_i2c_hwdata, },
340341
{ .compatible = "fsl,imx8mn-i2c", .data = &imx6_i2c_hwdata, },
@@ -532,22 +533,20 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
532533

533534
static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic)
534535
{
536+
bool multi_master = i2c_imx->multi_master;
535537
unsigned long orig_jiffies = jiffies;
536538
unsigned int temp;
537539

538-
if (!i2c_imx->multi_master)
539-
return 0;
540-
541540
while (1) {
542541
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
543542

544543
/* check for arbitration lost */
545-
if (temp & I2SR_IAL) {
544+
if (multi_master && (temp & I2SR_IAL)) {
546545
i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
547546
return -EAGAIN;
548547
}
549548

550-
if (for_busy && (temp & I2SR_IBB)) {
549+
if (for_busy && (!multi_master || (temp & I2SR_IBB))) {
551550
i2c_imx->stopped = 0;
552551
break;
553552
}

drivers/i2c/busses/i2c-microchip-corei2c.c

Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,27 +93,35 @@
9393
* @base: pointer to register struct
9494
* @dev: device reference
9595
* @i2c_clk: clock reference for i2c input clock
96+
* @msg_queue: pointer to the messages requiring sending
9697
* @buf: pointer to msg buffer for easier use
9798
* @msg_complete: xfer completion object
9899
* @adapter: core i2c abstraction
99100
* @msg_err: error code for completed message
100101
* @bus_clk_rate: current i2c bus clock rate
101102
* @isr_status: cached copy of local ISR status
103+
* @total_num: total number of messages to be sent/received
104+
* @current_num: index of the current message being sent/received
102105
* @msg_len: number of bytes transferred in msg
103106
* @addr: address of the current slave
107+
* @restart_needed: whether or not a repeated start is required after current message
104108
*/
105109
struct mchp_corei2c_dev {
106110
void __iomem *base;
107111
struct device *dev;
108112
struct clk *i2c_clk;
113+
struct i2c_msg *msg_queue;
109114
u8 *buf;
110115
struct completion msg_complete;
111116
struct i2c_adapter adapter;
112117
int msg_err;
118+
int total_num;
119+
int current_num;
113120
u32 bus_clk_rate;
114121
u32 isr_status;
115122
u16 msg_len;
116123
u8 addr;
124+
bool restart_needed;
117125
};
118126

119127
static void mchp_corei2c_core_disable(struct mchp_corei2c_dev *idev)
@@ -222,6 +230,47 @@ static int mchp_corei2c_fill_tx(struct mchp_corei2c_dev *idev)
222230
return 0;
223231
}
224232

233+
static void mchp_corei2c_next_msg(struct mchp_corei2c_dev *idev)
234+
{
235+
struct i2c_msg *this_msg;
236+
u8 ctrl;
237+
238+
if (idev->current_num >= idev->total_num) {
239+
complete(&idev->msg_complete);
240+
return;
241+
}
242+
243+
/*
244+
* If there's been an error, the isr needs to return control
245+
* to the "main" part of the driver, so as not to keep sending
246+
* messages once it completes and clears the SI bit.
247+
*/
248+
if (idev->msg_err) {
249+
complete(&idev->msg_complete);
250+
return;
251+
}
252+
253+
this_msg = idev->msg_queue++;
254+
255+
if (idev->current_num < (idev->total_num - 1)) {
256+
struct i2c_msg *next_msg = idev->msg_queue;
257+
258+
idev->restart_needed = next_msg->flags & I2C_M_RD;
259+
} else {
260+
idev->restart_needed = false;
261+
}
262+
263+
idev->addr = i2c_8bit_addr_from_msg(this_msg);
264+
idev->msg_len = this_msg->len;
265+
idev->buf = this_msg->buf;
266+
267+
ctrl = readb(idev->base + CORE_I2C_CTRL);
268+
ctrl |= CTRL_STA;
269+
writeb(ctrl, idev->base + CORE_I2C_CTRL);
270+
271+
idev->current_num++;
272+
}
273+
225274
static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)
226275
{
227276
u32 status = idev->isr_status;
@@ -238,19 +287,21 @@ static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)
238287
ctrl &= ~CTRL_STA;
239288
writeb(idev->addr, idev->base + CORE_I2C_DATA);
240289
writeb(ctrl, idev->base + CORE_I2C_CTRL);
241-
if (idev->msg_len == 0)
242-
finished = true;
243290
break;
244291
case STATUS_M_ARB_LOST:
245292
idev->msg_err = -EAGAIN;
246293
finished = true;
247294
break;
248295
case STATUS_M_SLAW_ACK:
249296
case STATUS_M_TX_DATA_ACK:
250-
if (idev->msg_len > 0)
297+
if (idev->msg_len > 0) {
251298
mchp_corei2c_fill_tx(idev);
252-
else
253-
last_byte = true;
299+
} else {
300+
if (idev->restart_needed)
301+
finished = true;
302+
else
303+
last_byte = true;
304+
}
254305
break;
255306
case STATUS_M_TX_DATA_NACK:
256307
case STATUS_M_SLAR_NACK:
@@ -287,7 +338,7 @@ static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)
287338
mchp_corei2c_stop(idev);
288339

289340
if (last_byte || finished)
290-
complete(&idev->msg_complete);
341+
mchp_corei2c_next_msg(idev);
291342

292343
return IRQ_HANDLED;
293344
}
@@ -311,21 +362,48 @@ static irqreturn_t mchp_corei2c_isr(int irq, void *_dev)
311362
return ret;
312363
}
313364

314-
static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev,
315-
struct i2c_msg *msg)
365+
static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
366+
int num)
316367
{
317-
u8 ctrl;
368+
struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap);
369+
struct i2c_msg *this_msg = msgs;
318370
unsigned long time_left;
371+
u8 ctrl;
372+
373+
mchp_corei2c_core_enable(idev);
374+
375+
/*
376+
* The isr controls the flow of a transfer, this info needs to be saved
377+
* to a location that it can access the queue information from.
378+
*/
379+
idev->restart_needed = false;
380+
idev->msg_queue = msgs;
381+
idev->total_num = num;
382+
idev->current_num = 0;
319383

320-
idev->addr = i2c_8bit_addr_from_msg(msg);
321-
idev->msg_len = msg->len;
322-
idev->buf = msg->buf;
384+
/*
385+
* But the first entry to the isr is triggered by the start in this
386+
* function, so the first message needs to be "dequeued".
387+
*/
388+
idev->addr = i2c_8bit_addr_from_msg(this_msg);
389+
idev->msg_len = this_msg->len;
390+
idev->buf = this_msg->buf;
323391
idev->msg_err = 0;
324392

325-
reinit_completion(&idev->msg_complete);
393+
if (idev->total_num > 1) {
394+
struct i2c_msg *next_msg = msgs + 1;
326395

327-
mchp_corei2c_core_enable(idev);
396+
idev->restart_needed = next_msg->flags & I2C_M_RD;
397+
}
328398

399+
idev->current_num++;
400+
idev->msg_queue++;
401+
402+
reinit_completion(&idev->msg_complete);
403+
404+
/*
405+
* Send the first start to pass control to the isr
406+
*/
329407
ctrl = readb(idev->base + CORE_I2C_CTRL);
330408
ctrl |= CTRL_STA;
331409
writeb(ctrl, idev->base + CORE_I2C_CTRL);
@@ -335,20 +413,8 @@ static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev,
335413
if (!time_left)
336414
return -ETIMEDOUT;
337415

338-
return idev->msg_err;
339-
}
340-
341-
static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
342-
int num)
343-
{
344-
struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap);
345-
int i, ret;
346-
347-
for (i = 0; i < num; i++) {
348-
ret = mchp_corei2c_xfer_msg(idev, msgs++);
349-
if (ret)
350-
return ret;
351-
}
416+
if (idev->msg_err)
417+
return idev->msg_err;
352418

353419
return num;
354420
}

0 commit comments

Comments
 (0)