[PATCH linux dev-5.1 v1] ARM: ASPEED: I2C: Update I2C driver to use APB_clk
Hongwei Zhang
hongweiz at ami.com
Sat Jun 8 06:39:41 AEST 2019
Update I2C clock driver to calculate the clock frequency based on
apb_clk, instead of bus's parent clock frequency.
Signed-off-by: Hongwei Zhang <hongweiz at ami.com>
---
drivers/i2c/busses/i2c-aspeed.c | 45 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 42 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index 6c8b38f..9cce1fe 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -167,6 +167,7 @@ struct aspeed_i2c_bus {
};
static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus);
+static u32 calculate_APB_clock_freq(struct platform_device *pdev);
static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
{
@@ -862,11 +863,11 @@ static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor)
}
/* precondition: bus.lock has been acquired. */
-static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
+static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus, u32 apb_clk)
{
u32 divisor, clk_reg_val;
- divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency);
+ divisor = DIV_ROUND_UP(apb_clk, bus->bus_frequency);
clk_reg_val = readl(bus->base + ASPEED_I2C_AC_TIMING_REG1);
clk_reg_val &= (ASPEED_I2CD_TIME_TBUF_MASK |
ASPEED_I2CD_TIME_THDSTA_MASK |
@@ -883,12 +884,16 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
struct platform_device *pdev)
{
u32 fun_ctrl_reg = ASPEED_I2CD_MASTER_EN;
+ u32 apb_clk;
int ret;
/* Disable everything. */
writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG);
- ret = aspeed_i2c_init_clk(bus);
+ apb_clk = calculate_APB_clock_freq(pdev);
+
+ ret = aspeed_i2c_init_clk(bus, apb_clk);
+
if (ret < 0)
return ret;
@@ -945,6 +950,40 @@ static const struct of_device_id aspeed_i2c_bus_of_table[] = {
};
MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
+static u32 calculate_APB_clock_freq(struct platform_device *pdev)
+{
+ u8 pclk_div;
+ u32 scu_csr, scu_hpll;
+ u32 apb_clk, output_freq;
+ char *baseptr = ioremap(0x1e6e2000, 0x28);
+ const struct of_device_id *of_id = of_match_device(aspeed_i2c_bus_of_table, &pdev->dev);
+
+ scu_csr = readl(baseptr + 0x08);
+ scu_hpll = readl(baseptr + 0x24);
+ pclk_div = (scu_csr & 0x03800000) >> 23; /* 23:25 */
+
+ if (strcmp(of_id->compatible, "aspeed, ast2400-i2c-bus") == 0) {
+ u8 OD, D, N;
+
+ D = scu_hpll & 0x0000000F; /* 0:3 */
+ OD = (scu_hpll & 0x00000010) >> 4; /* 4 */
+ N = (scu_hpll & 0x000007E0) >> 5; /* 5:10 */
+ output_freq = (24 * (2 - OD) * ((N+2) / (D+1)) * 1000000); /* Output Frequency */
+
+ apb_clk = (output_freq / ((pclk_div * 2) + 2));
+ } else {
+ u8 M, N, P;
+
+ N = scu_hpll & 0x0000001F; /* 0:4 */
+ M = (scu_hpll & 0x00001FE0) >> 5; /* 5:12 */
+ P = (scu_hpll & 0x0007E000) >> 13; /* 13:18 */
+ output_freq = ((24 * ((M+1) / (N+1) / (P+1))) * 1000000); /* Output Frequency */
+
+ apb_clk = (output_freq / ((pclk_div * 4) + 4));
+ }
+ return apb_clk;
+}
+
static int aspeed_i2c_probe_bus(struct platform_device *pdev)
{
const struct of_device_id *match;
--
2.7.4
More information about the openbmc
mailing list