Re: [PATCH v5] i2c: add driver for Rockchip RK3xxx SoC I2C adapter

From: Wolfram Sang
Date: Tue Jun 10 2014 - 15:27:21 EST


Hi,

On Sat, Jun 07, 2014 at 07:36:19PM +0200, Max Schwarz wrote:
> Driver for the native I2C adapter found in Rockchip RK3xxx SoCs.
>
> Configuration is only possible through devicetree. The driver is
> interrupt driven and supports the I2C_M_IGNORE_NAK mangling bit.
>
> Signed-off-by: Max Schwarz <max.schwarz@xxxxxxxxx>

Checking if the spinlock is needed would be nice, but we can also fix
this later. Besides this, my code-checkers say:

CHECKPATCH
CHECK: Logical continuations should be on the previous line
#615: FILE: drivers/i2c/busses/i2c-rk3x.c:470:
+ if (num >= 2 && msgs[0].len < 4
+ && !(msgs[0].flags & I2C_M_RD)

CHECK: Logical continuations should be on the previous line
#616: FILE: drivers/i2c/busses/i2c-rk3x.c:471:
+ && !(msgs[0].flags & I2C_M_RD)
+ && (msgs[1].flags & I2C_M_RD)) {

SPARSE
drivers/i2c/busses/i2c-rk3x.c:173:20: warning: Using plain integer as NULL pointer
drivers/i2c/busses/i2c-rk3x.c:664:45: warning: Using plain integer as NULL pointer
drivers/i2c/busses/i2c-rk3x.c:735:9: warning: cast removes address space of expression
SMATCH
drivers/i2c/busses/i2c-rk3x.c:592 rk3x_i2c_xfer() error: double unlock 'spin_lock:&i2c->lock'
SPATCH
drivers/i2c/busses/i2c-rk3x.c:366:1-10: WARNING: Assignment of bool to 0/1
drivers/i2c/busses/i2c-rk3x.c:187:2-11: WARNING: Assignment of bool to 0/1
CC drivers/i2c/busses/i2c-rk3x.o
drivers/i2c/busses/i2c-rk3x.c: In function 'rk3x_i2c_irq':
drivers/i2c/busses/i2c-rk3x.c:336:15: warning: 'val' may be used uninitialized in this function [-Wuninitialized]
drivers/i2c/busses/i2c-rk3x.c:321:15: note: 'val' was declared here

The smatch warning may be a false positive, please check. The gcc warning is a
false positive but to prevent people from sending fixup patches, please do
something like commit a55b44ac3fe0.

> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> new file mode 100644
> index 0000000..7a430f4
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -0,0 +1,769 @@
> +/*
> + * Driver for I2C adapter in Rockchip RK3xxx SoC
> + *
> + * Max Schwarz <max.schwarz@xxxxxxxxx>
> + * based on the patches by Rockchip Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +

No empty line here.

> +#include <linux/i2c.h>
> +#include <linux/time.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/spinlock.h>
> +#include <linux/clk.h>
> +#include <linux/wait.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>

Do you really need delay.h and time.h? Look like leftovers to me.

> +/**
> + * Generate a START condition, which triggers a REG_INT_START interrupt.
> + */
> +static void rk3x_i2c_start(struct rk3x_i2c *i2c)
> +{
> + u32 val;
> +
> + dev_dbg(i2c->dev, "start\n");

I think this debug could go now, or?

> +
> + rk3x_i2c_clean_ipd(i2c);
> + i2c_writel(i2c, REG_INT_START, REG_IEN);
> +
> + /* enable adapter with correct mode, send START condition */
> + val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
> +
> + /* if we want to react to NACK, set ACTACK bit */
> + if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
> + val |= REG_CON_ACTACK;
> +
> + i2c_writel(i2c, val, REG_CON);
> +}

...

> +
> +static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
> +{
> + unsigned int len = i2c->msg->len - i2c->processed;
> + u32 con;
> +
> + con = i2c_readl(i2c, REG_CON);
> +
> + /*
> + * The hw can read up to 32 bytes at a time. If we need more than one
> + * chunk, send an ACK after the last byte of the current chunk.
> + */
> + if (unlikely(len > 32)) {
> + len = 32;
> + con &= ~REG_CON_LASTACK;
> + } else {
> + con |= REG_CON_LASTACK;
> + }

This is a bit confusing also due to the description of this bit:
"/* 1: do not send ACK after last receive */"

It means not only don't send ACK, but merely do send NACK (to signal end of
read). I though "not send ack" means clock stretching so I was wondering. Maybe
needs some rewording.

> +
> + /* make sure we are in plain RX mode if we read a second chunk */
> + if (i2c->processed != 0) {
> + con &= ~REG_CON_MOD_MASK;
> + con |= REG_CON_MOD(REG_CON_MOD_RX);
> + }
> +
> + i2c_writel(i2c, con, REG_CON);
> + i2c_writel(i2c, len, REG_MRXCNT);
> +}
> +

Thanks, I think we're very close to go...

Wolfram

Attachment: signature.asc
Description: Digital signature