iPXE
Functions
i2c_bit.c File Reference

I2C bit-bashing interface. More...

#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <ipxe/bitbash.h>
#include <ipxe/i2c.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void i2c_delay (void)
 Delay between output state changes.
static void setscl (struct bit_basher *basher, int state)
 Set state of I2C SCL line.
static void setsda (struct bit_basher *basher, int state)
 Set state of I2C SDA line.
static int getsda (struct bit_basher *basher)
 Get state of I2C SDA line.
static void i2c_start (struct bit_basher *basher)
 Send an I2C start condition.
static void i2c_send_bit (struct bit_basher *basher, int bit)
 Send an I2C data bit.
static int i2c_recv_bit (struct bit_basher *basher)
 Receive an I2C data bit.
static void i2c_stop (struct bit_basher *basher)
 Send an I2C stop condition.
static int i2c_send_byte (struct bit_basher *basher, uint8_t byte)
 Send byte via I2C bus and check for acknowledgement.
static uint8_t i2c_recv_byte (struct bit_basher *basher)
 Receive byte via I2C bus.
static int i2c_select (struct bit_basher *basher, struct i2c_device *i2cdev, unsigned int offset, unsigned int direction)
 Select I2C device for reading or writing.
static int i2c_reset (struct bit_basher *basher)
 Reset I2C bus.
static int i2c_bit_read (struct i2c_interface *i2c, struct i2c_device *i2cdev, unsigned int offset, uint8_t *data, unsigned int len)
 Read data from I2C device via bit-bashing interface.
static int i2c_bit_write (struct i2c_interface *i2c, struct i2c_device *i2cdev, unsigned int offset, const uint8_t *data, unsigned int len)
 Write data to I2C device via bit-bashing interface.
int init_i2c_bit_basher (struct i2c_bit_basher *i2cbit, struct bit_basher_operations *bash_op)
 Initialise I2C bit-bashing interface.

Detailed Description

I2C bit-bashing interface.

This implements a simple I2C master via a bit-bashing interface that provides two lines: SCL (clock) and SDA (data).

Definition in file i2c_bit.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void i2c_delay ( void  ) [static]

Delay between output state changes.

Max rated i2c speed (for the basic i2c protocol) is 100kbps, i.e. 200k clock transitions per second.

Definition at line 49 of file i2c_bit.c.

References I2C_UDELAY, and udelay().

Referenced by setscl(), and setsda().

                               {
        udelay ( I2C_UDELAY );
}
static void setscl ( struct bit_basher basher,
int  state 
) [static]

Set state of I2C SCL line.

Parameters:
basherBit-bashing interface
stateNew state of SCL

Definition at line 59 of file i2c_bit.c.

References DBG2, I2C_BIT_SCL, i2c_delay(), and write_bit().

Referenced by i2c_recv_bit(), i2c_reset(), i2c_send_bit(), i2c_start(), and i2c_stop().

                                                            {
        DBG2 ( "%c", ( state ? '/' : '\\' ) );
        write_bit ( basher, I2C_BIT_SCL, state );
        i2c_delay();
}
static void setsda ( struct bit_basher basher,
int  state 
) [static]

Set state of I2C SDA line.

Parameters:
basherBit-bashing interface
stateNew state of SDA

Definition at line 71 of file i2c_bit.c.

References DBG2, I2C_BIT_SDA, i2c_delay(), and write_bit().

Referenced by i2c_reset(), i2c_send_bit(), i2c_start(), and i2c_stop().

                                                            {
        DBG2 ( "%c", ( state ? '1' : '0' ) );
        write_bit ( basher, I2C_BIT_SDA, state );
        i2c_delay();
}
static int getsda ( struct bit_basher basher) [static]

Get state of I2C SDA line.

Parameters:
basherBit-bashing interface
Return values:
stateState of SDA

Definition at line 83 of file i2c_bit.c.

References DBG2, I2C_BIT_SDA, read_bit(), and state.

Referenced by i2c_recv_bit(), and i2c_reset().

                                                {
        int state;
        state = read_bit ( basher, I2C_BIT_SDA );
        DBG2 ( "%c", ( state ? '+' : '-' ) );
        return state;
}
static void i2c_start ( struct bit_basher basher) [static]

Send an I2C start condition.

Parameters:
basherBit-bashing interface

Definition at line 95 of file i2c_bit.c.

References setscl(), and setsda().

Referenced by i2c_reset(), and i2c_select().

                                                    {
        setscl ( basher, 1 );
        setsda ( basher, 0 );
        setscl ( basher, 0 );
        setsda ( basher, 1 );
}
static void i2c_send_bit ( struct bit_basher basher,
int  bit 
) [static]

Send an I2C data bit.

Parameters:
basherBit-bashing interface
bitBit to send

Definition at line 108 of file i2c_bit.c.

References setscl(), and setsda().

Referenced by i2c_recv_byte(), and i2c_send_byte().

                                                                {
        setsda ( basher, bit );
        setscl ( basher, 1 );
        setscl ( basher, 0 );
        setsda ( basher, 1 );
}
static int i2c_recv_bit ( struct bit_basher basher) [static]

Receive an I2C data bit.

Parameters:
basherBit-bashing interface
Return values:
bitReceived bit

Definition at line 121 of file i2c_bit.c.

References getsda(), and setscl().

Referenced by i2c_recv_byte(), and i2c_send_byte().

                                                      {
        int bit;

        setscl ( basher, 1 );
        bit = getsda ( basher );
        setscl ( basher, 0 );
        return bit;
}
static void i2c_stop ( struct bit_basher basher) [static]

Send an I2C stop condition.

Parameters:
basherBit-bashing interface

Definition at line 135 of file i2c_bit.c.

References setscl(), and setsda().

Referenced by i2c_bit_read(), i2c_bit_write(), and i2c_reset().

                                                   {
        setsda ( basher, 0 );
        setscl ( basher, 1 );
        setsda ( basher, 1 );
}
static int i2c_send_byte ( struct bit_basher basher,
uint8_t  byte 
) [static]

Send byte via I2C bus and check for acknowledgement.

Parameters:
basherBit-bashing interface
byteByte to send
Return values:
rcReturn status code

Sends a byte via the I2C bus and checks for an acknowledgement from the slave device.

Definition at line 151 of file i2c_bit.c.

References DBG2, EIO, i2c_recv_bit(), and i2c_send_bit().

Referenced by i2c_bit_read(), i2c_bit_write(), and i2c_select().

                                                                     {
        int i;
        int ack;

        /* Send byte */
        DBG2 ( "[send %02x]", byte );
        for ( i = 8 ; i ; i-- ) {
                i2c_send_bit ( basher, byte & 0x80 );
                byte <<= 1;
        }

        /* Check for acknowledgement from slave */
        ack = ( i2c_recv_bit ( basher ) == 0 );
        DBG2 ( "%s", ( ack ? "[acked]" : "[not acked]" ) );

        return ( ack ? 0 : -EIO );
}
static uint8_t i2c_recv_byte ( struct bit_basher basher) [static]

Receive byte via I2C bus.

Parameters:
basherBit-bashing interface
Return values:
byteReceived byte

Receives a byte via the I2C bus and sends NACK to the slave device.

Definition at line 177 of file i2c_bit.c.

References byte, DBG2, i2c_recv_bit(), and i2c_send_bit().

Referenced by i2c_bit_read().

                                                           {
        uint8_t byte = 0;
        int i;

        /* Receive byte */
        for ( i = 8 ; i ; i-- ) {
                byte <<= 1;
                byte |= ( i2c_recv_bit ( basher ) & 0x1 );
        }

        /* Send NACK */
        i2c_send_bit ( basher, 1 );

        DBG2 ( "[rcvd %02x]", byte );
        return byte;
}
static int i2c_select ( struct bit_basher basher,
struct i2c_device i2cdev,
unsigned int  offset,
unsigned int  direction 
) [static]

Select I2C device for reading or writing.

Parameters:
basherBit-bashing interface
i2cdevI2C device
offsetStarting offset within the device
directionI2C_READ or I2C_WRITE
Return values:
rcReturn status code

Definition at line 203 of file i2c_bit.c.

References address, byte, i2c_device::dev_addr, i2c_device::dev_addr_len, direction, i2c_send_byte(), i2c_start(), rc, and i2c_device::word_addr_len.

Referenced by i2c_bit_read(), and i2c_bit_write().

                                                                      {
        unsigned int address;
        int shift;
        unsigned int byte;
        int rc;

        i2c_start ( basher );

        /* Calculate address to appear on bus */
        address = ( ( ( i2cdev->dev_addr |
                        ( offset >> ( 8 * i2cdev->word_addr_len ) ) ) << 1 )
                    | direction );

        /* Send address a byte at a time */
        for ( shift = ( 8 * ( i2cdev->dev_addr_len - 1 ) ) ;
              shift >= 0 ; shift -= 8 ) {
                byte = ( ( address >> shift ) & 0xff );
                if ( ( rc = i2c_send_byte ( basher, byte ) ) != 0 )
                        return rc;
        }

        return 0;
}
static int i2c_reset ( struct bit_basher basher) [static]

Reset I2C bus.

Parameters:
basherBit-bashing interface
Return values:
rcReturn status code

i2c devices often don't have a reset line, so even a reboot or system power cycle is sometimes not enough to bring them back to a known state.

Definition at line 238 of file i2c_bit.c.

References close_bit(), DBGC, ETIMEDOUT, getsda(), I2C_RESET_MAX_CYCLES, i2c_start(), i2c_stop(), open_bit(), setscl(), and setsda().

Referenced by init_i2c_bit_basher().

                                                   {
        unsigned int i;
        int sda;

        /* Clock through several cycles, waiting for an opportunity to
         * pull SDA low while SCL is high (which creates a start
         * condition).
         */
        open_bit ( basher );
        setscl ( basher, 0 );
        setsda ( basher, 1 );
        for ( i = 0 ; i < I2C_RESET_MAX_CYCLES ; i++ ) {
                setscl ( basher, 1 );
                sda = getsda ( basher );
                if ( sda ) {
                        /* Now that the device will see a start, issue it */
                        i2c_start ( basher );
                        /* Stop the bus to leave it in a known good state */
                        i2c_stop ( basher );
                        DBGC ( basher, "I2CBIT %p reset after %d attempts\n",
                               basher, ( i + 1 ) );
                        close_bit ( basher );
                        return 0;
                }
                setscl ( basher, 0 );
        }

        DBGC ( basher, "I2CBIT %p could not reset after %d attempts\n",
               basher, i );
        close_bit ( basher );
        return -ETIMEDOUT;
}
static int i2c_bit_read ( struct i2c_interface i2c,
struct i2c_device i2cdev,
unsigned int  offset,
uint8_t data,
unsigned int  len 
) [static]

Read data from I2C device via bit-bashing interface.

Parameters:
i2cI2C interface
i2cdevI2C device
offsetStarting offset within the device
dataData buffer
lenLength of data buffer
Return values:
rcReturn status code

Note that attempting to read zero bytes of data is a valid way to check for I2C device presence.

Definition at line 284 of file i2c_bit.c.

References i2c_bit_basher::basher, close_bit(), container_of, DBGC, i2c_device::dev_addr, I2C_READ, i2c_recv_byte(), i2c_select(), i2c_send_byte(), i2c_stop(), I2C_WRITE, open_bit(), and rc.

Referenced by init_i2c_bit_basher().

                                                            {
        struct i2c_bit_basher *i2cbit
                = container_of ( i2c, struct i2c_bit_basher, i2c );
        struct bit_basher *basher = &i2cbit->basher;
        int rc = 0;

        DBGC ( basher, "I2CBIT %p reading from device %x: ",
               basher, i2cdev->dev_addr );

        open_bit ( basher );

        for ( ; ; data++, offset++ ) {

                /* Select device for writing */
                if ( ( rc = i2c_select ( basher, i2cdev, offset,
                                         I2C_WRITE ) ) != 0 )
                        break;

                /* Abort at end of data */
                if ( ! ( len-- ) )
                        break;

                /* Select offset */
                if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
                        break;
                
                /* Select device for reading */
                if ( ( rc = i2c_select ( basher, i2cdev, offset,
                                         I2C_READ ) ) != 0 )
                        break;

                /* Read byte */
                *data = i2c_recv_byte ( basher );
                DBGC ( basher, "%02x ", *data );
        }
        
        DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
        i2c_stop ( basher );
        close_bit ( basher );
        return rc;
}
static int i2c_bit_write ( struct i2c_interface i2c,
struct i2c_device i2cdev,
unsigned int  offset,
const uint8_t data,
unsigned int  len 
) [static]

Write data to I2C device via bit-bashing interface.

Parameters:
i2cI2C interface
i2cdevI2C device
offsetStarting offset within the device
dataData buffer
lenLength of data buffer
Return values:
rcReturn status code

Note that attempting to write zero bytes of data is a valid way to check for I2C device presence.

Definition at line 341 of file i2c_bit.c.

References i2c_bit_basher::basher, close_bit(), container_of, DBGC, i2c_device::dev_addr, i2c_select(), i2c_send_byte(), i2c_stop(), I2C_WRITE, open_bit(), and rc.

Referenced by init_i2c_bit_basher().

                                                                   {
        struct i2c_bit_basher *i2cbit
                = container_of ( i2c, struct i2c_bit_basher, i2c );
        struct bit_basher *basher = &i2cbit->basher;
        int rc = 0;

        DBGC ( basher, "I2CBIT %p writing to device %x: ",
               basher, i2cdev->dev_addr );

        open_bit ( basher );

        for ( ; ; data++, offset++ ) {

                /* Select device for writing */
                if ( ( rc = i2c_select ( basher, i2cdev, offset,
                                         I2C_WRITE ) ) != 0 )
                        break;
                
                /* Abort at end of data */
                if ( ! ( len-- ) )
                        break;

                /* Select offset */
                if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
                        break;
                
                /* Write data to device */
                DBGC ( basher, "%02x ", *data );
                if ( ( rc = i2c_send_byte ( basher, *data ) ) != 0 )
                        break;
        }

        DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
        i2c_stop ( basher );
        close_bit ( basher );
        return rc;
}
int init_i2c_bit_basher ( struct i2c_bit_basher i2cbit,
struct bit_basher_operations bash_op 
)

Initialise I2C bit-bashing interface.

Parameters:
i2cbitI2C bit-bashing interface
bash_opBit-basher operations

Definition at line 387 of file i2c_bit.c.

References assert, i2c_bit_basher::basher, DBGC, i2c_bit_basher::i2c, i2c_bit_read(), i2c_bit_write(), i2c_reset(), NULL, bit_basher::op, rc, bit_basher_operations::read, i2c_interface::read, strerror(), bit_basher_operations::write, and i2c_interface::write.

Referenced by exanic_try_init_eeprom(), falcon_probe_spi(), linda_init_i2c(), and qib7322_init_i2c().

                                                                  {
        struct bit_basher *basher = &i2cbit->basher;
        int rc;

        /* Initialise data structures */
        basher->op = bash_op;
        assert ( basher->op->read != NULL );
        assert ( basher->op->write != NULL );
        i2cbit->i2c.read = i2c_bit_read;
        i2cbit->i2c.write = i2c_bit_write;

        /* Reset I2C bus */
        if ( ( rc = i2c_reset ( basher ) ) != 0 ) {
                DBGC ( basher, "I2CBIT %p could not reset I2C bus: %s\n",
                       basher, strerror ( rc ) );
                return rc;
        }

        return 0;
}