From patchwork Tue Nov 7 14:12:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Stein X-Patchwork-Id: 13448884 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 84E74C4332F for ; Tue, 7 Nov 2023 14:12:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc :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=s1Rk4CzsOZ1VtDXa+6r3B2IXoHRUD1X2Wf7Soc2uIFc=; b=bs5KIrdO7ymMVd UF9pbCM8qO6pbECmWKVqt9HYzFQSO+PMTO/kBwxK5V6MKi2TPDVCAkTomCAEK+pikAid2fMkpwjsR aDeUKOrKn6FTLrS8yMKyHIq8wUQv0OonZpYWDVvPQm81t0kBQew1zuD3Ismb6Qy9FUBUsMVhKEWLm 3Go/Mne20ooqSUVqmk0s1zS6TETzdkUxfkcRmxu38nJvFgFIdB6GU5fWlttX7G0DZZywDT32GVBpz bk7/BB3LJ/2ud5KzFDbq4FLYVo6vj62Nk1TkzzGD1vjh+w+/VEENck+e6+SlNO5Z5Xg4bkfU6dwyY 0efYHgV95RDlsAC6Y+9A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1r0Moh-001hii-0u; Tue, 07 Nov 2023 14:12:31 +0000 Received: from mx1.tq-group.com ([93.104.207.81]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1r0Mod-001hi3-0r for linux-arm-kernel@lists.infradead.org; Tue, 07 Nov 2023 14:12:29 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1699366347; x=1730902347; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=OkTo0oXd0SGlrDzbhRw7Pu0dtcxpyYuzNSLrwrYbOO8=; b=JNhKAPb5mPA2nEd9blYKTLEAzmapAoxnp9v8JyBN4Rlj42a3HYxeKb0/ 7C5YEKo2rlgwoHG2V0TRMSsNYmhYkmmWCDMhKoMcsKyKHivVP3e7i3eQr vfPd9v+63x1Cp0NeuOkvUmVTqLjdMEkCXgpej1hcXf7d55mMRmboddRkb HnjRlQ0g0AH+EhkVFi6x8lRTaRuwlpt1IWu7s67j27oxTvv7hTePN/vtl Dc0pS97dhvR50/Z4i/EDR+jXTymWtzr5737aDqydVOGS87HXzSWy/qBaw xUoXx5aWJX1RH7GTmLTdTCIzhrgXh9K3aXYyd8whkMQY4U8uGTyaDtXoq A==; X-IronPort-AV: E=Sophos;i="6.03,283,1694728800"; d="scan'208";a="33854643" Received: from vtuxmail01.tq-net.de ([10.115.0.20]) by mx1.tq-group.com with ESMTP; 07 Nov 2023 15:12:20 +0100 Received: from steina-w.tq-net.de (steina-w.tq-net.de [10.123.53.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by vtuxmail01.tq-net.de (Postfix) with ESMTPSA id C3C3928007F; Tue, 7 Nov 2023 15:12:19 +0100 (CET) From: Alexander Stein To: Dong Aisheng , Andi Shyti , Shawn Guo , Sascha Hauer , Fabio Estevam , Wolfram Sang Cc: Alexander Sverdlin , Pengutronix Kernel Team , NXP Linux Team , linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Alexander Stein Subject: [PATCH v7 1/1] i2c: lpi2c: use clk notifier for rate changes Date: Tue, 7 Nov 2023 15:12:01 +0100 Message-Id: <20231107141201.623482-1-alexander.stein@ew.tq-group.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231107_061227_712282_1E83E6B1 X-CRM114-Status: GOOD ( 18.43 ) 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 From: Alexander Sverdlin Instead of repeatedly calling clk_get_rate for each transfer, register a clock notifier to update the cached divider value each time the clock rate actually changes. There is also a lockdep splat if a I2C based clock provider needs to access the i2c bus while in recalc_rate(). "prepare_lock" is about to be locked recursively. Fixes: a55fa9d0e42e ("i2c: imx-lpi2c: add low power i2c bus driver") Signed-off-by: Alexander Sverdlin Reviewed-by: Alexander Stein Signed-off-by: Alexander Stein --- Changes in v7: * Use dev_err_probe * Reworked/Shortened the commit message It is not about saving CPU cycles, but to avoid locking the clk subsystem upon each transfer. drivers/i2c/busses/i2c-imx-lpi2c.c | 40 +++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 678b30e90492a..3070e605fd8ff 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -5,6 +5,7 @@ * Copyright 2016 Freescale Semiconductor, Inc. */ +#include #include #include #include @@ -99,6 +100,8 @@ struct lpi2c_imx_struct { __u8 *rx_buf; __u8 *tx_buf; struct completion complete; + struct notifier_block clk_change_nb; + atomic_t rate_per; unsigned int msglen; unsigned int delivered; unsigned int block_data; @@ -197,6 +200,20 @@ static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx) } while (1); } +static int lpi2c_imx_clk_change_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct clk_notifier_data *ndata = data; + struct lpi2c_imx_struct *lpi2c_imx = container_of(nb, + struct lpi2c_imx_struct, + clk_change_nb); + + if (action & POST_RATE_CHANGE) + atomic_set(&lpi2c_imx->rate_per, ndata->new_rate); + + return NOTIFY_OK; +} + /* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) { @@ -207,7 +224,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) lpi2c_imx_set_mode(lpi2c_imx); - clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk); + clk_rate = atomic_read(&lpi2c_imx->rate_per); if (!clk_rate) return -EINVAL; @@ -590,6 +607,27 @@ static int lpi2c_imx_probe(struct platform_device *pdev) if (ret) return ret; + lpi2c_imx->clk_change_nb.notifier_call = lpi2c_imx_clk_change_cb; + ret = devm_clk_notifier_register(&pdev->dev, lpi2c_imx->clks[0].clk, + &lpi2c_imx->clk_change_nb); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't register peripheral clock notifier\n"); + /* + * Lock the clock rate to avoid rate change between clk_get_rate() and + * atomic_set() + */ + ret = clk_rate_exclusive_get(lpi2c_imx->clks[0].clk); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't lock I2C peripheral clock rate\n"); + + atomic_set(&lpi2c_imx->rate_per, clk_get_rate(lpi2c_imx->clks[0].clk)); + clk_rate_exclusive_put(lpi2c_imx->clks[0].clk); + if (!atomic_read(&lpi2c_imx->rate_per)) + return dev_err_probe(&pdev->dev, -EINVAL, + "can't get I2C peripheral clock rate\n"); + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_get_noresume(&pdev->dev);