Wednesday, April 27, 2011

Bringing up your I2C device. (In progress..)

Assuming your I2C device is properly interfaced on your harware, we can proceed with coding necessary to make it work.
Lets take a look a all the I2C devices present in the nexus S for example by searching for I2C_BOARD_INFO in its board-file mach-herring.c  :

E:\samsung-HEAD-a998c26\arch\arm\mach-s5pv210\mach-herring.c (17 hits)
Line 1818: I2C_BOARD_INFO("S5K4ECGX", 0x5A>>1),
Line 2097: I2C_BOARD_INFO("S5KA3DFX", 0xc4>>1),
Line 2167: I2C_BOARD_INFO("k3g", 0x69),
Line 2174: I2C_BOARD_INFO("wm8994", (0x34>>1)),
Line 2192: I2C_BOARD_INFO("ak8973", 0x1c),
Line 2196: I2C_BOARD_INFO("kr3dm", 0x09),
Line 2264: I2C_BOARD_INFO(MXT224_DEV_NAME, 0x4a),
Line 2332: I2C_BOARD_INFO(CYPRESS_TOUCHKEY_DEV_NAME, 0x20),
Line 2340: I2C_BOARD_INFO("kr3dm", 0x09),
Line 2347: I2C_BOARD_INFO("k3g", 0x69),
Line 2435: I2C_BOARD_INFO("fsa9480", 0x4A >> 1),
Line 2445: I2C_BOARD_INFO("max8998", (0xCC >> 1)),
Line 2449: I2C_BOARD_INFO("rtc_max8998", (0x0D >> 1)),
Line 2462: I2C_BOARD_INFO("pn544", 0x2b),
Line 2488: I2C_BOARD_INFO("max17040", (0x6D >> 1)),
Line 2520: I2C_BOARD_INFO("gp2a", (0x88 >> 1)),
Line 2527: I2C_BOARD_INFO("ak8973", 0x1c),


We got 17 hits for our search which means we have 17 I2C client devices interfaced with our SoC.
The I2C_BOARD_INFO is used to statically declare I2C devices on their respective busses.
As seen above, there are two arguments you need to pass :

  1. Name of your device. This is not hardware dependent, you can name it anything you want, but remember to use the same name in the client driver later. This is binding element that will lead to the probing of your client driver.

  2. The I2C device address (usually 7 bit). This is hardware dependent. You can look up the device manual for information on this. For some devices provide flexibility to the manufactureres of choosing an address from a set of supported address space by setting the logic of certain address configuration pins. In such case you need to see the board schematic as well to get the device I2C address.

Now, we are ready with the arguments for I2C_BOARD_INFO. Next, we need to find the bus (pins) on which our I2C device is located. Generally, our SoCs have a lot of pins for I/O. In my experience, I have not seen an I2C bus being shared by more than 2 slaves. Since I2C is a simple protocol, normal GPIO pins are toggled by software to run the I2C protocol. The best thing is that linux already has an excellent stack to drive I2C over GPIO!!
Setting up GPIO as I2C bus:
  • First, identify the SoC pins to which SCL and SDA of your device is connected.

  • See if your device is sharing the SCL and SDA lines with any other device. If yes, you can look up for it's I2C_BOARD_INFO entry. If you find it, it means the bus is ready, all you need to do in this file is just add your I2C_BOARD_INFO after it.
    ex:

    static struct i2c_board_info i2c_devs1[] __initdata = {
    {
         I2C_BOARD_INFO("ak8973", 0x1c),
        .platform_data = &akm8973_pdata,
    },
    {
        I2C_BOARD_INFO("kr3dm", 0x09),
        .platform_data = &kr3dm_data,
    },
    };

    In the above code, its visible that kr3dm and ak8973 are using the same SoC pins as SDA and SCL. We will get to the .platform_data later. If the above is not the case, you will have to add few more lines of code as explained below.

  • Search the machine file for "i2c-gpio" . There is a I2C bus for every hit of the search.
    ex
    static struct i2c_gpio_platform_data i2c11_platdata = {
        .sda_pin = GPIO_ALS_SDA_28V,
        .scl_pin = GPIO_ALS_SCL_28V,
        .udelay = 2, /* 250KHz */
        .sda_is_open_drain = 0,
        .scl_is_open_drain = 0,
        .scl_is_output_only = 0,
    };

    static struct platform_device s3c_device_i2c11 = {
        .name = "i2c-gpio",
        .id = 11,
        .dev.platform_data = &i2c11_platdata,
    };

    For every hit for the search, look for sda and scl pins through the platform data, i.e. in the example above, i2c11_platdata is the platform data of the platform device s3c_device_i2c11. .sda_pin and .scl_pin are the GPIO pin numbers which are to be used as SDA and SCL respectively. Look through SCL and SDA for all hits of "i2c-gpio" and make sure that our pins are not already listed. If already listed, make sure that elements of the structure are listed properly as below.

  • create a static struct i2c_gpio_platform_data, enter your GPIO pins numbers to be used as SDA and SCL. Check the optimum clock speed for your I2C device from the data sheet.
    the approximate clock speed of the bus will be 500/.udelay kHz. So, make sure you set the clock speed to something that your device is comfortable with. If you have pull up resistors (on chip or external) on your I2C lines, you can set
    .sda_is_open_drain = 0,
    .scl_is_open_drain = 0,
    If your GPIO has no problems changing direction to INPUT, you can set
    .scl_is_output_only = 0,

  • Create a platform device and pass the pointer to the above structure as .dev.platform_data . Make sure the name remains "i2c-gpio" and the id is unique amongst all I2C bus. You can check all the existing ids by serching for i2c_register_board_info in the machine file. The first argument passed to this function is the id. The id is what that binds your device array to the I2C bus during this function call.

  • Create the device array of i2c_board_info for your bus as per the below example:
    static struct i2c_board_info i2c_devs1[] __initdata = {
    {
        I2C_BOARD_INFO("ak8973", 0x1c),
        .platform_data = &akm8973_pdata,
    },
    {
        I2C_BOARD_INFO("kr3dm", 0x09),
        .platform_data = &kr3dm_data,
    },
    };
    The above array has two elements because of two devices sharing the same bus.

  • Finally register the bus with its devices as below:
    i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
    Here, 1 is the unique bus id, i2c_devs1 is the array of I2C devices on the bus whose id is 1.