From: Hongliang Wang <wanghongliang@loongson.cn>
To: Binbin Zhou <zhoubinbin@loongson.cn>,
Andi Shyti <andi.shyti@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Wolfram Sang <wsa+renesas@sang-engineering.com>,
Hongliang Wang <wanghongliang@loongson.cn>
Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org,
loongarch@lists.linux.dev
Subject: [PATCH v3] i2c: ls2x: Add clocks property parsing and adjust bus speed
Date: Sat, 9 May 2026 16:28:37 +0800 [thread overview]
Message-ID: <20260509082837.28778-1-wanghongliang@loongson.cn> (raw)
From: wanghongliang <wanghongliang@loongson.cn>
The i2c-ls2x driver supports dts and acpi parameter passing.
In dts, uses clock framework, by parsing clocks property to
get i2c bus reference clock, and define the div of reference
clock by device data.
In acpi, by passing clocks property to describe i2c bus reference
clock and clock-div property to describe the div of reference clock.
Based on i2c bus reference clock(clock_a), i2c bus speed(clock_s)
and div, calculate the prcescale of i2c divider register. The
calculation formula is
prcescale = (clock_a*10)/(div*clock_s)-1
Signed-off-by: wanghongliang <wanghongliang@loongson.cn>
---
drivers/i2c/busses/i2c-ls2x.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c
index b475dd27b7af..6d332e59452d 100644
--- a/drivers/i2c/busses/i2c-ls2x.c
+++ b/drivers/i2c/busses/i2c-ls2x.c
@@ -12,6 +12,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/iopoll.h>
@@ -63,11 +64,18 @@
/* The default bus frequency, which is an empirical value */
#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ)
+/* The div of i2c reference clock on 2K0500/2K1000/2K2000 */
+#define LS2X_I2C_2K_CLOCK_DIV 40
+
+/* The div of i2c reference clock on 7A1000/7A2000 */
+#define LS2X_I2C_7A_CLOCK_DIV 50
+
struct ls2x_i2c_priv {
struct i2c_adapter adapter;
void __iomem *base;
struct i2c_timings i2c_t;
struct completion cmd_complete;
+ unsigned int div;
};
/*
@@ -96,6 +104,8 @@ static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id)
static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
{
u16 val;
+ u32 pclk, div;
+ struct clk *clk;
struct i2c_timings *t = &priv->i2c_t;
struct device *dev = priv->adapter.dev.parent;
u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
@@ -107,12 +117,29 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
else
t->bus_freq_hz = LS2X_I2C_FREQ_STD;
+ if (dev_of_node(dev)) {
+ clk = devm_clk_get_optional_enabled(dev, NULL);
+ if (clk && !IS_ERR(clk))
+ pclk = clk_get_rate(clk);
+ else
+ pclk = LS2X_I2C_PCLK_FREQ;
+
+ div = priv->div;
+
+ val = (pclk * 10) / (div * t->bus_freq_hz) - 1;
+ } else {
+ if (!device_property_read_u32(dev, "clocks", &pclk) &&
+ !device_property_read_u32(dev, "clock-div", &div))
+ val = (pclk * 10) / (div * t->bus_freq_hz) - 1;
+ else
+ val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1;
+ }
+
/*
* According to the chip manual, we can only access the registers as bytes,
* otherwise the high bits will be truncated.
* So set the I2C frequency with a sequential writeb() instead of writew().
*/
- val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1;
writeb(FIELD_GET(GENMASK(7, 0), val), priv->base + I2C_LS2X_PRER_LO);
writeb(FIELD_GET(GENMASK(15, 8), val), priv->base + I2C_LS2X_PRER_HI);
}
@@ -295,6 +322,8 @@ static int ls2x_i2c_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ priv->div = (unsigned int)(unsigned long)device_get_match_data(dev);
+
/* Map hardware registers */
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
@@ -349,8 +378,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops,
ls2x_i2c_suspend, ls2x_i2c_resume, NULL);
static const struct of_device_id ls2x_i2c_id_table[] = {
- { .compatible = "loongson,ls2k-i2c" },
- { .compatible = "loongson,ls7a-i2c" },
+ { .compatible = "loongson,ls2k-i2c", .data = (void *)LS2X_I2C_2K_CLOCK_DIV, },
+ { .compatible = "loongson,ls7a-i2c", .data = (void *)LS2X_I2C_7A_CLOCK_DIV, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table);
--
2.47.2
reply other threads:[~2026-05-09 8:29 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260509082837.28778-1-wanghongliang@loongson.cn \
--to=wanghongliang@loongson.cn \
--cc=andi.shyti@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-i2c@vger.kernel.org \
--cc=loongarch@lists.linux.dev \
--cc=robh@kernel.org \
--cc=wsa+renesas@sang-engineering.com \
--cc=zhoubinbin@loongson.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).