Inter-Integrated Circuit (I2C) Bus The Inter-Integrated Circuit (I2C) bus is a two wire multi-master/slave low speed serial bus. The different devices are accessed by transmitting unique 7-bit addresses. The bus is composed of two bidirectional pins: SCL - Serial Clock signal SDA - Serial Data signal Since communication on the bus is half-duplex, slaves do not transmit any data unless a master has first addressed it. Keep in mind that from the Linux point of view, the I2C master is the adapter while all of the slave devices that hook up to it are clients. I2C Transfer Protocols A normal transfer has the master send a start bit followed by the 7-bit address followed by a single bit to indicate whether it will be reading or writing the address. The slave at the corresponding address responds with an acknowledgment bit followed by 8-bits of data. At this point, the master can either transmit another start bit or it can issue a stop bit to stop transfers. Blackfin Interface Hardware TWI interface Many Blackfin variants have an on-chip hardware Two-Wire Interface (TWI (Two Wire Interface (I2C-compatible))) that is fully compatible with the widely used I2C bus standard. The figure below provides a block diagram of the TWI (Two Wire Interface (I2C-compatible)) controller. The interface is essentially a shift register that serially transmits and receives data bits, one bit at a time at the SCL rate, to and from other TWI (Two Wire Interface (I2C-compatible)) devices. The SCL synchronizes the shifting and sampling of the data on the serial data pin. Here you can see the Blackfin TWI (Two Wire Interface (I2C-compatible)) interface registers used in an I2C compatible transfer. Soft TWI interface The ADSP (Analog Digital Signal Processor)-BF533/532/531 and ADSP (Analog Digital Signal Processor)-BF561 lack an on-chip hardware TWI (Two Wire Interface (I2C-compatible)) interface, so instead I2C (Inter-Integrated Circuit) is implemented via GPIOs. You can choose the generic GPIO (General Purpose Input/Output) based I2C (Inter-Integrated Circuit) driver in the kernel configuration menu: Linux Kernel Configuration Device Drivers ---> I2C support ---> I2C Hardware Bus support ---> GPIO-based bitbanging I2C For I2C (Inter-Integrated Circuit) SDA/SCL GPIO (General Purpose Input/Output) pins configuration, they are defined in your board files. For example: Add i2c platform resources to you board files. (set sda_pin, scl_pin, udelay or other things to correct value according to your hardware configuration) arch/blackfin/mach-bf533/boards/ezkit.c (SDA using GPIO (General Purpose Input/Output) 2, SCL using GPIO (General Purpose Input/Output) 3) arch/blackfin/mach-bf561/boards/ezkit.c (SDA using GPIO (General Purpose Input/Output) 1 SCL using GPIO (General Purpose Input/Output) 0) Register the I2C (Inter-Integrated Circuit) device resource to your board file: arch/blackfin/mach-bf533/boards/ezkit.c and arch/blackfin/mach-bf561/boards/ezkit.c static struct platform_device *ezkit_devices[] __initdata = { ...... #if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE) &i2c_gpio_device, #endif } Linux Kernel Framework Since I2C slave addresses are registered and unique, there is no need to setup board-specific resources. The I2C driver knows the addresses of the clients it supports, so we simply need to build up a driver. Client Driver Our driver here will support just 1 client. Register I2C driver Here you just want to announce to the kernel you are making your driver available. In your init/exit functions, you only want to handle things that need to be done on a per-driver level, not on a per-client level. Remember that since we are using I2C here, you can have more than one client be serviced by the same driver! #include ... #define I2C_MT9M001 0xBA static u16 normal_i2c[] = { I2C_MT9M001 >> 1, (I2C_MT9M001 >> 1) + 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; ... static struct i2c_driver mt9m001_driver = { .driver = { .name = "mt9m001", }, .attach_adapter = mt9m001_attach_adapter, .detach_client = mt9m001_detach_client, }; ... static __init int mt9m001_init(void) { return i2c_add_driver(&mt9m001_driver); } static __exit void mt9m001_exit(void) { i2c_del_driver(&mt9m001_driver); } module_init(mt9m001_init); module_exit(mt9m001_exit); Probe I2C device In your probe/remove functions you want to take care of any resource allocation/setup that is needed for each client. Often times, this may involve setting up a per-device spinlock. static int mt9m001_detect_client(struct i2c_adapter *adapter, int address, int kind) { int ret; struct i2c_client *new_client; struct mt9m001_data *data; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; data = kzalloc(sizeof(struct mt9m001_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; ... i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &mt9m001_driver; strcpy(new_client->name, new_client->driver.name); ret = i2c_attach_client(new_client); if (ret) { kfree(data); return ret; } ... return 0; } static int mt9m001_attach_adapter(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, &mt9m001_detect_client); } ... static int mt9m001_detach_client(struct i2c_client *client) { struct mt9m001_data *data; int ret; ret = i2c_detach_client(client); if (ret) return ret; data = i2c_get_clientdata(client); ... kfree(data); return 0; } Utilize I2C device Now for the open ended part. To access your device, you’ll use a suite of functions. Here we’ll cover some of the common ones. int some_func(..., struct i2c_client *client, ...) { ... /* write a buffer to the client */ u8 buf[3] = { 1, 5, 7 }; i2c_master_send(client, buf, 3); ... /* read a buffer from the client */ u8 buf[5]; i2c_master_recv(client, buf, 5); ... /* write two bytes of data (0x8001) the address 0x1E */ i2c_smbus_write_word_data(client, 0x1E, 0x8001); ... /* read two bytes of data from the address 0x20 */ u16 val = i2c_smbus_read_word_data(client, 0x20); ... } Function Reference Here are the functions used to send/recv data. For indepth information on each function, see the External Resources section for locations in the kernel Documentation. int i2c_master_send (struct i2c_client *client, char *buffer, int count) int i2c_master_recv (struct i2c_client *client, char *buffer, int count) s32 i2c_smbus_write_quick (struct i2c_client *client, u8 value) s32 i2c_smbus_read_byte (struct i2c_client *client) s32 i2c_smbus_write_byte (struct i2c_client *client, u8 value) s32 i2c_smbus_read_byte_data (struct i2c_client *client, u8 command) s32 i2c_smbus_write_byte_data (struct i2c_client *client, u8 command, u8 value) s32 i2c_smbus_read_word_data (struct i2c_client *client, u8 command) s32 i2c_smbus_write_word_data (struct i2c_client *client, u8 command, u16 value) Linux Userspace Framework You can access I2C (Inter-Integrated Circuit) devices directly from userspace via the I2C (Inter-Integrated Circuit) device interface. This will create a character device node for each I2C (Inter-Integrated Circuit) which you can open and perform I2C (Inter-Integrated Circuit) transactions on. The linux-2.6.x/Documentation/i2c/dev-interface file documents the API (Application Programming Interface) and provides some examples. You will of course have to enable the relevant driver in your kernel config: Device Drivers ---> [*] I2C support ---> [*] I2C device interface External Resources For the latest and greatest I2C framework information, please read the following files in the kernel source: linux-2.6.x/include/linux/i2c.h linux-2.6.x/Documentation/i2c/writing-clients linux-2.6.x/Documentation/i2c/dev-interface linux-2.6.x/Documentation/i2c/i2c-protocol linux-2.6.x/Documentation/i2c/smbus-protocol The images/information used here were acquired from various sources including Blackfin HRMs and Wikipedia articles. Wikipedia I2C article