I2C in the 2.6.32 Linux Kernel

The other day I forward-ported an old and abandoned touch-screen driver to the shiny new 2.6.32 kernel. A small portion of the work was to bring the driver in-line with the latest I2C framework (notably due the removal of detach_client from struct i2c_driver since 2.6.31 in favour of the new device driver binding model). This post shares my new-found understanding of the I2C framework and provides a very brief guide to writing an I2C slave device driver.

In a nutshell I2C is a simple serial bus that is often used to communicate with devices such as EEPROMs and peripherals such as touchscreens – there is also SMBus which can sometimes be considered a subset of I2C. The kernel breaks down I2C into ‘Buses’ and ‘Devices’, and then further breaks down buses into ‘Algorithms‘ and ‘Adapters‘, and devices into ‘Drivers‘ and ‘Clients‘. We’ll take a look at these in a little more detail.

Algorithms

An Algorithm performs the actual reading and writing of I2C messages to the hardware – this may involve bit banging GPIO lines or writing to an I2C controller chip. An Algorithm is represented by the very straight-foward ‘struct i2c_algorithm‘ structure and allows you to define function pointers to functions that can write I2C messages (master_xfer) or SMBus messages (smbus_xfer).

Adapters

An Adapter effectively represents a bus – it is used to tie up a particular I2C/SMBus with an algorithm and bus number. It is represented by the ‘struct i2c_adapter‘ structure. If you imagine a system where there are many I2C buses – perhaps two controlled by a controller chip and one bit-banged – then you would expect to see 3 instances of an i2c_adapter and 2 instances of an i2c_algorithm.

Clients

A Client represents a chip (slave) on the I2C/SMBus such as a Touchscreen peripheral and is represented by a ‘struct i2c_client‘ structure. This includes various members such as chip address, name and pointers to the adapter and driver.

Drivers

Finally a driver, represented by a ‘struct i2c_driver‘ structure represents the device driver for a particular class of I2C/SMBus slave devices, e.g. a touchscreen driver. The structure contains a bunch of function pointers – the ones of interest to us are the ‘probe’ and ‘remove’ pointers – which we’ll shortly come onto.

So where do we start with writing an I2C slave device driver? We start by populating a ‘struct i2c_driver’ structure. In this tutorial we’ll populate just the ‘driver’, ‘id_table’, ‘probe’, and ‘remove’ members. We’ll also use the ‘migor_ts.c‘ touchscreen driver as reference code.

static struct i2c_driver migor_ts_driver = {
   .driver = {
      .name = "migor_ts",
   },
   .probe = migor_ts_probe,
   .remove = migor_ts_remove,
   .id_table = migor_ts_id,
};
We tell the kernel about our I2C slave driver by registering the 'struct i2c_driver' structure with the I2C core - we do this with a call to 'i2c_add_driver' in our __init function as follows:
static int __init migor_ts_init(void)
{
        return i2c_add_driver(&migor_ts_driver);
}

As described in an earlier post – the __init macro will ensure this function gets called upon kernel initialisation.

Back to our ‘struct i2c_driver’ structure – the id_table member allows us to tell the framework which I2C slaves chips we support – id_table is simply an array of ‘struct i2c_device_id’ – here’s the migors:

static struct i2c_device_id migor_ts_id[] = {
{ "migor_ts", 0 },
{ }
};

So in this case we’re saying that we only support a slave chip named ‘migor_ts’. This makes us wonder – how does the kernel know which slave chips are present and what they’re called? – we know the chip doesn’t contain such friendly naming strings and I2C doesn’t support enumeration. There is no magic – there are a number of mechanisms to discover and name an I2C slave – the most common in embedded devices is to define in your board set up file what slave devices you expect to see, their address and name. For example in the arch/sh/boards/mach-migor/setup.c file we see the following:

static struct i2c_board_info migor_i2c_devices[] = {
{
I2C_BOARD_INFO("migor_ts", 0x51),
.irq = 38, /* IRQ6 */
},
};

i2c_register_board_info(0, migor_i2c_devices, ARRAY_SIZE(migor_i2c_devices));

Without going into too much detail here – we populate a ‘struct i2c_board_info’ structure with the help of a I2C_BOARD_INFO macro – crucially we include a made up name for the slave chip and it’s I2C bus address.

So back to the migor driver. During boot, thanks to the ‘i2c_register_board_info’ call, the kernel will try to find any I2C driver which supports the ‘migor_ts’ name we provided. Upon finding such a driver, the kernel will call it’s ‘probe’ function. The idea being that the kernel believes it has found an I2C slave and would like us to probe to make sure that we are a suitable driver (It’s worth noting that the kernel won’t attempt to communicate with this device in any way).

So if all is well – upon start up the kernel should call our probe function – let’s take a look.

static int migor_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp)
{
...
}

Passed along as a parameter to the probe function is a ‘struct i2c_client’ structure – this represents our I2C slave chip. Typically a probe function where possible will communicate with the device to ensure it really is the device we think it is – this can be done by reading values from a revision ID register or the like. We can communicate with the slave by calling the ‘i2c_master_send’ function with a pointer to our ‘struct i2c_client’ – e.g:

i2c_master_send(client, buf, 1);
With regards to driver initialisation this is the last we’ll here from the kernel – so the probe function should also register with the input layer (assuming an input device) and perhaps set up an interrupt/timer. It’s also a good idea to make a note of the i2c_client for use later on. Now you can talk to your I2C slave device – what else goes on really depends on the type of device which is being supported.

[© 2011 embedded-bits.co.uk]

, , , , , , , , , , , , , ,

About Andrew Murray

Andrew is an experienced commercial Linux developer with a first class degree in Software Engineering and is the founder of Embedded Bits Limited. His day-to-day role fulfils his passion for learning and provides him with plenty of embedded Linux experience including kernel and embedded applications development on a wide variety of platforms. He loves to talk about boot time reduction and has performed a number of presentations on the topic at technical conferences - he has also been successful in achieving sub-second cold boot on Linux based products. Feel free to drop him an email at amurray@embedded-bits.co.uk

21 Responses to “I2C in the 2.6.32 Linux Kernel”

  1. green February 11, 2010 at 2:24 pm # Reply

    The probe callback has the

    How and where the migor_i2c_devices[] passes his address reference to the
    probe callback?. As you maybe noticed some how struct i2c_client *client = migor_i2c_devices;

    thx

  2. kunal October 12, 2010 at 8:51 am # Reply

    I am writing a driver for a chip which provides i2c bus for control interface. I want to write the driver as a loadable module. So, the probe functions will not be available unless I have loaded this module (which will happen much after the booting). I believe that i2c_register_board_info is called during early booting (platform initialization), so this method will not work (since there is no probe yet). Is there an alternate way to register i2c device at a later stage?

  3. Krishna Kakumani December 11, 2010 at 8:44 am # Reply

    This is fantastic articule. Explains whole i2c driver in a nut shell. Thanks for your time.

    Krishna

  4. Austin May 17, 2011 at 3:21 am # Reply

    Great post I am glad to see some more documentation for porting to the newer I2C binding methods.

    Unfortunately I have the same problem as kunal – the probe function is never run because the driver is a loadable module. Any ideas?

  5. Zahid Sayed July 19, 2011 at 12:38 pm # Reply

    This article is awesome…………..You have explained the concept very precisely………..Thank you

  6. Carlton Fischl September 23, 2011 at 1:41 pm # Reply

    how do you change your Blogger background into a picture?

  7. Kamalnath October 29, 2011 at 9:05 am # Reply

    Thanks a lot for giving pointers to start with on i2c driver. Appreciate your efforts…

  8. nagendra December 2, 2011 at 9:30 am # Reply

    good…article i like it

  9. ebanezar December 6, 2011 at 1:21 pm # Reply

    nice article……..Thanks for it….

  10. Michel Benoit December 9, 2011 at 12:00 pm # Reply

    Thanks for the article. It saved me a lot of time …

  11. Vinesh Balan January 27, 2012 at 11:31 am # Reply

    Nice one, I’ve been pondering for the basics of I2C for a while, got it finally. Thanks a ton!

  12. kakaburra February 15, 2012 at 4:51 pm # Reply

    thanks a lot .. it cleared up a lot of doubts

  13. girish August 15, 2012 at 7:14 am # Reply

    Got the clear flow of i2c driver

  14. Davesh August 22, 2012 at 3:43 am # Reply

    I have one doubt. where is struct 12c_client defined? we are using a pointer to this structre defined? does the i2c_board structure defines its parameters?

  15. Shawn March 5, 2013 at 7:27 am # Reply

    I’m trying to read the i2c-core code, really complicated, about how adapters, drivers, clients all come together, this blog gave me a big hint about how clients related with adapters and drivers. Thanks!

  16. Nikhil Kamath March 5, 2013 at 4:12 pm # Reply

    Superb article ! Thanks a lot.

Trackbacks/Pingbacks

  1. i2c question/problem - October 17, 2011

    […] * http://www.mjmwired.net/kernel/Docum…riting-clients * http://www.embedded-bits.co.uk/2009/…-linux-kernel/ * http://kernel-handbook.alioth.debian…h-modules.html Strong, strong book recommendation: * […]

  2. Workqueues in Recent Linux 2.6.31 - January 7, 2012

    […] Howto write a driver for an i2c client device […]

  3. Workqueues in Recent Linux 2.6.31 - January 7, 2012

    […] Howto write a driver for an i2c client device […]

  4. Workqueues in Recent Linux 2.6.31 - April 4, 2012

    […] Howto write a driver for an i2c client device […]

  5. Embedded Flavour – Linux Kernel Hacking. Módulos I2C para tu núcleo - August 23, 2012

    […] Entrada en el blog embedded-bits sobre I2C en el núcleo 2.6.32 […]

Leave a Reply