[U-Boot] [PATCH v2] mxs: i2c: Implement algorithm to set up arbitrary i2c speed
Heiko Schocher
hs at denx.de
Sat Dec 1 02:35:32 CET 2012
Hello Marek,
On 30.11.2012 16:28, Marek Vasut wrote:
> This algorithm computes the values of TIMING{0,1,2} registers for the
> MX28 I2C block. This algorithm was derived by using a scope, but the
> result seems correct.
>
> The resulting values programmed into the registers do not correlate
> with the contents in datasheet. When using the values from the datasheet,
> the I2C clock were completely wrong.
>
> Signed-off-by: Marek Vasut<marex at denx.de>
> Cc: Stefano Babic<sbabic at denx.de>
> Cc: Fabio Estevam<fabio.estevam at freescale.com>
> Cc: Wolfgang Denk<wd at denx.de>
> ---
> arch/arm/cpu/arm926ejs/mxs/clock.c | 2 +
> arch/arm/include/asm/arch-mxs/clock.h | 1 +
> drivers/i2c/mxs_i2c.c | 75 ++++++++++-----------------------
> 3 files changed, 26 insertions(+), 52 deletions(-)
>
> v2: Properly implement XTAL clock retrieval. The i2c clock are derived from the
> 24MHz XTAL clock.
>
[...]
> diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c
> index 006fb91..b040535 100644
> --- a/drivers/i2c/mxs_i2c.c
> +++ b/drivers/i2c/mxs_i2c.c
> @@ -28,6 +28,7 @@
>
> #include<common.h>
> #include<malloc.h>
> +#include<i2c.h>
> #include<asm/errno.h>
> #include<asm/io.h>
> #include<asm/arch/clock.h>
> @@ -40,6 +41,7 @@ void mxs_i2c_reset(void)
> {
> struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
> int ret;
> + int speed = i2c_get_bus_speed();
>
> ret = mxs_reset_block(&i2c_regs->hw_i2c_ctrl0_reg);
> if (ret) {
> @@ -53,6 +55,8 @@ void mxs_i2c_reset(void)
> &i2c_regs->hw_i2c_ctrl1_clr);
>
> writel(I2C_QUEUECTRL_PIO_QUEUE_MODE,&i2c_regs->hw_i2c_queuectrl_set);
> +
> + i2c_set_bus_speed(speed);
> }
This change is not described in the patch description, please fix.
> void mxs_i2c_setup_read(uint8_t chip, int len)
> @@ -210,62 +214,29 @@ int i2c_probe(uchar chip)
> return ret;
> }
>
> -static struct mxs_i2c_speed_table {
[...]
> int i2c_set_bus_speed(unsigned int speed)
> {
> struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
> - struct mxs_i2c_speed_table *spd = mxs_i2c_speed_to_cfg(speed);
>
> - if (!spd) {
> - printf("MXS I2C: Invalid speed selected (%d Hz)\n", speed);
> + uint32_t clk = mxc_get_clock(MXC_XTAL_CLK);
> + uint32_t base = ((clk / speed) - 38) / 2;
> + uint16_t high_count = base + 3;
> + uint16_t low_count = base - 3;
> + uint16_t rcv_count = (high_count * 3) / 4;
> + uint16_t xmit_count = low_count / 4;
a lot of magic constants ...
> +
> + if (speed> 540000) {
> + printf("MXS I2C: Speed too high (%d Hz)\n", speed);
> + return -EINVAL;
> + }
> +
> + if (speed< 12000) {
> + printf("MXS I2C: Speed too low (%d Hz)\n", speed);
> return -EINVAL;
> }
>
> - writel(spd->timing0,&i2c_regs->hw_i2c_timing0);
> - writel(spd->timing1,&i2c_regs->hw_i2c_timing1);
> + writel((high_count<< 16) | rcv_count,&i2c_regs->hw_i2c_timing0);
> + writel((low_count<< 16) | xmit_count,&i2c_regs->hw_i2c_timing1);
^ ^
spaces
>
> writel((0x0030<< I2C_TIMING2_BUS_FREE_OFFSET) |
> (0x0030<< I2C_TIMING2_LEADIN_COUNT_OFFSET),
> @@ -277,12 +248,12 @@ int i2c_set_bus_speed(unsigned int speed)
> unsigned int i2c_get_bus_speed(void)
> {
> struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
> - uint32_t timing0, timing1;
> + uint32_t clk = mxc_get_clock(MXC_XTAL_CLK);
> + uint32_t timing0;
>
> timing0 = readl(&i2c_regs->hw_i2c_timing0);
> - timing1 = readl(&i2c_regs->hw_i2c_timing1);
>
> - return mxs_i2c_cfg_to_speed(timing0, timing1);
> + return clk / ((((timing0>> 16) - 3) * 2) + 38);
^
spaces
... and here a lot of magic constants too ... as this is a result of
measuring ... we should at least note here, that we have this values
from a scope session and the values in the manual seem to be not
correct ...
Hmm... I am a little confused ... you write the i2c_regs->hw_i2c_timing{0,1,2}
registers in i2c_set_bus_speed() but you return in i2c_get_bus_speed()
just results from reading the i2c_regs->hw_i2c_timing0 register only
and do some funny calculations ... is this correct?
> }
>
> void i2c_init(int speed, int slaveadd)
Thanks!
bye,
Heiko
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
More information about the U-Boot
mailing list