From patchwork Wed May 9 14:24:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akinobu Mita X-Patchwork-Id: 910897 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-i2c-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="MBtcFbou"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40gzCn53fGz9s47 for ; Thu, 10 May 2018 00:25:25 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934331AbeEIOZY (ORCPT ); Wed, 9 May 2018 10:25:24 -0400 Received: from mail-pg0-f67.google.com ([74.125.83.67]:35879 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933887AbeEIOZX (ORCPT ); Wed, 9 May 2018 10:25:23 -0400 Received: by mail-pg0-f67.google.com with SMTP id z70-v6so2551404pgz.3; Wed, 09 May 2018 07:25:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=zaukltMyFBN5+2Gw/OtqB1XqtQKLGhkJyprrZSf5Fi0=; b=MBtcFbouqTql4AqFgk9jjCxGvgwmARBMLywdcYdXR8nyOSJ9I1IFkVUbHU5sITe2rt /uzzmfTQszCP3FeSYnWfFy3OTo+GMEImRxL/dx3GWeVwBvPGk/kHHNaHRZwGfczi6pSx xWokI10xuOA/8ooBw5A/a9XNM6ZPRZR+jioQO+/LTNHoOePR9ukbsijCuieR/fKkeOct 5DSj1oRvkuvC/4LwjJbmx7jfx11OGSFL19zJkJtXxcGJdbMlHJjTYllg+E8/qJvshaO4 7D+78SNYbRDkAwxEi6mHZa5B34z/kb9iEjKeEA2ns7HbLuSn3BzQfRcWDQ+6EwsnFYH6 /sxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=zaukltMyFBN5+2Gw/OtqB1XqtQKLGhkJyprrZSf5Fi0=; b=prcQTpnw7FUoQrrL9924VD4XA9F4B2Ze+jYariQ+KMqwZWvOa4V+DpUgHi77qFQF0F hNw6Hz68W569zj9AHgfaZyk/uEVOsGHvWmmXLKSeyF9x1nYCpgTgbSPvrdG3td3Mnda4 B7Hn4Vk6pYo2N/59s5RD7/EciIisl2VPr66l+yHkhZq/53yc7zrXIKU/VWCTNB75vjTh h9SkrXMJaFaBgcjS/QJI/3XFml56xZfudNFjcoj8mdzFnXbHqjv+yaZolCNDnaZXPDwb OMk33YajpYTVYAnQ/rccwYwiN3yPoA432DNJAFCBUC2YOvsB7Z5B7IiaFwePPO9cl20i nd6A== X-Gm-Message-State: ALQs6tC7bAhhDTAL2ZB6ElG/AmYh4LI8ETsqc9I2mwiDrEBjNIYg/v2s XZouIEgQw0MGzmoKIcbJAi5LJw== X-Google-Smtp-Source: AB8JxZqqRKcNcX0Vzb7Q1aF9xHf7POuFf5iRsPnRs9IO3sjOVSbtlcBdAzxQJ8O0YVI4SEFNpCR/EQ== X-Received: by 10.98.238.21 with SMTP id e21mr39844929pfi.203.1525875922554; Wed, 09 May 2018 07:25:22 -0700 (PDT) Received: from localhost.localdomain ([240f:4:c2bc:1:31dd:d313:7a15:aa7]) by smtp.gmail.com with ESMTPSA id 76-v6sm2885140pge.75.2018.05.09.07.25.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 07:25:21 -0700 (PDT) From: Akinobu Mita To: linux-media@vger.kernel.org, linux-i2c@vger.kernel.org Cc: Akinobu Mita , Sebastian Reichel , Wolfram Sang , Jacopo Mondi , Laurent Pinchart , Hans Verkuil , Sakari Ailus , Mauro Carvalho Chehab Subject: [RFC PATCH] i2c: add I2C_M_FORCE_STOP Date: Wed, 9 May 2018 23:24:37 +0900 Message-Id: <1525875877-10164-1-git-send-email-akinobu.mita@gmail.com> X-Mailer: git-send-email 2.7.4 Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org 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 Cc: Wolfram Sang Cc: Jacopo Mondi Cc: Laurent Pinchart Cc: Hans Verkuil Cc: Sakari Ailus Cc: Mauro Carvalho Chehab Signed-off-by: Akinobu Mita Reviewed-by: Mauro Carvalho Chehab --- 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 */