XYZ Interix Development
Monday, March 28, 2005
 
WinCE & Linux Blogs
  1. ESDEVCON - Day 2 - Linux Real Time.
  2. http://www.mobilesoft.com.cn/

 
Linux SPI architecture
  1. http://www.katix.org/
  2. Katix Embedded Linux SPI Subsystem description

 
Driving Me Nuts - Device Classes

Driving Me Nuts - Device Classes





More necessary instructions for making your new device driver play nice in the 2.6 kernel.






In the last Driving Me Nuts column [see LJ, June 2003], we introduced the kernel driver model framework with an explanation of how the generic bus and driver and device code works. The i2c core was used as an example to show how these different subsystems work. This month, we cover how the driver class code works, again using the i2c code to provide some working examples.


As discussed in the last column, device classes do not meet the general object-oriented definition of a class; rather they are something that provides a single type of function to the user. For example, kernel classes are used for tty devices, block devices, network devices, SCSI hosts and, in the near future, filesystems.


In the 2.5.69 kernel, the driver class support was rewritten radically. In previous kernel versions, class support was tied tightly to the driver and device support. A class would be bound to the device at the same time it was registered to a driver. This did work for a number of devices and classes, but some real-world devices did not fit very well into this model. Now, class support is tied only loosely to devices and drivers; in fact, a device or driver is not even needed to use the class code now, as the tty class code shows. The class code is now split into three different types of structures: classes, class devices and class interfaces.




Classes


Classes in the kernel are defined with a simple struct class structure. Yes, class is not a reserved word in C. (Everyone who wants to build a kernel with a C++ compiler, go flame the author of the new class code.) To create a class structure, only the name variable in the struct class structure needs to be defined for it to be a valid class. This can be done with the following code:


static struct class i2c_adapter_class = {
.name = "i2c_adapter"
};







After the class structure is defined, it can be registered with the driver core by calling the class_register function:


if (class_register(&i2c_adapter_class) != 0)
printk(KERN_ERR "i2c adapter class failed "
"to register properly\n");







After the class_register function returns without reporting an error, the /sys/class/i2c_adapter directory has been created successfully. Later, when the class needs to be unloaded, the class_unregister function should be called:


class_unregister(&i2c_adapter_class);






Class Devices


Classes are used to manage a set of different class devices. A class device is defined in the kernel with the struct class_device structure. This structure contains of a lot of variables the driver core uses, and it can be ignored by the driver writer. Only the following variables should be set:





  • class: should point to the struct class that is going to manage the class device.



  • dev: should be set to the address of the struct device associated with the class device, if any. A single struct device can be pointed to by multiple class device structures. This is the main difference between the previous kernel class support and the current implementation. This variable does not have to be set for the kernel to work properly. If it is set, a device symbolic link is created in the sysfs entry for the class device that points to the struct device. See below for an example.



  • class_id: an array of characters used to describe the class device. It must be unique among all class device structures assigned to a single class structure.



  • class_data: used to store a pointer to any private data the class driver wants to associate with the class device. This variable should not be accessed directly, but the class_set_devdata and class_get_devdata functions should be used to set and retrieve the value of this variable.




To register a properly set up struct class_device structure, the class_device_register function should be called. An example of how to initialize a struct class_device and register it with the driver core can be seen in the following code from the drivers/i2c/i2c-core.c file:


/* Add this adapter to the i2c_adapter class */
memset(&adap->class_dev, 0x00,
sizeof(struct class_device));
adap->class_dev.dev = &adap->dev;
adap->class_dev.class = &i2c_adapter_class;
strncpy(adap->class_dev.class_id,
adap->dev.bus_id, BUS_ID_SIZE);
class_device_register(&adap->class_dev);







First, the struct class_device variable (embedded in the struct i2c_adapter variable) is initialized to zero. All driver model structures need to have all variables set to zero before they are registered, in order for the driver core to use them properly.


Then the dev variable is set to point to the i2c_adapter's struct device variable; in this case, the same structure, struct i2c_adapter, contains both a struct device and a struct class_device. The class variable is set to the address of the i2c_adapter_class variable, and then the class_id variable is set to the same value as the device's bus_id. Because the i2c_adapter device's bus_id is unique, it also ensures that the i2c_adapter class_device's class_id is unique. Finally, the class device structure is registered with the kernel driver core by a call to the class_device_register function.


With the above code and two i2c adapters loaded on a test machine, the /sys/class/i2c_adapter tree might look like the following: Garrick use a smaller font here so the lines won't have to be broken.


$ tree /sys/class/i2c-adapter/
/sys/class/i2c-adapter/
-- i2c-0
-- device -> ../../../devices/pci0/00:07.3/i2c-0
`-- driver -> ../../../bus/i2c/drivers/i2c_adapter
`-- i2c-2
-- device -> ../../../devices/legacy/i2c-2
`-- driver -> ../../../bus/i2c/drivers/i2c_adapter




As you can see by the above tree output, a device and driver symbolic link are created automatically by the driver core to point to the proper place within the sysfs tree that represents those values. If the dev pointer was not set to point to a struct device, those symbolic links would not have been created. If you look in the /sys/class/tty directory, the majority of those class device entries do not have a corresponding struct device, so those symbolic links are not present.




Class Interfaces


Class interfaces simply are a way for your code to be notified whenever a struct class_device is registered or unregistered from a specific class. A class interface is defined with the struct class_interface structure. This structure is simple and looks like:


struct class_interface {
struct list_head node;
struct class *class;
int (*add) (struct class_device *);
void (*remove) (struct class_device *);
};







The class variable needs to be set to the class about which we want to be notified. The add and remove variables should be set to a function that is called when any devices are added or removed, respectively, from that class. It is not necessary to set both the add and remove variables if you do not want to be notified about one of those events.


To register a class interface with the kernel, the class_interface_register function is called. Likewise, to unregister a class interface, the class_interface_unregister function is called. An example of code that uses class interfaces is the CPU frequency core; this code can be found at kernel/cpufreq.c in the kernel source tree.




Creating Files


As described above, the i2c-adapter class is useful for easily determining all of the different i2c adapters present in the system and their specific location in the driver tree. But i2c adapters are not directly addressable by a user. To talk to an i2c adapter, an i2c chip driver needs to be loaded, or the i2c-dev driver can be used. The i2c-dev driver provides a character driver interface to all i2c adapters present in the system. Because it is useful to determine exactly which i2c-dev devices are attached to which i2c adapters, a i2c-dev class was created:


static struct class i2c_dev_class = {
.name = "i2c-dev"
};







Then, when every i2c adapter is found by the i2c-dev driver, a new i2c class device is added to the driver core. This addition is done in the i2c_add_class_device function:


static void
i2c_add_class_device(char *name, int minor,
struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
int retval;
i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
return;
memset(i2c_dev, 0x00, sizeof(*i2c_dev));
if (adap->dev.parent == &legacy_bus)
i2c_dev->class_dev.dev = &adap->dev;
else
i2c_dev->class_dev.dev = adap->dev.parent;
i2c_dev->class_dev.class = &i2c_dev_class;
snprintf(i2c_dev->class_dev.class_id,
BUS_ID_SIZE, "%s", name);
retval =
class_device_register(&i2c_dev->class_dev);
if (retval)
goto error;
class_device_create_file (&i2c_dev->class_dev,
&class_device_attr_dev);
i2c_dev->minor = minor;
spin_lock(&i2c_dev_list_lock);
list_add(&i2c_dev->node, &i2c_dev_list);
spin_unlock(&i2c_dev_list_lock);
return;
error:
kfree(i2c_dev);
}







This function looks almost like the i2c_adapter class registration code, with two exceptions. First, the class_dev.dev field is set to be either the adapter's parent device or the adapter's device. This is done because some i2c adapters do not have a real parent in the global kernel device tree, as they live on a bus that has not been converted to the kernel driver model (like ISA) or they do not really live on a bus at all (like some i2c embedded controllers). When an i2c adapter does not have a place in the kernel device tree, it is assigned to the legacy bus. The legacy bus, located at /sys/devices/legacy, is used for these kinds of devices.


The second thing that is different with this class device is the line:


class_device_create_file (&i2c_dev->class_dev, &class_device_attr_dev);







The class_device_create_file function is used to create a file in the class device's directory. The filename and attributes are defined with the CLASS_DEVICE_ATTR macro as: Garrick, please kern the double underscores in the code below.


static ssize_t
show_dev(struct class_device *class_dev, char *buf)
{
struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
return sprintf(buf, "%04x\n",
MKDEV(I2C_MAJOR, i2c_dev->minor));
}
static
CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);




The CLASS_DEVICE_ATTR macro is itself defined as:


#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) struct class_device_attribute class_device_attr_##_name = { .attr = {.name = __stringify(_name), .mode = _mode }, .show = _show, .store = _store, };







The arguments within the CLASS_DEVICE_ATTR macro are:





  • _name: both the name of the file to be created in sysfs and part of the variable name that describes this whole attribute.



  • _mode: the file access mode with which the file is created. Use the standard access macros to specify the proper value.



  • _show: points to a function that is called when the file is read from. This function must have the following return value and parameters. This variable does not have to be set if the file is not to be read from.

    ssize_t
    show (struct class_device *class_dev, char *buf);





  • _store: points to a function that is called when the file is written to. This function must have the following return value and paramaters. This variable does not have to be set if the file is not to be written to.

    ssize_t
    store (struct device *dev, const char *buf,
    size_t count);







Almost all driver model structures have an ATTR() macro that declares a file within the sysfs tree.


In this example, a file named dev is created when the class_device_create_file function is called. This file is created to be read-only by any user. If the file is read from, the show_dev function is called by the driver core. The show_dev function fills in the buffer passed to it with the information it wants to give the user. In this case, the major and minor number for this specific device are passed to the user. All class devices using a major and minor number should have a dev file within their sysfs class device directory.


The class_device_remove_file function can be used to remove any files created by the class_device_create_file function. But it is not necessary to remove manually any file created if the device is about to be removed. When devices are removed from sysfs, all files created in their directories are removed automatically by the sysfs core. So, when the i2c-dev class device is removed from the system, all that is needed is the following:


static void
i2c_remove_class_device(int minor)
{
struct i2c_dev *i2c_dev = NULL;
struct list_head *tmp;
int found = 0;
spin_lock(&i2c_dev_list_lock);
list_for_each (tmp, &i2c_dev_list) {
i2c_dev = list_entry(tmp, struct i2c_dev,
node);
if (i2c_dev->minor == minor) {
found = 1;
break;
}
}
if (found) {
list_del(&i2c_dev->node);
spin_unlock(&i2c_dev_list_lock);
class_device_unregister(&i2c_dev->class_dev);
kfree(i2c_dev);
} else {
spin_unlock(&i2c_dev_list_lock);
}
}






What It All Looks Like


With the i2c-dev driver and two i2c adapter drivers (the i2c-piix4 and i2c-isa drivers) loaded, the /sys/class/i2c-dev directory might look like the following: Garrick, please use a smaller font below so the lines don't need to be broken.


$ tree /sys/class/i2c-dev/
/sys/class/i2c-dev/
-- i2c-0
-- dev
-- device -> ../../../devices/pci0/00:07.3
`-- driver -> ../../../bus/pci/drivers/piix4-smbus
`-- i2c-2
-- dev
-- device -> ../../../devices/legacy/i2c-2
`-- driver -> ../../../bus/i2c/drivers/i2c_adapter







The dev file in the /sys/class/i2c-dev/i2c-2/ directory would contain the following string:


$ cat /sys/class/i2c-dev/i2c-2/dev
5902







which corresponds to major number 86 and minor number 2, the character major and minor numbers for this specific device.


Also, the /sys/bus/i2c/ directory with a few i2c client drivers loaded looks like: Garrick, please use a smaller font below so we don't have to break the lines.


$ tree /sys/bus/i2c/
/sys/bus/i2c/
-- devices
-- 0-0050 -> ../../../devices/pci0/00:07.3/i2c-0/0-0050
-- 0-0051 -> ../../../devices/pci0/00:07.3/i2c-0/0-0051
-- 0-0052 -> ../../../devices/pci0/00:07.3/i2c-0/0-0052
-- 0-0053 -> ../../../devices/pci0/00:07.3/i2c-0/0-0053
`-- 2-0290 -> ../../../devices/legacy/i2c-2/2-0290
`-- drivers
-- dev driver
-- eeprom
-- 0-0050 -> ../../../../devices/pci0/00:07.3/i2c-0/0-0050
-- 0-0051 -> ../../../../devices/pci0/00:07.3/i2c-0/0-0051
-- 0-0052 -> ../../../../devices/pci0/00:07.3/i2c-0/0-0052
`-- 0-0053 -> ../../../../devices/pci0/00:07.3/i2c-0/0-0053
-- i2c_adapter
`-- w83781d
`-- 2-0290 -> ../../../../devices/legacy/i2c-2/2-0290




And, the actual /sys/devices/ directories for the i2c adapters look like:


$ tree /sys/devices/pci0/00:07.3
/sys/devices/pci0/00:07.3
-- class
-- device
-- i2c-0
-- 0-0050
-- eeprom_00
-- name
`-- power
-- 0-0051
-- eeprom_00
-- name
`-- power
-- 0-0052
-- eeprom_00
-- name
`-- power
-- 0-0053
-- eeprom_00
-- name
`-- power
-- name
`-- power
-- irq
-- name
-- power
-- resource
-- subsystem_device
-- subsystem_vendor
`-- vendor







and:


$ tree /sys/devices/legacy/i2c-2/
/sys/devices/legacy/i2c-2/
-- 2-0290
-- alarms
-- beep_enable
-- beep_mask
-- fan_div1
-- fan_div2
-- fan_div3
-- fan_input1
-- fan_input2
-- fan_input3
-- fan_min1
-- fan_min2
-- fan_min3
-- in_input0
-- in_input1
-- in_input2
-- in_input3
-- in_input4
-- in_input5
-- in_input6
-- in_input7
-- in_input8
-- in_max0
-- in_max1
-- in_max2
-- in_max3
-- in_max4
-- in_max5
-- in_max6
-- in_max7
-- in_max8
-- in_min0
-- in_min1
-- in_min2
-- in_min3
-- in_min4
-- in_min5
-- in_min6
-- in_min7
-- in_min8
-- name
-- power
-- pwm1
-- pwm2
-- pwm_enable2
-- sensor1
-- sensor2
-- sensor3
-- temp_input1
-- temp_input2
-- temp_input3
-- temp_max1
-- temp_max2
-- temp_max3
-- temp_min1
-- temp_min2
-- temp_min3
-- vid
`-- vrm
-- name
`-- power




I think the best description of the kernel driver model's use of interconnected structure pointers and representation to the user was issued by Jonathan Corbet: "web woven by a spider on drugs" (lwn.net/Articles/31185/). Hopefully, these two articles have helped you unravel the loony web, showing the true interconnectedness of all devices within the kernel.




Acknowledgements


I would like to thank Pat Mochel for creating such a powerful and complete framework in which all kernel drivers and devices easily can be shown to the user. Also, a big thanks to all of the kernel driver subsystem maintainers who have gladly converted their subsystems over to this model; without their help, the driver core code would have been little more than a nice academic exercise. Garrick, please insert the embedded slug.


Greg Kroah-Hartman is currently the Linux USB and PCI Hot Plug kernel maintainer. He works for IBM, doing various Linux kernel-related things and can be reached at greg@kroah.com. 6872aa.tif


 
The Driver Model Core, Part I

The Driver Model Core, Part I




The 2.5 kernel implements a unified device driver model that will make driver development for 2.6 easier.




In the 2.5 Linux kernel development series, a unified device driver model framework was created by Pat Mochel. This framework consists of a number of common structures and functions all device driver subsystems have been converted to use. It also consists of some generic structures that are starting to be used outside of the driver code by other parts of the kernel. This article discusses parts of the driver model and provides an example of how to convert a specific device driver subsystem to the driver model.




Buses, Devices and Classes


The driver framework breaks all things down into buses, devices and classes. Using these primitives, it controls how drivers are matched up with physical and virtual devices, and it shows the user how all of these things are interconnected.


A bus can be described as something with devices connected to it. Examples of buses are PCI, USB, i2c, PCMCIA and SCSI. Usually only one bus driver controls the activity on a bus, and it provides a type of bridge from the bus it is on to the bus it controls.


An example of a bridge is a USB controller that lives on the PCI bus. It talks to the PCI bus as a PCI device and looks to the kernel as a PCI driver. But it controls all access to that specific USB bus, talking to the different USB devices plugged in to it.


Buses are represented in the kernel with the struct bus_type definition, found in include/linux/device.h. All buses in the system are shown to the user in subdirectories of the sysfs directory /sys/bus/.


Sidebar: Sysfs


Devices are physical or virtual devices that reside on a bus. They are represented by the struct device definition and are created by the bus when the bus sees they are present in the system. Usually only one driver controls a specific device at one time. They can be seen in the /sys/devices directory as a giant tree of all devices in the system or in the /sys/bus/BUS_TYPE/devices/ directory for a specific type of device.


Devices also have drivers assigned to them that control how to talk to the device across a specific bus. Some drivers know how to talk to multiple buses, such as the Tulip network driver, which can talk to PCI and ISA Tulip devices. All drivers are represented by the struct device_driver definition. They can be seen in sysfs at /sys/bus/BUS_TYPE/drivers/. Drivers register with a specific bus and export a list of different types of devices they can support. The bus matches the devices and drivers based on this list of exported devices. The list also is exported to user space so the /sbin/hotplug tools can be used to match drivers to devices that do not have drivers already loaded. See my article, ``Hot Plug'', in the April 2002 issue of Linux Journal for more information on this interface and how it works [also available at www.linuxjournal.com/article/5604].


Classes here do not take the general object-oriented definition but, rather, are things that provide a function to the user. They are not bus- or device-specific things but functionally look to the user as the same type of device. Examples of classes are audio devices; pointing devices, such as mice and touchpads; keyboards; joysticks; IDE disks; and tty devices. The kernel always has had these kinds of devices, and they traditionally have been grouped together by major/minor number range, so the user can access them easily. Classes are represented in the kernel with the struct device_class definition, and they can be seen as subdirectories of the sysfs directory /sys/class/.


For a description of the whole driver model, along with an introduction to the structures below the driver model that do all of the real work, see the thorough document at www.kernel.org/pub/linux/kernel/people/mochel/doc/lca/driver-model-lca2003.tar.gz. It was written by Pat Mochel for the 2003 Linux.Conf.Au conference.




Theory in Action


All of the above descriptions sound great on paper, but how does the driver model actually affect the kernel code? To show this, let us walk through how the i2c driver subsystem was modified to support this driver model.


The i2c code has lived outside of the main kernel tree for a long time, and it was offered as a patch for the 2.0, 2.2 and 2.4 kernels. It also was the subject of ``Using the i2c Bus'', by Simon G. Vogl, one of the main authors of the code [LJ, March 1997, www.linuxjournal.com/article/1342]. In the 2.4 development cycle, a number of the i2c core files and a few i2c bus drivers were accepted into the main kernel. In the 2.5 development cycle, a few more drivers were added; hopefully, all of them eventually will migrate into the main tree. For a good description of the i2c code, what devices it supports and how to use it, see the main development site at secure.netroedge.com/~lm78/index.html.


When loaded, the i2c bus drivers, which talk to the i2c controller chips, export a number of files in the /proc/bus directory. When an i2c device driver is loaded and bound to an i2c device, it exports files and directories in the /proc/sys/dev/sensors directory. By moving the representation of the devices and buses to the kernel driver core, all of these separate files can be shown in their proper places in /sys.




The i2c Bus


The main i2c bus subsystem needs to be declared in the kernel and registered with the driver core. To accomplish this, the following code was added to drivers/i2c/i2c-core.c:

static int i2c_device_match(struct device *dev,
struct device_driver *drv)
{
return 1;
}
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
};


The name field says what the bus should be called, and the match field points to our match function. Right now, the match function is left alone, always returning 1 whenever the driver core wants to try to match a driver with a device. This logic will be modified at a later time.


Then, in the i2c core startup code, the i2c_bus_type is registered with a call to:

bus_register(&i2c_bus_type);


When the i2c core is shut down, a call is added to unregister this bus:

bus_unregister(&i2c_bus_type);

When the above code runs, the following tree is created in sysfs:
$ tree /sys/bus/i2c/
/sys/bus/i2c/
-- devices
'-- drivers

When the i2c core is removed from the system, the above directories are removed. This is all that is needed to create the i2c bus.




i2c Adapters


An i2c bus by itself is pretty boring. Now, the i2c bus adapter drivers need to be modified to register themselves with this bus. To do this, a struct device variable is added to the struct i2c_adapter structure:

struct i2c_adapter {
.....
struct device dev;
};


A to_i2c_adapter() macro is defined as:

#define to_i2c_adapter(d) container_of(d,
struct i2c_adapter, dev)

This macro is used by the i2c core to get a pointer to a real i2c_adapter structure whenever the driver core passes it a pointer to a struct device.


The struct device in the i2c_adapter is a whole variable declared within the structure, not merely a pointer. This is done so when the driver core passes a pointer to a struct device, the i2c code can use the to_i2c_adapter() macro to get a pointer to the real i2c_adapter structure.


Sidebar: container_of()


The individual struct i2c_driver variables are declared in the different i2c bus drivers. For example, in the i2c-piix4.c driver, there is a variable called piix4_adapter of type struct i2c_driver. This variable is passed to the i2c core in the i2c_add_adapter() function, when a PIIX4 adapter is seen by the i2c-piix4 driver.


In the i2c-piix4.c driver, before i2c_add_adapter() is called, a pointer to the parent device of the PIIX4 adapter needs to be saved within the i2c_driver structure. This is done with a single line of code:

piix4_adapter.dev.parent = &dev->dev;


dev is a pointer to the struct pci_dev that is passed to the i2c-piix4 driver's PCI probe function; the PIIX4 is a PCI-based device.


To link the i2c_driver variable to the sysfs tree, the following lines of code are added to the i2c_add_adapter() function:

/* add the adapter to the driver core.
* The parent pointer should already
* have been set up.
*/
sprintf(adap->dev.bus_id, "i2c-%d", i);
strcpy(adap->dev.name, "i2c controller");
device_register(&adap->dev);


With this code, when the PIIX4 device is detected by the driver, an i2c bus tree is created and linked to the controlling PCI device:

$ tree /sys/devices/pci0/00:07.3/i2c-0
/sys/devices/pci0/00:07.3/i2c-0
-- name
`-- power

When the i2c-piix4 driver is unloaded, the i2c_del_adapter() function is called. The following line of code is added to clean up the i2c bus device:
/* clean up the sysfs representation */
device_unregister(&adap->dev);






i2c Drivers


The i2c bus has a number of different drivers that control access to a wide range of i2c devices that live on the i2c bus. These drivers are declared with a struct i2c_driver structure. Within this structure, a struct device_driver variable is added to allow these drivers to be registered with the driver core:

struct i2c_driver {
.....
struct device_driver driver;
};


And, a to_i2c_driver() macro is defined as:

#define to_i2c_driver(d) container_of(d, struct
i2c_driver, driver)

An i2c driver registers itself with the i2c core in a call to i2c_add_driver(). To add driver core support for i2c drivers, the following lines of code are added to this function:
/* add the driver to the list of
*i2c drivers in the driver core */
driver->driver.name = driver->name;
driver->driver.bus = &i2c_bus_type;
driver->driver.probe = i2c_device_probe;
driver->driver.remove = i2c_device_remove;

retval = driver_register(&driver->driver);
if (retval)
return retval;

This sets up the driver core structure to have the same name as the driver and a bus type of i2c_bus_type; the probe and remove functions are set to local i2c functions. For now, these functions are declared as:
int i2c_device_probe(struct device *dev)
{
return -ENODEV;
}

int i2c_device_remove(struct device *dev)
{
return 0;
}

because no i2c device support has been added yet. These functions will be called when an i2c device is added or removed from the driver core, but that will be described in the next column.


When the i2c_add_driver() is called, the driver is registered with the i2c_bus_type, and it shows up in sysfs as:

$ tree /sys/bus/i2c/
/sys/bus/i2c/
-- devices
`-- drivers
-- EEPROM READER
`-- W83781D sensors


To remove an i2c driver from the system, the i2c_del_driver() function is called. In order to remove the i2c driver from the driver core that was registered with the call to driver_register, the following line of code is added to this function:

driver_unregister(&driver->driver);






Conclusion


We have covered the basics of the new driver core, and to help understand how this driver model affects different subsystems, we covered the changes needed to convert the i2c core to support the kernel core bus and driver model. In the next Driving Me Nuts column, we will cover how to add i2c device support and how the probe() and remove() functions should look.


 
I2C Drivers, Part II



Here's what has to happen to read the sensors that report the temperature, fan speed and other important system health information.




In my last column [LJ, December 2003], we discussed how I2C bus drivers and I2C algorithm drivers work. We also described how to make a tiny dummy I2C bus driver. This month, we discuss how an I2C chip driver works and provide an example of one in action.


An I2C chip driver controls the process of talking to an individual I2C device that lives on an I2C bus. I2C chip devices usually monitor a number of different physical devices on a motherboard, such as the different fan speeds, temperature values and voltages.


The struct i2c_driver structure describes a I2C chip driver. This structure is defined in the include/linux/i2c.h file. Only the following fields are necessary to create a working chip driver:





  • struct module *owner; - set to the value THIS_MODULE that allows the proper module reference counting.



  • char name[I2C_NAME_SIZE]; - set to a descriptive name of the I2C chip driver. This value shows up in the sysfs file name created for every I2C chip device.



  • unsigned int flags; - set to the value I2C_DF_NOTIFY in order for the chip driver to be notified of any new I2C devices loaded after this driver is loaded. This field probably will go away soon, as almost all drivers set this field.



  • int (*attach_adapter)(struct i2c_adapter *); - called whenever a new I2C bus driver is loaded in the system. This function is described in more detail below.



  • int (*detach_client)(struct i2c_client *); - called when the i2c_client device is to be removed from the system. More information about this function is provided below.


The following code is from an example I2C chip driver called tiny_i2c_chip.c., which is available from the Linux Journal FTP site [ftp.ssc.com/pub/lj/listings/issue118/7252.tgz]. It shows how the struct i2c_driver structure is set up:


static struct i2c_driver chip_driver = {
.owner = THIS_MODULE,
.name = "tiny_chip",
.flags = I2C_DF_NOTIFY,
.attach_adapter = chip_attach_adapter,
.detach_client = chip_detach_client,
};






Registering a Chip Driver


To register this I2C chip driver, the function i2c_add_driver should be called with a pointer to the struct i2c_driver: Garrick, please kern the double underscores below.


static int __init tiny_init(void)
{
return i2c_add_driver(&chip_driver);
}




To unregister the I2C chip driver, the i2c_del_driver function should be called with the same pointer to the struct i2c_driver:


static void __exit tiny_exit(void)
{
i2c_del_driver(&chip_driver);
}




After the I2C chip driver is registered, the attach_adapter function callback is called when an I2C bus driver is loaded. This function checks to see if any I2C devices are on this I2C bus to which the client driver wants to attach. Almost all I2C chip drivers call the core I2C function i2c_detect to determine this. For example, the tiny_i2c_chip.c driver does this:


static int
chip_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_detect(adapter, &addr_data,
chip_detect);
}




The i2c_detect function probes the I2C adapter, looking for the different addresses specified in the addr_data structure. If a device is found, the chip_detect function then is called.


If you look closely at the source code, you cannot find the addr_data structure anywhere. The reason for this is it is created by the SENSORS_INSMOD_1 macro. This macro is defined in the include/linux/i2c-sensor.h file and is quite complicated. It sets up a static variable called addr_data based on the number of different types of chips that this driver supports and the addresses at which these chips typically are present. It then provides the ability to override these values by using module parameters. An I2C chip driver must provide the variables normal_i2c, normal_i2c_range, normal_isa and normal_isa_range. These variables define the i2c smbus and i2c isa addresses this chip driver supports. They are an array of addresses, all terminated by either the special value I2C_CLIENT_END or I2C_CLIENT_ISA_END. Usually a specific type of I2C chip shows up in only a limited range of addresses. The tiny_i2c_client.c driver defines these variables as:


static unsigned short normal_i2c[] =
{ I2C_CLIENT_END };
static unsigned short normal_i2c_range[] =
{ 0x00, 0xff, I2C_CLIENT_END };
static unsigned int normal_isa[] =
{ I2C_CLIENT_ISA_END };
static unsigned int normal_isa_range[] =
{ I2C_CLIENT_ISA_END };




The normal_i2c_range variable specifies that we can find this chip device at any I2C smbus address. This allows us to test this driver on almost any I2C bus driver.




What to Do When the Chip Is Found


In the tiny_i2c_chip.c driver, when an I2C chip device is found, the function chip_detect is called by the I2C core. This function is declared with the following parameters:


static int
chip_detect(struct i2c_adapter *adapter,
int address, int kind);




The adapter variable is the I2C adapter structure on which this chip is located. The address variable contains the address where the chip was found, and the kind variable indicates what kind of chip was found. The kind variable usually is ignored, but some I2C chip drivers support different kinds of I2C chips, so this variable can be used to determine the type of chip present.


This function is responsible for creating a struct i2c_client structure that then is registered with the I2C core. The I2C core uses that structure as an individual I2C chip device. To create this structure, the chip_detect function does the following:


struct i2c_client *new_client = NULL;
struct chip_data *data = NULL;
int err = 0;
new_client = kmalloc(sizeof(*new_client),
GFP_KERNEL);
if (!new_client) {
err = -ENOMEM;
goto error;
}
memset(new_client, 0x00, sizeof(*new_client));
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto error;
}
memset(data, 0x00, sizeof(*data));
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &chip_driver;
new_client->flags = 0;
strncpy(new_client->name, "tiny_chip",
I2C_NAME_SIZE);




First, the struct i2c_client structure and a separate local data structure (called struct chip_data) are created and initialized to zero. It is important that the i2c_client structure is initialized to zero, as the lower levels of the kernel driver core require this in order to work properly. After the memory is allocated successfully, some fields in the struct i2c_client are set to point to this specific device and this specific driver. Notably, the addr, adapter and driver variables must be initialized. The name of the struct i2c_client also must be set if it is to show up properly in the sysfs tree for this I2C device.


After the struct i2c_client structure is initialized, it must be registered with the I2C core. This is done with a call to the i2c_attach_client function:


/* Tell the I2C layer a new client has arrived */
err = i2c_attach_client(new_client);
if (err)
goto error;




When this function returns, with no errors reported, the I2C chip device is set up properly in the kernel.




I2C and sysfs


In the 2.0, 2.2 and 2.4 kernels, the I2C code would place the I2C chip devices in the /proc/bus/i2c directory. In the 2.6 kernel, all I2C chip devices and adapters show up in the sysfs filesystem. I2C chip devices can be found at /sys/bus/i2c/devices, listed by their adapter address and chip address. For example, the tiny_i2c_chip driver loaded on a machine might produce the following sysfs tree structure:

Garrick, use small font size for the listing below.

$ tree /sys/bus/i2c/
/sys/bus/i2c/
-- devices
-- 0-0009 -> ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0009
-- 0-000a -> ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000a
-- 0-000b -> ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000b
`-- 0-0019 -> ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0019
`-- drivers
-- i2c_adapter
`-- tiny_chip
-- 0-0009 -> ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0009
-- 0-000a -> ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000a
-- 0-000b -> ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000b
`-- 0-0019 -> ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0019




This shows four different I2C chip devices, all controlled by the same tiny_chip driver. The controlling driver can be located by looking at the devices in the /sys/bus/i2c/drivers directory or by looking in the directory of the chip device itself and reading the name file: Garrick, please use small font below.

$ cat /sys/devices/pci0000\:00/0000\:00\:06.0/i2c-0/0-0009/name
tiny_chip




All I2C chip drivers export the different sensor values through sysfs files within the I2C chip device directory. These filenames are standardized, along with the units in which the values are expressed, and are documented within the kernel tree in the file Documentation/i2c/sysfs-interface (Table 1).



Table 1. Sensor Values Exported through sysfs Files















temp_max[1-3]Temperature max value. Fixed point value in form XXXXX and should be divided by 1,000 to get degrees Celsius. Read/Write value.
temp_min[1-3]Temperature min or hysteresis value. Fixed point value in form XXXXX and should be divided by 1,000 to get degrees Celsius. This is preferably a hysteresis value, reported as an absolute temperature, not a delta from the max value. Read/Write value.
temp_input[1-3]Temperature input value. Read-only value.

As the information in Table 1 shows, there is only one value per file. All files are readable and some can be written to by users with the proper privileges.


The tiny_i2c_chip.c driver emulates an I2C chip device that can report temperature values. It creates the files, temp_max1, temp_min1 and temp_input1 in sysfs. The values it returns when these files are read from is incremented every time the file is read to show how to access different unique chip values.


In order to create a file in sysfs, the DEVICE_ATTR macro is used:


static DEVICE_ATTR(temp_max, S_IWUSR S_IRUGO,
show_temp_max, set_temp_max);
static DEVICE_ATTR(temp_min, S_IWUSR S_IRUGO,
show_temp_hyst, set_temp_hyst);
static DEVICE_ATTR(temp_input, S_IRUGO,
show_temp_input, NULL);




This macro creates a structure that then is passed to the function device_create_file at the end of the chip_detect function:


/* Register sysfs files */
device_create_file(&new_client->dev,
&dev_attr_temp_max);
device_create_file(&new_client->dev,
&dev_attr_temp_min);
device_create_file(&new_client->dev,
&dev_attr_temp_input);







That call creates the sysfs files for the device:

/sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009
-- detach_state
-- name
-- power
`-- state
-- temp_input
-- temp_max
`-- temp_min




The file name is created by the I2C core, and the files detach_state and power/state are created by the driver core.


But, let's go back to the DEVICE_ATTR macro. That macro wants to know the name of the file to be created, the mode of the file to be created, the name of the function to be called when the file is read from and the name of the function to be called when the file is written to. For the file temp_max, this declaration was:


static DEVICE_ATTR(temp_max, S_IWUSR S_IRUGO,
show_temp_max, set_temp_max);




The function called when the file is read from is show_temp_max. This is defined, as are many sysfs files, with another macro that creates a function:


#define show(value) static ssize_t show_##value(struct device *dev, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct chip_data *data = i2c_get_clientdata(client); chip_update_client(client); return sprintf(buf, "%d\n", data->value); }
show(temp_max);
show(temp_hyst);
show(temp_input);







The reason this function is created with a macro is that it is quite simple to create other sysfs files that do almost the same thing, with different names and that read from different variables, without having to duplicate code. This single macro creates three different functions to read from three different variables from the struct chip_data structure.


In this function, the struct device * is converted into a struct i2c_client *. Then the private struct chip_data * is obtained from the struct i2c_client *. After that the chip data is updated with a call to chip_update_client. From there, the variable that has been asked for is printed into a buffer and returned to the driver core, which then returns it to the user: Garrick, please use a small font below.

           
$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_input
1




The chip_update_client increments all values by one every time it is called: Garrick, please kern the double underscores below.


static void
chip_update_client(struct i2c_client *client)
{
struct chip_data *data =
i2c_get_clientdata(client);
down(&data->update_lock);
dev_dbg(&client->dev, "%s\n", __FUNCTION__);
++data->temp_input;
++data->temp_max;
++data->temp_hyst;
data->last_updated = jiffies;
data->valid = 1;
up(&data->update_lock);
}







So, all subsequent requests for this value are different: Garrick, please use small font below.

$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_input
2
$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_input
3




The set_temp_max function also is created from a macro to allow variables to be written to:


#define set(value, reg) static ssize_t set_##value(struct device *dev, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct chip_data *data = i2c_get_clientdata(client); int temp = simple_strtoul(buf, NULL, 10); down(&data->update_lock); data->value = temp; up(&data->update_lock); return count; }
set(temp_max, REG_TEMP_OS);
set(temp_hyst, REG_TEMP_HYST);




Just like the show functions, this function converts the struct device * to a struct i2c_client *, and then the private struct chip_data * is found. The data the user provides then is turned into a number with a call to simple_strtoul and is saved into the proper variable: Garrick, please use small font below.

$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_max
1
$ echo 41 > /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_max
$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_max
42






Cleaning Up


When the I2C chip device is removed from the system, either by the I2C bus driver being unloaded or by the I2C chip driver being unloaded, the I2C core calls the detatch_client function specified in the struct i2c_driver structure. This usually is a simple function, as can be seen in the example driver's implementation: Garrick, please use small font below.


static int chip_detach_client(struct i2c_client *client)
{
struct chip_data *data = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
if (err) {
dev_err(&client->dev,
"Client deregistration failed, "
"client not detached.\n");
return err;
}
kfree(client);
kfree(data);
return 0;
}




As the i2c_attach_client function was called to register the struct i2c_client structure with the I2C core, the i2c_detach_client function must be called to unregister it. If that function succeeds, the memory the driver has allocated for the I2C device then needs to be freed before returning from the function.


This example driver does not specifically remove the sysfs files from the sysfs core. This step is done automatically in the driver core within the i2c_detach_client function. But if the author would like, the file can be removed manually by a call to device_remove_file.




Conclusion


This two-part series of articles has explained the basics of how to write a kernel I2C bus driver, I2C algorithm driver and I2C chip driver. A lot of good information on how to write I2C drivers can be found in the Documentation/i2c directory in the kernel tree and on the Lm_sensors Web site (secure.netroedge.com/~lm78).


Greg Kroah-Hartman currently is the Linux kernel maintainer for a variety of different driver subsystems. He works for IBM, doing Linux kernel-related things, and can be reached at greg@kroah.com. 7252aa.tif


 
I2C Drivers, Part I



The I2C bus helps you monitor the health of your system. Here's how to develop a driver that will get you all the hardware info you need to know.




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.




I2C Bus Drivers


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.ssc.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);






I2C Algorithm Drivers


An I2C algorithm is used by the I2C bus driver to talk to the I2C bus. Most I2C bus drivers define their own I2C algorithms and use them, as they are tied closely to how the bus driver talks to that specific type of hardware. For some classes of I2C bus drivers, a number of I2C algorithm drivers already have been written. Examples of these are ITE adapters found in drivers/i2c/i2c-algo-ite.c, IBM PPC 405 adapters found in drivers/i2c/i2c-algo-ibm_ocp.c and a generic I2C bit shift algorithm found in drivers/i2c/i2c-algo-bit.c. All of these already written algorithms have their own functions with which an I2C bus driver needs to register to use. For more information on these, please see all of the drivers/i2c/i2c-algo-*.c files in the kernel tree.


For our example driver, we are going to create our own I2C algorithm driver. An algorithm driver is defined by a struct i2c_algorithm structure and is defined in the include/linux/i2c.h file. Here is a description of some of the commonly used fields:





  • char name[32];: the name of the algorithm.



  • unsigned int id;: description of the type of algorithm this structure defines. These different types are defined in the include/linux/i2c-id.h file and start with the characters I2C_ALGO_.



  • int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], int num);: a function pointer to be set if this algorithm driver can do I2C direct-level accesses. If it is set, this function is called whenever an I2C chip driver wants to communicate with the chip device. If it is set to NULL, the smbus_xfer function is used instead.



  • int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data);: a function pointer to be set if this algorithm driver can do SMB bus accesses. Most PCI-based I2C bus drivers are able to do this, and they should set this function pointer. If it is set, this function is called whenever an I2C chip driver wants to communicate with the chip device. If it is set to NULL, the master_xfer function is used instead.



  • u32 (*functionality) (struct i2c_adapter *);: a function pointer called by the I2C core to determine what kind of reads and writes the I2C adapter driver can do.


In our example I2C adapter driver, the i2c_adapter structure referenced the tiny_algorithm variable. That structure is defined as the following:


static struct i2c_algorithm tiny_algorithm = {
.name = "tiny algorithm",
.id = I2C_ALGO_SMBUS,
.smbus_xfer = tiny_access,
.functionality = tiny_func,
};




The tiny_func function is small and tells the I2C core what types of I2C messages this algorithm can support. For this driver, we want to be able to support a few different I2C message types:


static u32 tiny_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK
I2C_FUNC_SMBUS_BYTE
I2C_FUNC_SMBUS_BYTE_DATA
I2C_FUNC_SMBUS_WORD_DATA
I2C_FUNC_SMBUS_BLOCK_DATA;
}







All of the different I2C message types are defined in include/linux/i2c.h and start with the characters I2C_FUNC_.


The tiny_access function is called when an I2C client driver wants to talk to the I2C bus. Our example function is quite simple; it merely logs all of the requests the I2C chip driver makes to the syslog and reports success back to the caller. This log allows you to see all of the different addresses and data types that an I2C chip driver may request. The implementation looks like: Garrick, please kern the double underscores in the code below.


static s32 tiny_access(struct i2c_adapter *adap,
u16 addr,
unsigned short flags,
char read_write,
u8 command,
int size,
union i2c_smbus_data *data)
{
int i, len;
dev_info(&adap->dev, "%s was called with the "
"following parameters:\n",
__FUNCTION__);
dev_info(&adap->dev, "addr = %.4x\n", addr);
dev_info(&adap->dev, "flags = %.4x\n", flags);
dev_info(&adap->dev, "read_write = %s\n",
read_write == I2C_SMBUS_WRITE ?
"write" : "read");
dev_info(&adap->dev, "command = %d\n",
command);
switch (size) {
case I2C_SMBUS_PROC_CALL:
dev_info(&adap->dev,
"size = I2C_SMBUS_PROC_CALL\n");
break;
case I2C_SMBUS_QUICK:
dev_info(&adap->dev,
"size = I2C_SMBUS_QUICK\n");
break;
case I2C_SMBUS_BYTE:
dev_info(&adap->dev,
"size = I2C_SMBUS_BYTE\n");
break;
case I2C_SMBUS_BYTE_DATA:
dev_info(&adap->dev,
"size = I2C_SMBUS_BYTE_DATA\n");
if (read_write == I2C_SMBUS_WRITE)
dev_info(&adap->dev,
"data = %.2x\n", data->byte);
break;
case I2C_SMBUS_WORD_DATA:
dev_info(&adap->dev,
"size = I2C_SMBUS_WORD_DATA\n");
if (read_write == I2C_SMBUS_WRITE)
dev_info(&adap->dev,
"data = %.4x\n", data->word);
break;
case I2C_SMBUS_BLOCK_DATA:
dev_info(&adap->dev,
"size = I2C_SMBUS_BLOCK_DATA\n");
if (read_write == I2C_SMBUS_WRITE) {
dev_info(&adap->dev, "data = %.4x\n",
data->word);
len = data->block[0];
if (len < 0)
len = 0;
if (len > 32)
len = 32;
for (i = 1; i <= len; i++)
dev_info(&adap->dev,
"data->block[%d] = %x\n",
i, data->block[i]);
}
break;
}
return 0;
}




Now that the tiny_i2c_adap driver is built and loaded, what can it do? On its own, it cannot do anything. An I2C bus driver needs an I2C client driver in order to do anything besides sit in the sysfs tree. So, if the lm75 I2C client driver is loaded, it tries to use the tiny_i2c_adap driver to find the chip for which it was written: Garrick, please use a small font so these lines don't have to break.

$ modprobe lm75
$ tree /sys/bus/i2c/
/sys/bus/i2c/
-- devices
-- 0-0048 -> ../../../devices/legacy/i2c-0/0-0048
-- 0-0049 -> ../../../devices/legacy/i2c-0/0-0049
-- 0-004a -> ../../../devices/legacy/i2c-0/0-004a
-- 0-004b -> ../../../devices/legacy/i2c-0/0-004b
-- 0-004c -> ../../../devices/legacy/i2c-0/0-004c
-- 0-004d -> ../../../devices/legacy/i2c-0/0-004d
-- 0-004e -> ../../../devices/legacy/i2c-0/0-004e
`-- 0-004f -> ../../../devices/legacy/i2c-0/0-004f
`-- drivers
-- i2c_adapter
`-- lm75
-- 0-0048 -> ../../../../devices/legacy/i2c-0/0-0048
-- 0-0049 -> ../../../../devices/legacy/i2c-0/0-0049
-- 0-004a -> ../../../../devices/legacy/i2c-0/0-004a
-- 0-004b -> ../../../../devices/legacy/i2c-0/0-004b
-- 0-004c -> ../../../../devices/legacy/i2c-0/0-004c
-- 0-004d -> ../../../../devices/legacy/i2c-0/0-004d
-- 0-004e -> ../../../../devices/legacy/i2c-0/0-004e
`-- 0-004f -> ../../../../devices/legacy/i2c-0/0-004f




Because the tiny_i2c_adap driver responds with a success to every read and write request it is asked to accomplish, the lm75 I2C chip driver thinks it has found an lm75 chip at every known possible I2C address for this chip. This abundance of addresses is why I2C devices 0-0048 through 0-004f have been created. If we look at the directory for one of these devices, the sensor files for this chip driver are shown:

$ tree /sys/devices/legacy/i2c-0/0-0048/
/sys/devices/legacy/i2c-0/0-0048/
-- detach_state
-- name
-- power
`-- state
-- temp_input
-- temp_max
`-- temp_min







The detach_state file and power directory is created by the kernel driver core and is used for power management. It is not created by the lm75 driver. The functions of the other files in this directory are described below.


If we ask the lm75 driver for the current value of temp_max, we receive the following:

$ cat /sys/devices/legacy/i2c-0/0-0048/temp_max
1000




To get that value, the lm75 driver asked the tiny_i2c_adap driver to read some addresses on the I2C bus. This request is shown in the syslog: Garrick, please use a really small font so this will fit without breaking the lines.

$ dmesg
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = read
i2c_adapter i2c-0: command = 0
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = read
i2c_adapter i2c-0: command = 3
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = read
i2c_adapter i2c-0: command = 2
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA




The log file shows that the tiny_access function was called three times. The first command wanted to read a word of data from register 0 out of the device with the address 0048. The second and third reads asked for register 3 and register 2 from the same device. The commands match up with the following code from the drivers/i2c/chips/lm75.c file in the lm75_update_client function:


data->temp_input = lm75_read_value(client,
LM75_REG_TEMP);
data->temp_max = lm75_read_value(client,
LM75_REG_TEMP_OS);
data->temp_hyst = lm75_read_value(client,
LM75_REG_TEMP_HYST);




The lm75_read_value function in that same file contains the following code:


/* All registers are word-sized, except for the
configuration register. LM75 uses a high-byte
first convention, which is exactly opposite to
the usual practice. */
static int lm75_read_value(struct i2c_client
*client, u8 reg)
{
if (reg == LM75_REG_CONF)
return i2c_smbus_read_byte_data(client,
reg);
else
return swap_bytes(
i2c_smbus_read_word_data(client,
reg));
}




Therefore, when the lm75 driver wants to read the value of the max temperature, it calls the lm75_read_value function with the register number, which then calls the I2C core function i2c_smbus_read_word_data. That I2C core function looks up on which I2C bus the client device is, and then it calls the I2C algorithm associated with that specific I2C bus to do the data transfer. This is the method, then, by which our tiny_i2c_adap driver is asked to complete the transfer.


If this same sysfs file is written to, the lm75 driver asks the tiny_i2c_adap driver to write some data to a specific address on the I2C bus in the same way the read was requested. This request also is shown in the syslog: Garrick, again, use small font below.

$ echo 300 > /sys/devices/legacy/i2c-0/0-0048/temp_max
$ dmesg
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = write
i2c_adapter i2c-0: command = 3
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA
i2c_adapter i2c-0: data = 8000






Conclusion


This month we covered the basics of the I2C driver subsystem and explained how to write a simple I2C bus and I2C algorithm driver that work with any existing I2C client driver. The complete driver, dmn-09-i2c-adap.c, is available from the Linux Journal FTP site at ftp.ssc.com/pub/lj/listings/issue116/7136.tgz. In Part II, we will cover how to write an I2C chip driver.


Greg Kroah-Hartman currently is the Linux kernel maintainer for a variety of different driver subsystems. He works for IBM, doing Linux kernel-related things and can be reached at greg@kroah.com. 7136aa.tif



Powered by Blogger