Hi Brendan,

here is my review. Only minor stuff, no real show-stopper.

> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 144cbadc7c72..280f84a0d7d1 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -326,6 +326,16 @@ config I2C_POWERMAC
>  
>  comment "I2C system bus drivers (mostly embedded / system-on-chip)"
>  
> +config I2C_ASPEED
> +     tristate "Aspeed I2C Controller"
> +     depends on ARCH_ASPEED

|| COMPILE_TEST?

> +     help
> +       If you say yes to this option, support will be included for the
> +       Aspeed I2C controller.
> +
> +       This driver can also be built as a module.  If so, the module
> +       will be called i2c-aspeed.
> +
>  config I2C_AT91
>       tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
>       depends on ARCH_AT91
> +struct aspeed_i2c_bus {
> +     struct i2c_adapter              adap;
> +     struct device                   *dev;
> +     void __iomem                    *base;
> +     /* Synchronizes I/O mem access to base. */
> +     spinlock_t                      lock;
> +     struct completion               cmd_complete;
> +     int                             irq;

'irq' not really needed, I'd think.

> +     unsigned long                   parent_clk_frequency;
> +     u32                             bus_frequency;
> +     /* Transaction state. */
> +     enum aspeed_i2c_master_state    master_state;
> +     struct i2c_msg                  *msgs;
> +     size_t                          buf_index;
> +     size_t                          msgs_index;
> +     size_t                          msgs_count;
> +     bool                            send_stop;
> +     int                             cmd_err;
> +     /* Protected only by i2c_lock_bus */
> +     int                             master_xfer_result;
> +};

...

> +static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
> +{
> +     unsigned long time_left, flags;
> +     int ret = 0;
> +     u32 command;
> +
> +     spin_lock_irqsave(&bus->lock, flags);
> +     command = readl(bus->base + ASPEED_I2C_CMD_REG);
> +
> +     if (command & ASPEED_I2CD_SDA_LINE_STS) {
> +             /* Bus is idle: no recovery needed. */
> +             if (command & ASPEED_I2CD_SCL_LINE_STS)
> +                     goto out;
> +             dev_dbg(bus->dev, "bus hung (state %x), attempting recovery\n",
> +                     command);
> +
> +             reinit_completion(&bus->cmd_complete);
> +             writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
> +             spin_unlock_irqrestore(&bus->lock, flags);
> +
> +             time_left = wait_for_completion_timeout(
> +                             &bus->cmd_complete, bus->adap.timeout);
> +
> +             spin_lock_irqsave(&bus->lock, flags);
> +             if (time_left == 0)
> +                     goto reset_out;
> +             else if (bus->cmd_err)
> +                     goto reset_out;
> +             /* Recovery failed. */
> +             else if (!(readl(bus->base + ASPEED_I2C_CMD_REG) &
> +                        ASPEED_I2CD_SCL_LINE_STS))
> +                     goto reset_out;
> +     /* Bus error. */
> +     } else {
> +             dev_dbg(bus->dev, "bus hung (state %x), attempting recovery\n",
> +                     command);

Same dbg message as in the condition? Move it out of the 'if'?

> +
> +             reinit_completion(&bus->cmd_complete);
> +             writel(ASPEED_I2CD_BUS_RECOVER_CMD,
> +                    bus->base + ASPEED_I2C_CMD_REG);

Out of interest: What does the RECOVER_CMD do?

> +             spin_unlock_irqrestore(&bus->lock, flags);
> +
> +             time_left = wait_for_completion_timeout(
> +                             &bus->cmd_complete, bus->adap.timeout);
> +
> +             spin_lock_irqsave(&bus->lock, flags);
> +             if (time_left == 0)
> +                     goto reset_out;
> +             else if (bus->cmd_err)
> +                     goto reset_out;
> +             /* Recovery failed. */
> +             else if (!(readl(bus->base + ASPEED_I2C_CMD_REG) &
> +                        ASPEED_I2CD_SDA_LINE_STS))
> +                     goto reset_out;
> +     }
> +
> +out:
> +     spin_unlock_irqrestore(&bus->lock, flags);
> +
> +     return ret;
> +
> +reset_out:
> +     spin_unlock_irqrestore(&bus->lock, flags);
> +
> +     return aspeed_i2c_reset(bus);
> +}

...

> +     case ASPEED_I2C_MASTER_INACTIVE:
> +             dev_err(bus->dev,
> +                     "master received interrupt 0x%08x, but is inactive",
> +                     irq_status);
> +             bus->cmd_err = -EIO;
> +             /* Do not STOP as we should be inactive. */
> +             goto out_complete;
> +     default:
> +             WARN(1, "unknown master state\n");
> +             bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> +             bus->cmd_err = -EIO;
> +             goto out_complete;
> +     }
> +error_and_stop:
> +     bus->cmd_err = -EIO;
> +     aspeed_i2c_do_stop(bus);
> +     goto out_no_complete;
> +out_complete:
> +     bus->msgs = NULL;
> +     if (bus->cmd_err)
> +             bus->master_xfer_result = bus->cmd_err;
> +     else
> +             bus->master_xfer_result = bus->msgs_index + 1;
> +     complete(&bus->cmd_complete);
> +out_no_complete:
> +     if (irq_status != status_ack)
> +             dev_err(bus->dev,
> +                     "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
> +                     irq_status, status_ack);
> +     spin_unlock(&bus->lock);
> +     return !!irq_status;
> +}

You return in the interrupt handler -EIO always in case of errors. Can
you check Documentation/i2c/fault-codes and see if you can follow those
guidelines? Especially ENXIO on NACK and EAGAIN...

> +
> +static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
> +{
> +     struct aspeed_i2c_bus *bus = dev_id;
> +
> +     if (aspeed_i2c_master_irq(bus))
> +             return IRQ_HANDLED;
> +     else
> +             return IRQ_NONE;

Ternary operator? Your choice, though...

And one more question: Why do you use adapter->algo_data instead of
i2c_{get|set}_adapdata?

Kind regards,

   Wolfram

Attachment: signature.asc
Description: PGP signature

Reply via email to