[PATCH linux dev-5.1 v1] ARM: ASPEED: I2C: Update I2C driver to use APB_clk

Joel Stanley joel at jms.id.au
Tue Jun 11 12:36:41 AEST 2019


Hi Hongwei,

On Fri, 7 Jun 2019 at 20:39, Hongwei Zhang <hongweiz at ami.com> wrote:
>
> Update I2C clock driver to calculate the clock frequency based on
> apb_clk, instead of bus's parent clock frequency.

I'm not sure what your patch is trying to do. As I understand it, this
is what the driver already does.

The parent clock frequency should be set in the device tree to be the APB clock:

        i2c0: i2c-bus at 40 {
                #address-cells = <1>;
                #size-cells = <0>;
                #interrupt-cells = <1>;

                reg = <0x40 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB>;

Cheers,

Joel

>
> 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