From mboxrd@z Thu Jan 1 00:00:00 1970 From: Olliver Schinagl Subject: Re: [linux-sunxi] [PATCH] i2c: mv64xxx: The n clockdiv factor is 0 based on sunxi SoCs Date: Sun, 27 Sep 2015 18:05:35 +0200 Message-ID: <560813CF.4000807@schinagl.nl> References: <1443365828-8956-1-git-send-email-hdegoede@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Return-path: Received: from 7of9.schinagl.nl ([88.159.158.68]:35793 "EHLO 7of9.schinagl.nl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756224AbbI0QFm (ORCPT ); Sun, 27 Sep 2015 12:05:42 -0400 In-Reply-To: <1443365828-8956-1-git-send-email-hdegoede@redhat.com> Sender: linux-i2c-owner@vger.kernel.org List-Id: linux-i2c@vger.kernel.org To: hdegoede@redhat.com, Wolfram Sang , Thomas Petazzoni Cc: Maxime Ripard , linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@googlegroups.com Hey Hans, On 27-09-15 16:57, Hans de Goede wrote: > According to the datasheets to n factor for dividing the tclk is > 2 to the power n on Allwinner SoCs, not 2 to the power n + 1 as it is > on other mv64xxx implementations. Ah! > > I've contacted Allwinner about this and they have confirmed that the > datasheet is correct. > > This commit fixes the clk-divider calculations for Allwinner SoCs > accordingly. So this explains why all my i2c frequenties are double of what I setup. Thanks for taking the time of figuring it out! I'll give it a test hopefully soon. Olliver > > Signed-off-by: Hans de Goede > --- > drivers/i2c/busses/i2c-mv64xxx.c | 27 ++++++++++++++++++--------- > 1 file changed, 18 insertions(+), 9 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c > index 30059c1..e75cf6d 100644 > --- a/drivers/i2c/busses/i2c-mv64xxx.c > +++ b/drivers/i2c/busses/i2c-mv64xxx.c > @@ -146,6 +146,8 @@ struct mv64xxx_i2c_data { > bool errata_delay; > struct reset_control *rstc; > bool irq_clear_inverted; > + /* Clk div is 2 to the power n, not 2 to the power n + 1 */ > + bool clk_n_base_0; > }; > > static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { > @@ -759,25 +761,29 @@ MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); > #ifdef CONFIG_OF > #ifdef CONFIG_HAVE_CLK > static int > -mv64xxx_calc_freq(const int tclk, const int n, const int m) > +mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data, > + const int tclk, const int n, const int m) > { > - return tclk / (10 * (m + 1) * (2 << n)); > + if (drv_data->clk_n_base_0) > + return tclk / (10 * (m + 1) * (1 << n)); > + else > + return tclk / (10 * (m + 1) * (2 << n)); > } > > static bool > -mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, > - u32 *best_m) > +mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data, > + const u32 req_freq, const u32 tclk) > { > int freq, delta, best_delta = INT_MAX; > int m, n; > > for (n = 0; n <= 7; n++) > for (m = 0; m <= 15; m++) { > - freq = mv64xxx_calc_freq(tclk, n, m); > + freq = mv64xxx_calc_freq(drv_data, tclk, n, m); > delta = req_freq - freq; > if (delta >= 0 && delta < best_delta) { > - *best_m = m; > - *best_n = n; > + drv_data->freq_m = m; > + drv_data->freq_n = n; > best_delta = delta; > } > if (best_delta == 0) > @@ -815,8 +821,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, > if (of_property_read_u32(np, "clock-frequency", &bus_freq)) > bus_freq = 100000; /* 100kHz by default */ > > - if (!mv64xxx_find_baud_factors(bus_freq, tclk, > - &drv_data->freq_n, &drv_data->freq_m)) { > + if (of_device_is_compatible(np, "allwinner,sun4i-a10-i2c") || > + of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) > + drv_data->clk_n_base_0 = true; > + > + if (!mv64xxx_find_baud_factors(drv_data, bus_freq, tclk)) { > rc = -EINVAL; > goto out; > } From mboxrd@z Thu Jan 1 00:00:00 1970 From: oliver+list@schinagl.nl (Olliver Schinagl) Date: Sun, 27 Sep 2015 18:05:35 +0200 Subject: [linux-sunxi] [PATCH] i2c: mv64xxx: The n clockdiv factor is 0 based on sunxi SoCs In-Reply-To: <1443365828-8956-1-git-send-email-hdegoede@redhat.com> References: <1443365828-8956-1-git-send-email-hdegoede@redhat.com> Message-ID: <560813CF.4000807@schinagl.nl> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hey Hans, On 27-09-15 16:57, Hans de Goede wrote: > According to the datasheets to n factor for dividing the tclk is > 2 to the power n on Allwinner SoCs, not 2 to the power n + 1 as it is > on other mv64xxx implementations. Ah! > > I've contacted Allwinner about this and they have confirmed that the > datasheet is correct. > > This commit fixes the clk-divider calculations for Allwinner SoCs > accordingly. So this explains why all my i2c frequenties are double of what I setup. Thanks for taking the time of figuring it out! I'll give it a test hopefully soon. Olliver > > Signed-off-by: Hans de Goede > --- > drivers/i2c/busses/i2c-mv64xxx.c | 27 ++++++++++++++++++--------- > 1 file changed, 18 insertions(+), 9 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c > index 30059c1..e75cf6d 100644 > --- a/drivers/i2c/busses/i2c-mv64xxx.c > +++ b/drivers/i2c/busses/i2c-mv64xxx.c > @@ -146,6 +146,8 @@ struct mv64xxx_i2c_data { > bool errata_delay; > struct reset_control *rstc; > bool irq_clear_inverted; > + /* Clk div is 2 to the power n, not 2 to the power n + 1 */ > + bool clk_n_base_0; > }; > > static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { > @@ -759,25 +761,29 @@ MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); > #ifdef CONFIG_OF > #ifdef CONFIG_HAVE_CLK > static int > -mv64xxx_calc_freq(const int tclk, const int n, const int m) > +mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data, > + const int tclk, const int n, const int m) > { > - return tclk / (10 * (m + 1) * (2 << n)); > + if (drv_data->clk_n_base_0) > + return tclk / (10 * (m + 1) * (1 << n)); > + else > + return tclk / (10 * (m + 1) * (2 << n)); > } > > static bool > -mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, > - u32 *best_m) > +mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data, > + const u32 req_freq, const u32 tclk) > { > int freq, delta, best_delta = INT_MAX; > int m, n; > > for (n = 0; n <= 7; n++) > for (m = 0; m <= 15; m++) { > - freq = mv64xxx_calc_freq(tclk, n, m); > + freq = mv64xxx_calc_freq(drv_data, tclk, n, m); > delta = req_freq - freq; > if (delta >= 0 && delta < best_delta) { > - *best_m = m; > - *best_n = n; > + drv_data->freq_m = m; > + drv_data->freq_n = n; > best_delta = delta; > } > if (best_delta == 0) > @@ -815,8 +821,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, > if (of_property_read_u32(np, "clock-frequency", &bus_freq)) > bus_freq = 100000; /* 100kHz by default */ > > - if (!mv64xxx_find_baud_factors(bus_freq, tclk, > - &drv_data->freq_n, &drv_data->freq_m)) { > + if (of_device_is_compatible(np, "allwinner,sun4i-a10-i2c") || > + of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) > + drv_data->clk_n_base_0 = true; > + > + if (!mv64xxx_find_baud_factors(drv_data, bus_freq, tclk)) { > rc = -EINVAL; > goto out; > }