@@ -249,18 +249,46 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
249
249
if (!slave )
250
250
return 0 ;
251
251
252
- command = readl (bus -> base + ASPEED_I2C_CMD_REG );
252
+ /*
253
+ * Handle stop conditions early, prior to SLAVE_MATCH. Some masters may drive
254
+ * transfers with low enough latency between the nak/stop phase of the current
255
+ * command and the start/address phase of the following command that the
256
+ * interrupts are coalesced by the time we process them.
257
+ */
258
+ if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP ) {
259
+ irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP ;
260
+ bus -> slave_state = ASPEED_I2C_SLAVE_STOP ;
261
+ }
262
+
263
+ if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
264
+ bus -> slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED ) {
265
+ irq_handled |= ASPEED_I2CD_INTR_TX_NAK ;
266
+ bus -> slave_state = ASPEED_I2C_SLAVE_STOP ;
267
+ }
268
+
269
+ /* Propagate any stop conditions to the slave implementation. */
270
+ if (bus -> slave_state == ASPEED_I2C_SLAVE_STOP ) {
271
+ i2c_slave_event (slave , I2C_SLAVE_STOP , & value );
272
+ bus -> slave_state = ASPEED_I2C_SLAVE_INACTIVE ;
273
+ }
253
274
254
- /* Slave was requested, restart state machine. */
275
+ /*
276
+ * Now that we've dealt with any potentially coalesced stop conditions,
277
+ * address any start conditions.
278
+ */
255
279
if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH ) {
256
280
irq_handled |= ASPEED_I2CD_INTR_SLAVE_MATCH ;
257
281
bus -> slave_state = ASPEED_I2C_SLAVE_START ;
258
282
}
259
283
260
- /* Slave is not currently active, irq was for someone else. */
284
+ /*
285
+ * If the slave has been stopped and not started then slave interrupt
286
+ * handling is complete.
287
+ */
261
288
if (bus -> slave_state == ASPEED_I2C_SLAVE_INACTIVE )
262
289
return irq_handled ;
263
290
291
+ command = readl (bus -> base + ASPEED_I2C_CMD_REG );
264
292
dev_dbg (bus -> dev , "slave irq status 0x%08x, cmd 0x%08x\n" ,
265
293
irq_status , command );
266
294
@@ -279,17 +307,6 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
279
307
irq_handled |= ASPEED_I2CD_INTR_RX_DONE ;
280
308
}
281
309
282
- /* Slave was asked to stop. */
283
- if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP ) {
284
- irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP ;
285
- bus -> slave_state = ASPEED_I2C_SLAVE_STOP ;
286
- }
287
- if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
288
- bus -> slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED ) {
289
- irq_handled |= ASPEED_I2CD_INTR_TX_NAK ;
290
- bus -> slave_state = ASPEED_I2C_SLAVE_STOP ;
291
- }
292
-
293
310
switch (bus -> slave_state ) {
294
311
case ASPEED_I2C_SLAVE_READ_REQUESTED :
295
312
if (unlikely (irq_status & ASPEED_I2CD_INTR_TX_ACK ))
@@ -324,8 +341,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
324
341
i2c_slave_event (slave , I2C_SLAVE_WRITE_RECEIVED , & value );
325
342
break ;
326
343
case ASPEED_I2C_SLAVE_STOP :
327
- i2c_slave_event (slave , I2C_SLAVE_STOP , & value );
328
- bus -> slave_state = ASPEED_I2C_SLAVE_INACTIVE ;
344
+ /* Stop event handling is done early. Unreachable. */
329
345
break ;
330
346
case ASPEED_I2C_SLAVE_START :
331
347
/* Slave was just started. Waiting for the next event. */ ;
0 commit comments