From patchwork Mon Sep 30 06:44:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rayagonda Kokatanur X-Patchwork-Id: 11166107 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 18D7D912 for ; Mon, 30 Sep 2019 06:49:54 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EA95E206C0 for ; Mon, 30 Sep 2019 06:49:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Y9aa0sxO"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="abvY2T4r" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EA95E206C0 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=broadcom.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=7XSgnZjDkB6CyFFiI9oTvKzRxdSGk3ky+mcKC+K/2AU=; b=Y9a a0sxO41O310bdEh/iKAV20N6IG2EF7J9RYJBF4zb4gUv4U+dbYJoKecFS0eVwDKAkl7qpvqi/sYxj 1Iqz62Zo5YQNr2vlqNshjK3CmsJbwF8LUPXLqyz6WpvLvxZnwp00RYGwAyImBBzS9bj+ResR7ggbN Bj/XdCN0+wKjNvxmnOUBnIDBE7IRIUbvayholFumMZoy/cmTROEXtvVknwg5rWlEeuvjapL/5HWXz wGPjOTs9vaH3uUR++W0+1sFFTQx0JVyU9RnQErg9WL6O4uajDr1W6WeaeR8E/JW69zc3f+BzcWXj8 ORXuDow5lmCUaNVoYqTd7pVsWExDd7w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.2 #3 (Red Hat Linux)) id 1iEpVF-0003K2-HC; Mon, 30 Sep 2019 06:49:49 +0000 Received: from mail-pg1-x543.google.com ([2607:f8b0:4864:20::543]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iEpVC-0003JF-Vv for linux-arm-kernel@lists.infradead.org; Mon, 30 Sep 2019 06:49:48 +0000 Received: by mail-pg1-x543.google.com with SMTP id y35so6856349pgl.1 for ; Sun, 29 Sep 2019 23:49:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id; bh=hbbHzY2mGN6GVRxX5qIoZkQRWZNUdeV1dB8ZZwNAXLY=; b=abvY2T4rdd8Vnv2F3AiA9oFrTeKJQxXAc3uROdDGqfG1CdXfeOnyCz1oQmmAfw1jGa 1oXroO/ZhhuIFL3ACdklnPMAbSUhUC9Y/yRzdkc9qfSIDxOY2Pa4fE2Tlhlh6gm0MTxc xjZL5SS0/yQ/UAAb+LUJpXpyCjmQqv6JJvh8M= 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=hbbHzY2mGN6GVRxX5qIoZkQRWZNUdeV1dB8ZZwNAXLY=; b=axsQDZ/v7a9PlzVqIjg9agrQUq1yM3JX6Ld833zzU4Jgj7pT/Z6ujUi86KyqHc7r55 N+ePn+krIJ0g3Dz+NlLL5k0vPMNZQ8bY42M+/EfU4fJT7HLGAYkjG/TFvsDQZNERuZYx Sv2uJB23jZzNcf+ncCLkxSbt0fHLOWku+S6NdvOm4m6w898In+/DEUEK9b69+YYj6FcI rxFI82Ecxnu+XLQo0hDHnzMeWMSXSkQJCnp91f+bNkiHiRLPY03kn7OofXONw4EEeyQx oFDQKgQOp50JZfFw0NddIOfpGGjL2sfpSsVv+d8JJir3mIo04xQyWIVpuZPzcZ4cy056 rCdg== X-Gm-Message-State: APjAAAVogICfHCHVfxZA0zbQDh8ExDEoO9sLpBiEi3b1C1N0A6zSS8qe Gn6ac63IQQeSWD+YeWW7I/e5eQ== X-Google-Smtp-Source: APXvYqzp/gOfWnc+S7RU2qyxgw9Yg9ZgO2i+zhY7rs+emkfs10m9oO16DHTchECfvCrzb/LvoO3XdA== X-Received: by 2002:a63:dd0a:: with SMTP id t10mr22765858pgg.354.1569826184880; Sun, 29 Sep 2019 23:49:44 -0700 (PDT) Received: from rayagonda.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id w6sm13056041pfj.17.2019.09.29.23.49.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 29 Sep 2019 23:49:43 -0700 (PDT) From: Rayagonda Kokatanur To: Ray Jui , Scott Branden , bcm-kernel-feedback-list@broadcom.com, Wolfram Sang , Michael Cheng , Shreesha Rajashekar , Lori Hikichi , linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/1] i2c: iproc: Add i2c repeated start capability Date: Mon, 30 Sep 2019 12:14:29 +0530 Message-Id: <1569825869-30640-1-git-send-email-rayagonda.kokatanur@broadcom.com> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190929_234947_034014_BBA78DF6 X-CRM114-Status: GOOD ( 22.69 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:543 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.0 DKIMWL_WL_HIGH DKIMwl.org - Whitelisted High sender X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Rayagonda Kokatanur , Icarus Chau , Ray Jui , Shivaraj Shetty MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Lori Hikichi Enable handling of i2c repeated start. The current code handles a multi msg i2c transfer as separate i2c bus transactions. This change will now handle this case using the i2c repeated start protocol. The number of msgs in a transfer is limited to two, and must be a write followed by a read. Signed-off-by: Lori Hikichi Signed-off-by: Rayagonda Kokatanur Signed-off-by: Icarus Chau Signed-off-by: Ray Jui Signed-off-by: Shivaraj Shetty --- changes from v1: - Address following review comments from Wolfarm Sang, Use i2c_8bit_addr_from_msg() api instead of decoding i2c_msg struct and remove check against number of i2c message as it will be taken care by core using quirks flags. drivers/i2c/busses/i2c-bcm-iproc.c | 63 ++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index d7fd76b..e478db7 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -81,6 +81,7 @@ #define M_CMD_PROTOCOL_MASK 0xf #define M_CMD_PROTOCOL_BLK_WR 0x7 #define M_CMD_PROTOCOL_BLK_RD 0x8 +#define M_CMD_PROTOCOL_PROCESS 0xa #define M_CMD_PEC_SHIFT 8 #define M_CMD_RD_CNT_SHIFT 0 #define M_CMD_RD_CNT_MASK 0xff @@ -675,13 +676,20 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c, return 0; } -static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, - struct i2c_msg *msg) +/* + * If 'process_call' is true, then this is a multi-msg transfer that requires + * a repeated start between the messages. + * More specifically, it must be a write (reg) followed by a read (data). + * The i2c quirks are set to enforce this rule. + */ +static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c, + struct i2c_msg *msgs, bool process_call) { int i; u8 addr; u32 val, tmp, val_intr_en; unsigned int tx_bytes; + struct i2c_msg *msg = &msgs[0]; /* check if bus is busy */ if (!!(iproc_i2c_rd_reg(iproc_i2c, @@ -707,14 +715,29 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, val = msg->buf[i]; /* mark the last byte */ - if (i == msg->len - 1) - val |= BIT(M_TX_WR_STATUS_SHIFT); + if (!process_call && (i == msg->len - 1)) + val |= 1 << M_TX_WR_STATUS_SHIFT; iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val); } iproc_i2c->tx_bytes = tx_bytes; } + /* Process the read message if this is process call */ + if (process_call) { + msg++; + iproc_i2c->msg = msg; /* point to second msg */ + + /* + * The last byte to be sent out should be a slave + * address with read operation + */ + addr = i2c_8bit_addr_from_msg(msg); + /* mark it the last byte out */ + val = addr | (1 << M_TX_WR_STATUS_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val); + } + /* mark as incomplete before starting the transaction */ if (iproc_i2c->irq) reinit_completion(&iproc_i2c->done); @@ -733,7 +756,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, * underrun interrupt, which will be triggerred when the TX FIFO is * empty. When that happens we can then pump more data into the FIFO */ - if (!(msg->flags & I2C_M_RD) && + if (!process_call && !(msg->flags & I2C_M_RD) && msg->len > iproc_i2c->tx_bytes) val_intr_en |= BIT(IE_M_TX_UNDERRUN_SHIFT); @@ -743,6 +766,8 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, */ val = BIT(M_CMD_START_BUSY_SHIFT); if (msg->flags & I2C_M_RD) { + u32 protocol; + iproc_i2c->rx_bytes = 0; if (msg->len > M_RX_FIFO_MAX_THLD_VALUE) iproc_i2c->thld_bytes = M_RX_FIFO_THLD_VALUE; @@ -758,7 +783,10 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, /* enable the RX threshold interrupt */ val_intr_en |= BIT(IE_M_RX_THLD_SHIFT); - val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) | + protocol = process_call ? + M_CMD_PROTOCOL_PROCESS : M_CMD_PROTOCOL_BLK_RD; + + val |= (protocol << M_CMD_PROTOCOL_SHIFT) | (msg->len << M_CMD_RD_CNT_SHIFT); } else { val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT); @@ -774,17 +802,24 @@ static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg msgs[], int num) { struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter); - int ret, i; + bool process_call = false; + int ret; - /* go through all messages */ - for (i = 0; i < num; i++) { - ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]); - if (ret) { - dev_dbg(iproc_i2c->device, "xfer failed\n"); - return ret; + if (num == 2) { + /* Repeated start, use process call */ + process_call = true; + if (msgs[1].flags & I2C_M_NOSTART) { + dev_err(iproc_i2c->device, "Invalid repeated start\n"); + return -EOPNOTSUPP; } } + ret = bcm_iproc_i2c_xfer_internal(iproc_i2c, msgs, process_call); + if (ret) { + dev_dbg(iproc_i2c->device, "xfer failed\n"); + return ret; + } + return num; } @@ -806,6 +841,8 @@ static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap) }; static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_comb_1st_msg_len = M_TX_RX_FIFO_SIZE, .max_read_len = M_RX_MAX_READ_LEN, };