Skip to content

Commit 42d158c

Browse files
wang-whlMingcongBai
authored andcommitted
FROMLIST: i2c: ls2x: Add clocks property parsing and adjust bus speed
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 Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> Cc: stable@vger.kernel.org Signed-off-by: Hongliang Wang <wanghongliang@loongson.cn> Link: https://lore.kernel.org/loongarch/20260608024533.32419-1-wanghongliang@loongson.cn/ Signed-off-by: Mingcong Bai <jeffbai@aosc.io>
1 parent 91be652 commit 42d158c

1 file changed

Lines changed: 33 additions & 3 deletions

File tree

drivers/i2c/busses/i2c-ls2x.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <linux/bitfield.h>
1414
#include <linux/bits.h>
15+
#include <linux/clk.h>
1516
#include <linux/completion.h>
1617
#include <linux/device.h>
1718
#include <linux/iopoll.h>
@@ -63,11 +64,18 @@
6364
/* The default bus frequency, which is an empirical value */
6465
#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ)
6566

67+
/* The div of i2c reference clock on LS2K0500/2K1000/2K2000 */
68+
#define LS2X_I2C_2K_CLOCK_DIV 40
69+
70+
/* The div of i2c reference clock on LS7A1000/7A2000 */
71+
#define LS2X_I2C_7A_CLOCK_DIV 50
72+
6673
struct ls2x_i2c_priv {
6774
struct i2c_adapter adapter;
6875
void __iomem *base;
6976
struct i2c_timings i2c_t;
7077
struct completion cmd_complete;
78+
unsigned int div;
7179
};
7280

7381
/*
@@ -96,6 +104,8 @@ static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id)
96104
static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
97105
{
98106
u16 val;
107+
u32 pclk, div;
108+
struct clk *clk;
99109
struct i2c_timings *t = &priv->i2c_t;
100110
struct device *dev = priv->adapter.dev.parent;
101111
u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
@@ -107,12 +117,30 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
107117
else
108118
t->bus_freq_hz = LS2X_I2C_FREQ_STD;
109119

120+
if (dev_of_node(dev)) {
121+
clk = devm_clk_get_optional_enabled(dev, NULL);
122+
if (!IS_ERR_OR_NULL(clk))
123+
pclk = clk_get_rate(clk);
124+
else
125+
pclk = LS2X_I2C_PCLK_FREQ;
126+
127+
div = priv->div;
128+
129+
val = (pclk * 10) / (div * t->bus_freq_hz) - 1;
130+
} else {
131+
/* clocks and clock-div are only ACPI properties. */
132+
if (!device_property_read_u32(dev, "clocks", &pclk) &&
133+
!device_property_read_u32(dev, "clock-div", &div))
134+
val = (pclk * 10) / (div * t->bus_freq_hz) - 1;
135+
else
136+
val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1;
137+
}
138+
110139
/*
111140
* According to the chip manual, we can only access the registers as bytes,
112141
* otherwise the high bits will be truncated.
113142
* So set the I2C frequency with a sequential writeb() instead of writew().
114143
*/
115-
val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1;
116144
writeb(FIELD_GET(GENMASK(7, 0), val), priv->base + I2C_LS2X_PRER_LO);
117145
writeb(FIELD_GET(GENMASK(15, 8), val), priv->base + I2C_LS2X_PRER_HI);
118146
}
@@ -295,6 +323,8 @@ static int ls2x_i2c_probe(struct platform_device *pdev)
295323
if (!priv)
296324
return -ENOMEM;
297325

326+
priv->div = (unsigned long)device_get_match_data(dev);
327+
298328
/* Map hardware registers */
299329
priv->base = devm_platform_ioremap_resource(pdev, 0);
300330
if (IS_ERR(priv->base))
@@ -349,8 +379,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops,
349379
ls2x_i2c_suspend, ls2x_i2c_resume, NULL);
350380

351381
static const struct of_device_id ls2x_i2c_id_table[] = {
352-
{ .compatible = "loongson,ls2k-i2c" },
353-
{ .compatible = "loongson,ls7a-i2c" },
382+
{ .compatible = "loongson,ls2k-i2c", .data = (void *)LS2X_I2C_2K_CLOCK_DIV, },
383+
{ .compatible = "loongson,ls7a-i2c", .data = (void *)LS2X_I2C_7A_CLOCK_DIV, },
354384
{ /* sentinel */ }
355385
};
356386
MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table);

0 commit comments

Comments
 (0)