From patchwork Wed Oct 9 10:23:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Th=C3=A9o_Lebrun?= X-Patchwork-Id: 13828142 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 7CE9BCF044A for ; Wed, 9 Oct 2024 10:36:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=BV6jtGBlKFIHxumMjV1kYyi9dXX5jMmSnqUBcSCcyT4=; b=vE5izbo0Htfg88efByF3vt6wzy APzGKacUPNfcmI3/YIqASYOq+8W0nZmfmCMNotfK9gSTzzpNuhbyo7iHz7OktEBPC7ReTWrLgMZvF vnttZlj8odKkaavfCOClVGirReIGrNR1IjUnYci1jPSnJOc6go6SMTERXfwnHWa9s+NBweAmYEOTr o2xEFCkHq1BiaVaYqj+vgxA9VgX4/T79IP0xT1RmxG3HRkz2+WFrz45M2PKF64i5Cnnl9qDjSSwjF hZg9q7Ys9nYXkKn+XvaZUgxpwXbffbDWKpENuIBggGdQdsC9EkiVyjLgmHsmQTYN9DFnSGqu5RvTj gltt2p/Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syU2s-00000008u2I-0pZR; Wed, 09 Oct 2024 10:35:54 +0000 Received: from relay6-d.mail.gandi.net ([2001:4b98:dc4:8::226]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syTqw-00000008rih-0tls for linux-arm-kernel@lists.infradead.org; Wed, 09 Oct 2024 10:23:36 +0000 Received: by mail.gandi.net (Postfix) with ESMTPSA id 2D749C000D; Wed, 9 Oct 2024 10:23:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1728469412; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BV6jtGBlKFIHxumMjV1kYyi9dXX5jMmSnqUBcSCcyT4=; b=T9vRPdRiFoyAgmJHbkPIWpP17ik6oZp5Jh8CbHNa3CLZxmANyGkn44dth9algKv03fh1XK kvgTofQ+xvG1Ll9LZloX/bNUCxKbgVEyQf/SRFfB8iaqne9ol8Bt7ARp2BY3WkQwNCD6Co 2b3GL0sotik4uGPv+9U68OsbViQKJX6f7deTnN33to/aB1wx5MKLkg+fFDsV3agUBdvyPr tPmIuuJDQWGicMLrXPsoavsQOjg/Hm2IaKJMJHPMsRZwKoe4ZTg/45eHRQDtp2o/UwDN0w 52XVKgSlnDVjXzukdvSPd1nGbuQZcRgdygvevvqD1hsvVY3970inXYJJ+qwHMQ== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Wed, 09 Oct 2024 12:23:31 +0200 Subject: [PATCH v2 5/6] i2c: nomadik: fix BRCR computation MIME-Version: 1.0 Message-Id: <20241009-mbly-i2c-v2-5-ac9230a8dac5@bootlin.com> References: <20241009-mbly-i2c-v2-0-ac9230a8dac5@bootlin.com> In-Reply-To: <20241009-mbly-i2c-v2-0-ac9230a8dac5@bootlin.com> To: Linus Walleij , Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Vladimir Kondratiev , =?utf-8?q?Gr=C3=A9?= =?utf-8?q?gory_Clement?= , Thomas Petazzoni , Tawfik Bayouk , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.14.2 X-GND-Sasl: theo.lebrun@bootlin.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241009_032334_576152_FA009674 X-CRM114-Status: GOOD ( 12.86 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Current BRCR computation is: brcr = floor(i2cclk / (clkfreq * div)) With brcr: "baud rate counter", an internal clock divider, and i2cclk: input clock rate (24MHz, 38.4MHz or 48MHz), and clkfreq: desired bus rate, and div: speed-mode dependent divider (2 for standard, 3 otherwise). Assume i2cclk=48MHz, clkfreq=3.4MHz, div=3, then brcr = floor(48MHz / (3.4MHz * 3)) = 4 and resulting bus rate = 48MHz / (4 * 3) = 4MHz Assume i2cclk=38.4MHz, clkfreq=1.0MHz, div=3, then brcr = floor(38.4MHz / (1.0MHz * 3)) = 12 and resulting bus rate = 38.4MHz / (12 * 3) = 1066kHz The current computation means we always pick the smallest divider that gives a bus rate above target. We should instead pick the largest divider that gives a bus rate below target, using: brcr = floor(i2cclk / (clkfreq * div)) + 1 If we redo the above examples: Assume i2cclk=48MHz, clkfreq=3.4MHz, div=3, then brcr = floor(48MHz / (3.4MHz * 3)) + 1 = 5 and resulting bus rate = 48MHz / (5 * 3) = 3.2MHz Assume i2cclk=38.4MHz, clkfreq=1.0MHz, div=3, then brcr = floor(38.4MHz / (1.0MHz * 3)) + 1 = 13 and resulting bus rate = 38.4MHz / (13 * 3) = 985kHz This is much less of an issue with slower bus rates (ie those currently supported), because the gap from one divider to the next is much smaller. It however keeps us from always using bus rates superior to the target. This fix is required for later on supporting faster bus rates: I2C_FREQ_MODE_FAST_PLUS (1MHz) and I2C_FREQ_MODE_HIGH_SPEED (3.4MHz). Signed-off-by: Théo Lebrun --- drivers/i2c/busses/i2c-nomadik.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 8f52ae4d6285af2dd2b3dc7070672757e831a019..b2b9da0b32ed903c080f4bdc427ea0dd7b031b49 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -454,9 +454,12 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv) * operation, and the other is for std, fast mode, fast mode * plus operation. Currently we do not supprt high speed mode * so set brcr1 to 0. + * + * BRCR is a clock divider amount. Pick highest value that + * leads to rate strictly below target. */ brcr1 = FIELD_PREP(I2C_BRCR_BRCNT1, 0); - brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, i2c_clk / (priv->clk_freq * div)); + brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, i2c_clk / (priv->clk_freq * div) + 1); /* set the baud rate counter register */ writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR);