Complete Communications Engineering

I2C is a serial communication bus used to link microcontrollers to peripheral devices.  The Linux kernel has built-in support for I2C communication on many different platforms.  In general, the microcontroller will be the bus master and the various peripheral devices are clients.  If the microcontroller is running Linux, it can use the Linux I2C methods for reading and writing register values on the peripheral devices.  This may be necessary when developing custom device drivers.

The Linux I2C interface is declared in the header file <linux/i2c.h>.  The i2c_adapter type represents an I2C bus master.  If I2C support is configured properly, then a device driver that implements the I2C adapter methods will already exist in the system.  The function ‘bus_find_device_by_name()’ can be used to find it, if the name is known.  If that function returns a valid device, the macro ‘to_i2c_adapter()’ can be used on the device pointer to get the i2c_adapter pointer.  Given the i2c_adapter, the function ‘i2c_transfer()’ can be used for both read and write operations on registers.  The following code examples demonstrate this:

Write a new value to a register of an I2C device:

void reg_write(i2c_adapter *i2c, u8 device_address,

                        u8 reg_index, u8 new_reg_value)

{

    struct i2c_msg msg;

    u8 buf[2] = {reg_index, new_reg_value};

   

    msg.addr = (__u16)device_address;

    msg.flags = 0;

    msg.len = 2;

    msg.buf = buf;

   

    i2c_transfer(i2c, &msg, 1);

}

 

Read the value of a register from an I2C device:

u8 reg_read(i2c_adapter *i2c, u8 device_address, u8 reg_index)

{

    struct i2c_msg msg[2];

    u8 reg_value;

 

    msg[0].addr = (__u16)device_address;

    msg[0].flags = 0;

    msg[0].len = 1;

    msg[0].buf = &reg_index;

 

    msg[1].addr = (__u16)device_address;

    msg[1].flags = I2C_M_RD;

    msg[1].len = 1;

    msg[1].buf = &reg_value;

 

    i2c_transfer(i2c, msg, 2);

 

    return reg_value;

}