loongson: i2c: support clock and bus freq from dts or acpi

Changelog: 龙芯i2c驱动支持输入时钟和总线时钟从dts或acpi获取
Signed-off-by: maoxiaochuan <maoxiaochuan@loongson.cn>
This commit is contained in:
tao89959
2026-08-24 14:17:10 +08:00
committed by maoxiaochuan
parent 5b79993616
commit ddc84e010f
+59 -7
View File
@@ -25,6 +25,7 @@
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/units.h>
#include <linux/clk.h>
/* I2C Registers */
#define I2C_LS2X_PRER_LO 0x0 /* Freq Division Low Byte Register */
@@ -68,6 +69,8 @@ struct ls2x_i2c_priv {
void __iomem *base;
struct i2c_timings i2c_t;
struct completion cmd_complete;
u32 bus_frequency;
u64 clock_frequency;
};
/*
@@ -98,21 +101,16 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
u16 val;
struct i2c_timings *t = &priv->i2c_t;
struct device *dev = priv->adapter.dev.parent;
u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
i2c_parse_fw_timings(dev, t, false);
if (acpi_speed || t->bus_freq_hz)
t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
else
t->bus_freq_hz = LS2X_I2C_FREQ_STD;
t->bus_freq_hz = priv->bus_frequency;
/*
* 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;
val = priv->clock_frequency / (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);
}
@@ -284,6 +282,55 @@ static const struct i2c_algorithm ls2x_i2c_algo = {
.functionality = ls2x_i2c_func,
};
static void clock_frequency_get(struct platform_device *pdev, struct device *dev, struct ls2x_i2c_priv *priv)
{
int err;
u32 clk;
struct clk *clk_unit;
if (!(device_property_read_u32(dev, "clock-frequency", &clk)))
priv->clock_frequency = clk;
else {
clk_unit = devm_clk_get(&pdev->dev, "i2c-clk");
if(IS_ERR(clk_unit))
goto err_def;
err = clk_prepare_enable(clk_unit);
if (err)
goto err_def;
clk = clk_get_rate(clk_unit);
if (!clk) {
clk_disable_unprepare(clk_unit);
goto err_def;
}
priv->clock_frequency = clk;
clk_unit = NULL;
return;
err_def:
pr_info("i2c-ls2x %s warning: cant get i2c input clock, default value 125000000", pdev->name);
priv->clock_frequency = 125000000;
clk_unit = NULL;
}
}
static void bus_frequency_get(struct platform_device *pdev, struct device *dev, struct ls2x_i2c_priv *priv)
{
u32 bus_freq;
priv->bus_frequency = 0;
if (!(device_property_read_u32(dev, "bus_freq", &bus_freq)))
priv->bus_frequency = bus_freq;
else
priv->bus_frequency = i2c_acpi_find_bus_speed(dev);
if (!(priv->bus_frequency))
priv->bus_frequency = 100000; // default 100KHz
}
static int ls2x_i2c_probe(struct platform_device *pdev)
{
int ret, irq;
@@ -304,6 +351,11 @@ static int ls2x_i2c_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
clock_frequency_get(pdev, dev, priv);
dev_info(dev, "i2c dev input clock is %lld Hz\n", priv->clock_frequency);
bus_frequency_get(pdev, dev, priv);
dev_info(dev, "i2c dev bus clock is %d Hz\n", priv->bus_frequency);
/* Add the i2c adapter */
adap = &priv->adapter;
adap->retries = 5;