From patchwork Tue Dec 2 10:05:49 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harini Katakam X-Patchwork-Id: 5419041 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 702349F1CD for ; Tue, 2 Dec 2014 10:09:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2CF422028D for ; Tue, 2 Dec 2014 10:09:28 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D746A202B8 for ; Tue, 2 Dec 2014 10:09:26 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XvkMu-0006Tp-LB; Tue, 02 Dec 2014 10:07:40 +0000 Received: from mail-oi0-x22e.google.com ([2607:f8b0:4003:c06::22e]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XvkMh-0006Cv-8C for linux-arm-kernel@lists.infradead.org; Tue, 02 Dec 2014 10:07:28 +0000 Received: by mail-oi0-f46.google.com with SMTP id h136so8764625oig.5 for ; Tue, 02 Dec 2014 02:07:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=gpLmmlPnk2FlGSubhBEYDNPQEUYv6Hts6GzDQ18884A=; b=CMLPZMnaUbhW6gnBdNwENLb7KkfMRn+MEqhutRNXvNsDGeuIFfcw63XNzogCR5r4o8 Km8utNi90wI5NRUuFjU0sINN0gXfvrqcP8K7qgmbWHT8wfJ1apueXeveKF1b3a+6SeIv nBXG0WsnQdfdKhhWVN0sa49XsaZu7UUmXFZgVdrIgNIKRjt2R4B7vm+6JrYIqtl8qJ9+ JNZSZNXDXyJW35rSRv2Gk8MzGw0gziKUFiNXOrSXaqo4wLYQreuqmhCccPqVAAoD1tmu FwR+sgX2ttgIyrA+5G+bgA7oCjueQGS6ZzMVqy9DfAVOoAl3Qvo5BdohOMatFrswAOM7 foiQ== X-Received: by 10.202.53.86 with SMTP id c83mr36059003oia.125.1417514825644; Tue, 02 Dec 2014 02:07:05 -0800 (PST) Received: from localhost ([149.199.62.254]) by mx.google.com with ESMTPSA id a1sm9585316oem.10.2014.12.02.02.07.03 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 02 Dec 2014 02:07:04 -0800 (PST) From: Harini Katakam To: wsa@the-dreams.de, grant.likely@linaro.org, robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com, ijc+devicetree@hellion.org.uk, galak@codeaurora.org Subject: [PATCH 4/4] i2c: cadence: Defeature repeated start based on devicetree property Date: Tue, 2 Dec 2014 15:35:49 +0530 Message-Id: <1417514749-24319-5-git-send-email-harinik@xilinx.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1417514749-24319-1-git-send-email-harinik@xilinx.com> References: <1417514749-24319-1-git-send-email-harinik@xilinx.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20141202_020727_449275_7B926A7F X-CRM114-Status: GOOD ( 20.49 ) X-Spam-Score: -0.7 (/) Cc: devicetree@vger.kernel.org, harinik@xilinx.com, vishnum@xilinx.com, linux-kernel@vger.kernel.org, michal.simek@xilinx.com, soren.brinkmann@xilinx.com, linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_LOW, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Vishnu Motghare This patch defeatures repeated start in the driver if "defeature-repeated-start" property is present in the devicetree. This defeature is proposed due to a few bugs in the controller - completion indication is not given to the driver at the end of a read/receive transfer with HOLD bit set. - Invalid read transaction are generated on the bus when HW timeout condition occurs with HOLD bit set. Signed-off-by: Vishnu Motghare Signed-off-by: Harini Katakam --- drivers/i2c/busses/i2c-cadence.c | 44 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 8065205..89335f7 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -135,6 +135,7 @@ * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit * @clk: Pointer to struct clk * @clk_rate_change_nb: Notifier block for clock rate changes + * @defeature_repeated_start: Flag to de feature repeated start */ struct cdns_i2c { void __iomem *membase; @@ -154,6 +155,7 @@ struct cdns_i2c { unsigned int bus_hold_flag; struct clk *clk; struct notifier_block clk_rate_change_nb; + unsigned int defeature_repeated_start; }; #define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \ @@ -246,7 +248,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) } if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) { - if (!id->bus_hold_flag) + if (id->defeature_repeated_start || !id->bus_hold_flag) cdns_i2c_clear_bus_hold(id); done_flag = 1; } @@ -283,7 +285,8 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) */ done_flag = 1; } - if (!id->send_count && !id->bus_hold_flag) + if ((id->defeature_repeated_start && !id->send_count) || + (!id->send_count && !id->bus_hold_flag)) cdns_i2c_clear_bus_hold(id); status = IRQ_HANDLED; @@ -347,10 +350,15 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) } else cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET); /* Clear the bus hold flag if bytes to receive is less than FIFO size */ - if (!id->bus_hold_flag && - ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && - (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) - cdns_i2c_clear_bus_hold(id); + if (id->defeature_repeated_start && + (((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && + (id->recv_count <= CDNS_I2C_FIFO_DEPTH))) + cdns_i2c_clear_bus_hold(id); + else if (!id->bus_hold_flag && + ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && + (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) + cdns_i2c_clear_bus_hold(id); + /* Set the slave address in address register - triggers operation */ cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, CDNS_I2C_ADDR_OFFSET); @@ -411,8 +419,10 @@ static void cdns_i2c_msend(struct cdns_i2c *id) * Clear the bus hold flag if there is no more data * and if it is the last message. */ - if (!id->bus_hold_flag && !id->send_count) + if ((id->defeature_repeated_start && !id->send_count) || + (!id->send_count && !id->bus_hold_flag)) cdns_i2c_clear_bus_hold(id); + /* Set the slave address in address register - triggers operation. */ cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, CDNS_I2C_ADDR_OFFSET); @@ -520,19 +530,25 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, /* * Set the flag to one when multiple messages are to be * processed with a repeated start. + * De feature repeated start when defeature_repeated_start flag is set */ - if (num > 1) { - id->bus_hold_flag = 1; - reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); - reg |= CDNS_I2C_CR_HOLD; - cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET); + if (!id->defeature_repeated_start && num > 1) { + for (count = 0; count < num-1; count++) { + if (msgs[count].flags & I2C_M_RD) + return -EINVAL; + } + id->bus_hold_flag = 1; + reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); + reg |= CDNS_I2C_CR_HOLD; + cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET); } else { id->bus_hold_flag = 0; } /* Process the msg one by one */ for (count = 0; count < num; count++, msgs++) { - if (count == (num - 1)) + if (!id->defeature_repeated_start && + (count == (num - 1))) id->bus_hold_flag = 0; ret = cdns_i2c_process_msg(id, msgs, adap); @@ -840,6 +856,8 @@ static int cdns_i2c_probe(struct platform_device *pdev) cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS, CDNS_I2C_CR_OFFSET); + of_property_read_u32(pdev->dev.of_node, "defeature-repeated-start", + &id->defeature_repeated_start); ret = cdns_i2c_setclk(id->input_clk, id); if (ret) { dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);