This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Is the bit of I2C_SYSTEST register of DM8168 read-only?

Hi,

I want to clear the bus of I2C of DM8168 because a peripheral is driving SDA bus low.

I find the following web site.

lists.infradead.org/.../080062.html

Can the I2C_SYSTEST register of DM8168 use it in the same way, too?
The[5..0]bit of the I2C_SYSTEST register of Table 21-33 of TRM of DM8168 has a mention like read-only, is it an error in writing?
Judging from contents of description, SDA_O bit and the SDL_O bit are thought to be writable.

Best Regards,

Shigehiro Tsuda

  • Hi Shigehiro,

    shigehiro tsuda said:
    I want to clear the bus of I2C of DM8168 because a peripheral is driving SDA bus low.

    See if the below wiki page will be in help:

    shigehiro tsuda said:
    The[5..0]bit of the I2C_SYSTEST register of Table 21-33 of TRM of DM8168 has a mention like read-only, is it an error in writing?
    Judging from contents of description, SDA_O bit and the SDL_O bit are thought to be writable.

    Yes, also seems to be writable to me also, but after switch from normal functional mode to test mode. Have you tried to write in these bits? See also if the below e2e threads will be in help:

    Regards,
    Pavel

  • After checking I2C internal documentation, I can confirm we have TRM error, I2C_SYSTEST[0] SDA_O and [2] SCL_O are read/write (RW) in test mode.

    Regards,
    Pavel
  • Hi Pavel,

    Thank you for your quick reply.
    I can understand TRM is wrong and I2C_SYSTEST[0] SDA_O and [2] SCL_O are read/write (RW) in test mode.

    Thank you.

    Best Regards,
    Shigehiro Tsuda
  • ikebana-i2c.c
    /*
     * Copyright (C) 2014, SpinetiX
     *
     * See file CREDITS for list of people who contributed to this
     * project.
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License as
     * published by the Free Software Foundation version 2.
     *
     * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     * kind, whether express or implied; without even the implied warranty
     * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     */
    
    #include <common.h>
    #include <asm/arch/i2c.h>
    #include <asm/io.h>
    
    /* import register bit definitions */
    #include "../../../drivers/i2c/omap24xx_i2c.h"
    
    #include "ikebana-funcs.h"
    
    /*
     * WARNING - WARNING - WARNING
     *
     * This code may be called before U-Boot is relocated. Hence it cannot
     * use any global nor static variables and must be position
     * independent. It cannot call udelay() either as that calls into the
     * watchdog reset function which may use global variables, call
     * __udelay() instead.
     *
     */
    
    DECLARE_GLOBAL_DATA_PTR;
    
    /* Waits until I2C SCL is not being stretched by any device or timeout */
    static inline void i2c_wait_stretched_scl(struct i2c *i2c_base)
    {
    	unsigned tout = 1000;
    	while (tout-- > 0) {
    		if (readw(&i2c_base->systest) & I2C_SYSTEST_SCL_I)
    			return;
    		__udelay(1);
    	}
    	if (gd->have_console)
    		puts("timeout waiting for stretched SCL to be released\n");
    }
    
    /*
     * Does a soft reset on the I2C bus. This will take out all I2C slaves
     * out of whatever state they were in, for instance in case of a hard
     * reset of the system that interrupted an I2C transaction midways.
     * The I2C interface and timer must have been initialized before
     * calling this.
     */
    void i2c_bus_reset(struct i2c *i2c_base)
    {
    	unsigned long saved_con;
    	unsigned long saved_psc;
    	unsigned long saved_systest;
    	unsigned long mode_sda_lo_scl_lo;
    	unsigned long mode_sda_hi_scl_lo;
    	unsigned long mode_sda_lo_scl_hi;
    	unsigned long mode_sda_hi_scl_hi;
    	unsigned long i2c_delay;
    	int i;
    
    	/* We use the test features of the I2C controller to drive the
    	 * SCL and SDA pins manually and bit-bang the reset sequence
    	 * (TMODE = 3 is required for bit-banging). The reset sequence
    	 * is the one recommended in Microchip's AN1028 and Atmel
    	 * AT24C512C datasheet. It is a start condition, 9 clock
    	 * cycles with SDA released, a start condition and a stop
    	 * condition. The test features need the I2C controller to be
    	 * out of reset to work. */
    
    	/* save the current I2C mode and configuration */
    	saved_con = readw(&i2c_base->con);
    	saved_psc = readw(&i2c_base->psc);
    	saved_systest = readw(&i2c_base->systest);
    
    	/* NOTE: when switching into and out of test mode the
    	 * controller generates glitches on the SCL and SDA pins
    	 * (momentarily drives the pins low). This can be avoided by
    	 * using the fastest sampling clock, hence we change PSC to
    	 * the lowest possible value (0). Changing the PSC requires
    	 * for the controller to be in reset. */
    	writew(0, &i2c_base->con);
    	__udelay(10);
    	writew(0, &i2c_base->psc);
    	writew(I2C_CON_EN, &i2c_base->con);
    	do {} while ((readw(&i2c_base->syss) & I2C_SYSS_RDONE) == 0);
    
    	mode_sda_lo_scl_lo = I2C_SYSTEST_ST_EN |
    		( 3 << I2C_SYSTEST_TMODE_SHIFT ) |
    		(saved_systest & I2C_SYSTEST_FREE);
    	mode_sda_hi_scl_lo = mode_sda_lo_scl_lo | I2C_SYSTEST_SDA_O;
    	mode_sda_lo_scl_hi = mode_sda_lo_scl_lo | I2C_SYSTEST_SCL_O;
    	mode_sda_hi_scl_hi = mode_sda_hi_scl_lo | I2C_SYSTEST_SCL_O;
    
    	/* We reset the bus at a low 10 kHz frequency for safety. */
    	i2c_delay = 1000000U / 10000 / 4; /* quarter period */
    
    	/* send start condition */
    	writew(mode_sda_hi_scl_hi, &i2c_base->systest);
    	i2c_wait_stretched_scl(i2c_base);
    	__udelay(i2c_delay);
    	writew(mode_sda_lo_scl_hi, &i2c_base->systest);
    	__udelay(i2c_delay);
    	writew(mode_sda_lo_scl_lo, &i2c_base->systest);
    	__udelay(i2c_delay);
    	writew(mode_sda_hi_scl_lo, &i2c_base->systest);
    	__udelay(i2c_delay);
    
    	/* send 9 dummy clock cycles, keeping SDA released */
    	for (i = 0; i < 9; i++) {
    		writew(mode_sda_hi_scl_hi, &i2c_base->systest);
    		i2c_wait_stretched_scl(i2c_base);
    		__udelay(2*i2c_delay);
    		writew(mode_sda_hi_scl_lo, &i2c_base->systest);
    		__udelay(2*i2c_delay);
    	}
    
    	/* send start condition */
    	writew(mode_sda_hi_scl_hi, &i2c_base->systest);
    	i2c_wait_stretched_scl(i2c_base);
    	__udelay(i2c_delay);
    	writew(mode_sda_lo_scl_hi, &i2c_base->systest);
    	__udelay(i2c_delay);
    	writew(mode_sda_lo_scl_lo, &i2c_base->systest);
    	__udelay(2*i2c_delay);
    
    	/* send stop condition */
    	writew(mode_sda_lo_scl_hi, &i2c_base->systest);
    	i2c_wait_stretched_scl(i2c_base);
    	__udelay(i2c_delay);
    	writew(mode_sda_hi_scl_hi, &i2c_base->systest);
    	__udelay(i2c_delay);
    
    	/* revert to normal mode */
    	writew(saved_systest, &i2c_base->systest);
    	__udelay(10);
    
    	/* reset I2C module to revert state machine as the bit-banged
    	 * data sent above leaves it in a confused state */
    	writew(0, &i2c_base->con);
    	__udelay(100);
    	writew(saved_psc, &i2c_base->psc);
    	writew(saved_con, &i2c_base->con);
    	if (saved_con & I2C_CON_EN)
    		do {} while ((readw(&i2c_base->syss) & I2C_SYSS_RDONE) == 0);
    }
    
    

    I have implemented an I2C bus reset protocol using the I2C_SYSTEST register in U-Boot for our DM814x based board. This register is used to do bit-banging to output an I2C bus reset sequence. I think the I2C peripheral is the same on the DM816x, so the code should be applicable too.

    I have attached the U-Boot code for our board that implements this to this post. In our case we need to run this very early during U-Boot initialization (i.e. before relocation) so there are a few extra restrictions on this code (e.g., no global variables), but you should get the idea on how to do a reliable I2C bus reset without running the risk of doing spurious writes to EEPROMs etc.

  • Hi Diego,

    Thank you for an answer.
    I will refer to the attached u-boot code.
    It was a great help for me.

    Best Regards,
    Shigehiro Tsuda