I2C Drivers, Part I
In the June and August 2003 issues of Linux Journal, my column covered the Linux kernel driver model, and the I2C subsystem was used as an example. This month, we discuss what the I2C subsystem does and how to write a driver for it.
I2C is the name for a two-wire serial bus protocol originally developed by Phillips. It commonly is used in embedded systems so different components can communicate; PC motherboards use I2C to talk to different sensor chips. Those sensors typically report back fan speeds, processor temperatures and a whole raft of system hardware information. The protocol also is used in some RAM chips to report information about the DIMM itself back to the operating system.
The I2C kernel code has lived outside of the main kernel tree for much of its development life—it originally was written back in the 2.0 days. The 2.4 kernel contains a bit of I2C support, mainly for some video drivers. With the 2.6 kernel, a large portion of the I2C code has made it into the main kernel tree, thanks to the effort of a number of kernel developers who changed the interfaces to be more acceptable to the kernel community. A few drivers still live only in the external CVS tree and have not been moved into the main kernel.org tree, but it is only a matter of time before they, too, are ported.
The I2C kernel code is broken up into a number of logical pieces: the I2C core, I2C bus drivers, I2C algorithm drivers and I2C chip drivers. We ignore how the I2C core operates in this article and focus instead on how to write a bus and algorithm driver. In Part II, we will cover how to write an I2C chip driver.
An I2C bus driver is described by a struct named i2c_adapter, which is defined in the include/linux/i2c.h file. Only the following fields need to be set up by the bus driver:
struct module *owner; —set to the value (THIS_MODULE) that allows the proper module reference counting.
unsigned int class; —the type of I2C class devices that this driver supports. Usually this is set to the value I2C_ADAP_CLASS_SMBUS.
struct i2c_algorithm *algo; —a pointer to the struct i2c_algorithm structure that describes the way data is transferred through this I2C bus controller. More information on this structure is provided below.
char name[I2C_NAME_SIZE]; —set to a descriptive name of the I2C bus driver. This value shows up in the sysfs filename associated with this I2C adapter.
The code below comes from an example I2C adapter driver called tiny_i2c_adap.c, available from the Linux Journal FTP site [ftp.linuxjournal.com/pub/lj/listings/issue116/7136.tgz] and shows how the struct i2c_adapter is set up:
static struct i2c_adapter tiny_adapter = {
.owner = THIS_MODULE,
.class = I2C_ADAP_CLASS_SMBUS,
.algo = &tiny_algorithm,
.name = "tiny adapter",
};
To register this I2C adapter, the driver calls the function i2c_add_adapter with a pointer to the struct i2c_adapter:
retval = i2c_add_adapter(&tiny_adapter);
If the I2C adapter lives on a type of device that has a struct device associated with it, such as a PCI or USB device, then before the call to i2c_add_adapter, the adapter device's parent pointer should be set to that device. This pointer configuration can be seen in the following line from the drivers/i2c/busses/i2c-piix4.c driver:
/* set up sysfs linkage to our parent device */ piix4_adapter.dev.parent = &dev->dev;
If this parent pointer is not set up, the I2C adapter is positioned on the legacy bus and shows up in the sysfs tree at /sys/devices/legacy. Here is what happens to our example driver when it is registered:
$ tree /sys/devices/legacy/
/sys/devices/legacy/
|-- detach_state
|-- floppy0
| |-- detach_state
| `-- power
| `-- state
|-- i2c-0
| |-- detach_state
| |-- name
| `-- power
| `-- state
`-- power
`-- state
As discussed in the previous kernel driver model columns, the I2C adapter also shows up in the /sys/class/i2c-adapter directory:
$ tree /sys/class/i2c-adapter/
/sys/class/i2c-adapter/
`-- i2c-0
|-- device -> ../../../devices/legacy/i2c-0
`-- driver -> ../../../bus/i2c/drivers/i2c_adapter
To unregister an I2C adapter, the driver should call the function i2c_del_adapter with a pointer to the struct i2c_adapter, like this:
i2c_del_adapter(&tiny_adapter);
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.
Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.
Sponsored by ActiveState
| Non-Linux FOSS: libnotify, OS X Style | Jun 18, 2013 |
| Containers—Not Virtual Machines—Are the Future Cloud | Jun 17, 2013 |
| Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer | Jun 12, 2013 |
| Weechat, Irssi's Little Brother | Jun 11, 2013 |
| One Tail Just Isn't Enough | Jun 07, 2013 |
| Introduction to MapReduce with Hadoop on Linux | Jun 05, 2013 |
- Containers—Not Virtual Machines—Are the Future Cloud
- Non-Linux FOSS: libnotify, OS X Style
- Linux Systems Administrator
- Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer
- Validate an E-Mail Address with PHP, the Right Way
- Technical Support Rep
- Senior Perl Developer
- UX Designer
- Web & UI Developer (JavaScript & j Query)
- Introduction to MapReduce with Hadoop on Linux
- Cari Uang
1 hour 11 min ago - user namespaces
4 hours 4 min ago - yea
4 hours 30 min ago - One advantage with VMs
6 hours 58 min ago - about info
7 hours 32 min ago - info
7 hours 33 min ago - info
7 hours 33 min ago - info
7 hours 36 min ago - info
7 hours 37 min ago - abut info
7 hours 38 min ago




Comments
2.6
Hello,
I am tried building the examples from parts 1 and 2, and got errors. I am running version 2.6.21. The example from part 1 tried to include linux/config.h, which does not seem to exist in 2.6. I removed the include, but I still get errors. They start with the spinlock header
include/linux/spinlock.h: At top level:
include/linux/spinlock.h:290: error: expected declaration specifiers or '...' before 'bool'
include/linux/spinlock.h: In function 'double_spin_lock':
include/linux/spinlock.h:294: error: 'l1_first' undeclared (first use in this function)
include/linux/spinlock.h:294: error: (Each undeclared identifier is reported only once
include/linux/spinlock.h:294: error: for each function it appears in.)
include/linux/spinlock.h:295: warning: implicit declaration of function 'current_thread_info'
include/linux/spinlock.h:295: error: invalid type argument of '->' (have 'int')
include/linux/spinlock.h:295: warning: implicit declaration of function 'barrier'
include/linux/spinlock.h:296: error: invalid type argument of '->' (have 'int')
include/linux/spinlock.h:298: error: invalid type argument of '->' (have 'int')
include/linux/spinlock.h:299: error: invalid type argument of '->' (have 'int')
include/linux/spinlock.h: At top level:
include/linux/spinlock.h:309: error: expected declaration specifiers or '...' before 'bool'
include/linux/spinlock.h: In function 'double_spin_unlock':
include/linux/spinlock.h:313: error: 'l1_taken_first' undeclared (first use in this function)
include/linux/spinlock.h:314: error: invalid type argument of '->' (have 'int')
include/linux/spinlock.h:314: warning: implicit declaration of function 'unlikely'
include/linux/spinlock.h:314: warning: implicit declaration of function 'test_thread_flag'
include/linux/spinlock.h:314: error: 'TIF_NEED_RESCHED' undeclared (first use in this function
Is there something I need to change to make this example compatible with 2.6?
Thanks,
Chris
trying to write a driver for an audio chip
hello !
I'm trying to write a driver for an audio chip, this chip can be controlled via i2c bus (i2c-0)
the problem is that I don't understand how I can "open" the i2c-0 in kernel space...
I tried to do as le lm75 sensor driver...but it's not better..
I know that I have to register my driver as an i2c driver with the i2c_add_driver function
does this:
static intchip_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_detect(adapter, &addr_data,
chip_detect);
}
probes every i2c bus on my board ?
and I don't understand what addr_data is or what it does,
I know it is in the SENSORS_INSMOD_1 macro
but I'm not writing a driver for a sensor, but for an audio chip...
can anyone help me understand better all this ?