On 14/04/21 1:52 am, Andy Shevchenko wrote: > On Tue, Apr 13, 2021 at 8:10 AM Chris Packham > <chris.packham@xxxxxxxxxxxxxxxxxxx> wrote: >> The fsl-i2c controller will generate an interrupt after every byte >> transferred. Make use of this interrupt to drive a state machine which >> allows the next part of a transfer to happen as soon as the interrupt is >> received. This is particularly helpful with SMBUS devices like the LM81 >> which will timeout if we take too long between bytes in a transfer. > Also see my other comments below. > > ... > >> +// SPDX-License-Identifier: GPL-2.0 > I think it is better to split this with a removal of old stuff and > updating a copyright notice and go as a last one in the series. > > ... Have split out into new patch. >> +static char *action_str[] = { > static const char * const action_str[] Ack. >> + "invalid", >> + "start", >> + "restart", >> + "read begin", >> + "read", >> + "write", >> + "stop", >> +}; > ... > >> + dev_dbg(i2c->dev, "%s: action = %s\n", __func__, >> + action_str[i2c->action]); > Drop useless __func__. With Dynamic Debug enabled it can be turned on > and off at run time. Ack. Other instances of __func__ also. > > ... > >> + /* Generate txack on next to last byte */ > Tx ACK ? Ditto for other comments. > > ... ACK. > >> + dev_dbg(i2c->dev, "%s: %s %02x\n", __func__, >> + action_str[i2c->action], byte); > You already printed action. Anything changed? It's mainly the addition of the byte read. I couldn't figure out a sensible way of always printing the action then appending the data in the read/write case. Open to suggestions. > >> + dev_dbg(i2c->dev, "%s: %s %02x\n", __func__, >> + action_str[i2c->action], msg->buf[i2c->byte_posn]); > Deduplicate this. Perhaps at the end of switch-case print once with > whatever temporary variable value you want to. > > ... I thought about this but decided not to because in the write case it's printed before going to hardware and in the read case it's after. If I moved it after the case I'd have to use something other than i2c->byte_posn which seemed error prone. > >> + case MPC_I2C_ACTION_INVALID: >> + default: > Does the first one deserve loud WARN? > Otherwise, why is it defined at all? I added MPC_I2C_ACTION_INVALID to make sure that a value of 0 was not something that would naturally happen via a zeroed initialization. I could probably achieve the same thing by making MPC_I2C_ACTION_START = 1. >> + WARN(1, "Unexpected action %d\n", i2c->action); >> + break; > ... > >> +static void mpc_i2c_do_intr(struct mpc_i2c *i2c, u8 status) >> { >> + spin_lock_irqsave(&i2c->lock, flags); > Why _irqsave? > > ... Primarily because it's the only one I've ever used and it was the one similar i2c drivers used when I started this work. I see they've now been updated so I don't think there will be a problem switching to spin_lock(). >> + dev_dbg(i2c->dev, "arbiritration lost\n"); > arbitration Ack. > ... > >> + if (i2c->expect_rxack && (status & CSR_RXAK)) { >> + dev_dbg(i2c->dev, "no RXAK\n"); > You see, you have to be consistent in comments and messages. > Either use TXAK/RXAK, or more verbose 'Tx ACK/Rx ACK' everywhere. > > ... Updated to "Rx ACK". I think I've got them all now. > >> +out: > out_unlock: > >> + spin_unlock_irqrestore(&i2c->lock, flags); > ... > >> +static irqreturn_t mpc_i2c_isr(int irq, void *dev_id) >> +{ >> + struct mpc_i2c *i2c = dev_id; >> + u8 status = readb(i2c->base + MPC_I2C_SR); > I would split this assignment, so it will be closer to its user. Ack. >> + if (status & CSR_MIF) { >> + writeb(0, i2c->base + MPC_I2C_SR); >> + mpc_i2c_do_intr(i2c, status); >> + return IRQ_HANDLED; >> } >> + return IRQ_NONE; >> +} > ... > >> + time_left = wait_event_timeout(i2c->waitq, !i2c->block, i2c->adap.timeout); >> + > No need for a blank line here. Ack. >> + if (!time_left) >> + i2c->rc = -ETIMEDOUT; >> + else if (time_left < 0) > Redundant 'else' Ack. >> + i2c->rc = time_left; > Can't you return an error code from here, rather than injecting it > somewhere where it doesn't belong to? Yes I think so. If I make mpc_i2c_wait_for_completion() return an int then have mpc_i2c_execute_msg() check it and set i2c->rc if needed. >> } > -- > With Best Regards, > Andy Shevchenko