OSL I2C Driver

This information corresponds to the I2C driver that's in the main (master) branch of the GIT tree. This is not a flattened driver yet, but is working.

Xilinx I2C Driver Kernel Configuration

I2C is not enabled in the current default kernel configuration. The following steps may be used to enable the driver in the kernel configuration

  1. From the device drivers menu, select I2C support
  2. Select I2C device interface to allow access from user space thru the device interface
  3. Deselect Autoselect pertinent helper modules if it is selected
  4. Select I2C algorithms
  5. Select Xilinx IIC interface

Reading The I2C EEPROM From A User Space Application

The following example reads the I2C EEPROM on the ML507 board. This example can be downloaded at the following link.

download link for i2c read example

This assumes the /dev/i2c/0 device file was created by the user or using udev.

NOTE: The EEPROM higher level driver referenced below cannot be built into the kernel for this example to work. An error that indicates the application cannot set the I2C address will occur if this is the case.

/* Read input line for args of offset and bytes to read from IIC device.
   Do read and dump contents.

   Modified to have EEPROM_ADDR as parameter
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#include "i2c.h"
#include "i2c-dev.h"
#include "buffDump.h"

int main(int argc, char** argv)
{
    unsigned offsetAddr;
    unsigned eepromAddr;
    int count, bytesToRead;
    unsigned char *i2c_buffer;
    unsigned char i2c_ptr[2];
    unsigned argRead, bytesRead;
    int dev_i2c;

    if(argc != 4) {
        printf("Usage i2c_read 0xXXXX (EPROM Addr) 0xXXXX (offset) 0xXXXX (bytes to read)\n");
        return(-1);
    }
    argRead = sscanf(argv[1],"0x%x", &eepromAddr);
    argRead += sscanf(argv[2],"0x%x", &offsetAddr);
    argRead += sscanf(argv[3],"0x%x", &bytesToRead);

    if(argRead != 3 || bytesToRead <= 0) {
        printf("Couldn't scan Address, offset & bytes\n");
        return(-1);
    }

    printf("Reading from I2C EEPROM at 0x%X, Offset=0x%X, Bytes0x%X\n", eepromAddr, offsetAddr, bytesToRead);
    i2c_buffer = malloc(sizeof(char) * bytesToRead);

    if(i2c_buffer == NULL) {
        printf("STATUS: Couldn't malloc buffer.\n");
        return(-1);
    }

    // Open and read i2c
    if ((dev_i2c = open("/dev/i2c/0", O_RDWR)) < 0) {
        printf("Cannot Open I2C Master Device\n");
        exit(1);
    }

    if (ioctl(dev_i2c, I2C_SLAVE, eepromAddr) < 0) {
        printf("Cannot set I2C address\n");
        exit(1);
    }

    // Set address using 16 or 8 bit address, default to 8 bit address
#ifdef ADDR_16
    i2c_ptr[1] = (offsetAddr) & 0xFF;
    i2c_ptr[0] = (offsetAddr>>8) & 0xFF;
    if(write(dev_i2c, i2c_ptr, 2) != 2) {
        printf("I2C write failed\n");
        exit(1);
    }
#else
    i2c_ptr[0] = (offsetAddr) & 0xFF;
    if(write(dev_i2c, i2c_ptr, 1) != 1) {
        printf("I2C write failed\n");
        exit(1);
    }
#endif

    // Read from device
    bytesRead = read(dev_i2c, i2c_buffer, bytesToRead);
    if(bytesRead != bytesToRead) {
        printf("I2C read failed. Return code = %u\n", bytesRead);
        exit(1);
    }

    // Dump what we read
    buffDump(i2c_buffer, bytesToRead);

    return(0);
}

Using An I2C EEPROM Driver As A Higher Layer

A bug was corrected in the I2C driver on 10/6/08 such that you may need to pull the latest code for this to work.

I2C EEPROM Driver Kernel Configuration

There are higher layer drivers that allow the I2C driver to be used to access other devices such as the I2C serial EEPROM on the ML507 board. The following steps may be used to enable the driver in the kernel configuration.

  1. From the device drivers menu, select Misc devices
  2. Select EEPROM Support
  3. Select I2C EEPROMs from most vendors

Adding An I2C EEPROM To The Device Tree

The following example shows adding the I2C EEPROM for the ML507 to it's device tree. The value of 0x050 is the I2C address of the EEPROM.

The device-tree generator for the EDK does not create this device on the I2C bus.

IIC: i2c@81600000 {
    compatible = "xlnx,xps-iic-2.00.a";
    interrupt-parent = <&xps_intc_0>;
    interrupts = < 6 2 >;
    reg = < 0x81600000 0x10000 >;
    xlnx,clk-freq = <0x5f5e100>;
    xlnx,family = "virtex5";
    xlnx,gpo-width = <0x1>;
    xlnx,iic-freq = <0x186a0>;
    xlnx,scl-inertial-delay = <0x0>;
    xlnx,sda-inertial-delay = <0x0>;
    xlnx,ten-bit-adr = <0x0>;

    #address-cells = <1>;
    #size-cells = <0>;

    m24c08@50 {
        compatible = "at,24c08";
        reg = <0x50>;
    };            
} ;

Kernel Console Output

The following kernel output (or similar) shows the EEPROM driver was started.

Device Tree Probing 'i2c'
81600000.i2c #0 at 0x81600000 mapped to 0xD1020000, irq=20
at24 0-0050: 1024 byte 24c08 EEPROM (writable)

SysFs Interface

The EEPROM driver allows the contents of the EEPROM to be seen in the sys file system at /sys/bus/i2c/devices/0-0050/eeprom. The file, eeprom, is a file that can be read and
written from user space.

If the sys file system is not mounted (no /sys dir), then the following commands will create and mount it.

bash>mkdir /sys
bash>mount - t sysfs sysfs sys

The following shell commands can view the contents of the eeprom by 1st capturing it and then displaying the file as binary data.

bash>more /sys/bus/i2c/devices/0-0050/eeprom > eeprom.txt | od -x

The following command will write "01234567890DEADBEEFCAFE" to the EEPROM. Be careful as the ethernet MAC address is in the EEPROM and can be overwritten.

bash>echo 0123456789DEADBEEFCAFE > /sys/bus/i2c/devices/0-0050/eeprom

Using An Aardvark I2C/SPI Activity Board For I2C EEPROM Testing

TotalPhase, the company that sells the Aardvark I2C test equipment, also sells a small board that we can use for our own testing, independent of the Aardvark. The board has an I2C EEPROM and an SPI EEPROM on it such that it can be connected to an FPGA board pretty easy.

http://www.totalphase.com/products/activity_board/
http://www.totalphase.com/download/pdf/activity-board-v1.00.pdf
http://www.totalphase.com/products/split_cable/

The point of this exercise is to have a standard test for the I2C that can be used across all boards.

See the following page, I2C With The Aardvark Board, for more information on how to do it.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License