Em Wed, 9 May 2018 23:24:37 +0900
Akinobu Mita <[email protected]> escreveu:
> This adds a new I2C_M_FORCE_STOP flag that forces a stop condition after
> the message in a combined transaction.
>
> This flag is intended to be used by the devices that don't support
> repeated starts like SCCB (Serial Camera Control Bus) devices.
>
> Here is an example usage for ov772x driver that needs to issue two
> separated I2C messages as the ov772x device doesn't support repeated
> starts.
>
> static int ov772x_read(struct i2c_client *client, u8 addr)
> {
> u8 val;
> struct i2c_msg msg[] = {
> {
> .addr = client->addr,
> .flags = I2C_M_FORCE_STOP,
> .len = 1,
> .buf = &addr,
> },
> {
> .addr = client->addr,
> .flags = I2C_M_RD,
> .len = 1,
> .buf = &val,
> },
> };
> int ret;
>
> ret = i2c_transfer(client->adapter, msg, 2);
> if (ret != 2)
> return (ret < 0) ? ret : -EIO;
>
> return val;
> }
>
> This is another approach based on Mauro's advise for the initial attempt
> (http://patchwork.ozlabs.org/patch/905192/).
>
> Cc: Sebastian Reichel <[email protected]>
> Cc: Wolfram Sang <[email protected]>
> Cc: Jacopo Mondi <[email protected]>
> Cc: Laurent Pinchart <[email protected]>
> Cc: Hans Verkuil <[email protected]>
> Cc: Sakari Ailus <[email protected]>
> Cc: Mauro Carvalho Chehab <[email protected]>
> Signed-off-by: Akinobu Mita <[email protected]>
Patch looks good to me.
Reviewed-by: Mauro Carvalho Chehab <[email protected]>
> ---
> drivers/i2c/i2c-core-base.c | 46
> ++++++++++++++++++++++++++++++++++-----------
> include/uapi/linux/i2c.h | 1 +
> 2 files changed, 36 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
> index 1ba40bb..6b73484 100644
> --- a/drivers/i2c/i2c-core-base.c
> +++ b/drivers/i2c/i2c-core-base.c
> @@ -1828,6 +1828,25 @@ static int i2c_check_for_quirks(struct i2c_adapter
> *adap, struct i2c_msg *msgs,
> return 0;
> }
>
> +static int i2c_transfer_nolock(struct i2c_adapter *adap, struct i2c_msg
> *msgs,
> + int num)
> +{
> + unsigned long orig_jiffies;
> + int ret, try;
> +
> + /* Retry automatically on arbitration loss */
> + orig_jiffies = jiffies;
> + for (ret = 0, try = 0; try <= adap->retries; try++) {
> + ret = adap->algo->master_xfer(adap, msgs, num);
> + if (ret != -EAGAIN)
> + break;
> + if (time_after(jiffies, orig_jiffies + adap->timeout))
> + break;
> + }
> +
> + return ret;
> +}
> +
> /**
> * __i2c_transfer - unlocked flavor of i2c_transfer
> * @adap: Handle to I2C bus
> @@ -1842,8 +1861,8 @@ static int i2c_check_for_quirks(struct i2c_adapter
> *adap, struct i2c_msg *msgs,
> */
> int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> {
> - unsigned long orig_jiffies;
> - int ret, try;
> + int ret;
> + int i, n;
>
> if (WARN_ON(!msgs || num < 1))
> return -EINVAL;
> @@ -1857,7 +1876,6 @@ int __i2c_transfer(struct i2c_adapter *adap, struct
> i2c_msg *msgs, int num)
> * being executed when not needed.
> */
> if (static_branch_unlikely(&i2c_trace_msg_key)) {
> - int i;
> for (i = 0; i < num; i++)
> if (msgs[i].flags & I2C_M_RD)
> trace_i2c_read(adap, &msgs[i], i);
> @@ -1865,18 +1883,24 @@ int __i2c_transfer(struct i2c_adapter *adap, struct
> i2c_msg *msgs, int num)
> trace_i2c_write(adap, &msgs[i], i);
> }
>
> - /* Retry automatically on arbitration loss */
> - orig_jiffies = jiffies;
> - for (ret = 0, try = 0; try <= adap->retries; try++) {
> - ret = adap->algo->master_xfer(adap, msgs, num);
> - if (ret != -EAGAIN)
> - break;
> - if (time_after(jiffies, orig_jiffies + adap->timeout))
> + for (i = 0; i < num; i += n) {
> + for (n = 0; i + n < num; n++) {
> + if (msgs[i + n].flags & I2C_M_FORCE_STOP) {
> + n++;
> + break;
> + }
> + }
> +
> + ret = i2c_transfer_nolock(adap, &msgs[i], n);
> + if (ret != n) {
> + if (i > 0)
> + ret = (ret < 0) ? i : i + ret;
> break;
> + }
> + ret = i + n;
> }
>
> if (static_branch_unlikely(&i2c_trace_msg_key)) {
> - int i;
> for (i = 0; i < ret; i++)
> if (msgs[i].flags & I2C_M_RD)
> trace_i2c_reply(adap, &msgs[i], i);
> diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
> index f71a175..36e8c7c 100644
> --- a/include/uapi/linux/i2c.h
> +++ b/include/uapi/linux/i2c.h
> @@ -72,6 +72,7 @@ struct i2c_msg {
> #define I2C_M_RD 0x0001 /* read data, from slave to master */
> /* I2C_M_RD is guaranteed to be 0x0001!
> */
> #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
> +#define I2C_M_FORCE_STOP 0x0100 /* force a stop condition after the
> message */
> #define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message
> is DMA safe */
> /* makes only sense in kernelspace */
> /* userspace buffers are copied anyway
> */
Thanks,
Mauro