Author: Liu Hongtao,Hua Qing vision embedded college lecturer.
4. Writing I2C device drivers in the kernel
The previous article introduced the use of/dev/i2c-0 in the application layer to complete the operation of I2C devices, but many times we are still used to writing drivers for I2C devices in the kernel layer. Currently, the kernel supports writing I2C drivers. The following describes the implementation of these two methods. The two methods are respectively named "adapter method (legacy)" and "probe method (New Style )".
(1) Adapter method (legacy)
(The following instance code is modified on the basis of the kernel pca953x. c 2.6.27. The original code uses the 2nd methods to be discussed in this article, that is, the probe method)
● Build i2c_driver
Static struct i2c_driver pca953x_driver = {
. Driver = {
. Name = "pca953x", // name
},
. ID = id_pca9555, // ID
. Attach_adapter = pca953x_attach_adapter, // call the adapter to connect to the device
. Detach_client = pca953x_detach_client, // disconnect the device from the adapter
};
● Register i2c_driver
Static int _ init pca953x_init (void)
{
Return i2c_add_driver (& pca953x_driver );
}
Module_init (pca953x_init );
● Attach_adapter action
After i2c_add_driver (& pca953x_driver) is executed, if the I2C adapter has been registered in the kernel, these adapters are called sequentially to connect to our I2C device. This process is completed by calling the attach_adapter method in i2c_driver. The specific implementation form is as follows:
Static int pca953x_attach_adapter (struct i2c_adapter * adapter)
{
Return i2c_probe (adapter, & addr_data, pca953x_detect );
/*
Adapter: Adapter
Addr_data: address information
Pca953x_detect: The function called after the device is detected.
*/
}
The address information addr_data is specified by the following code.
/* Addresses to scan */
Static unsigned short normal_i2c [] = {0x20, 0x24, 0x25, 0x26, 0x27, i2c_client_end };
I2c_client_insmod;
Note: The address in normal_i2c must be the address of your I2C chip. Otherwise, the device cannot be correctly detected. I2C _ client_insmod is a macro that uses normal_i2c to build addr_data.
● Build the i2c_client and register the character Device Driver
After detecting the target device, i2c_probe calls pca953x_detect and uses the current detection address as the parameter.
Static int pca953x_detect (struct i2c_adapter * adapter, int address, int kind)
{
Struct i2c_client * new_client;
Struct pca953x_chip * chip; // device structure
Int err = 0, result;
Dev_t pca953x_dev = mkdev (pca953x_major, 0); // build the device number. Set it based on the actual situation. Here I only consider that there is only one address matching in normal_i2c.
If (! I2c_check_functionality (adapter, i2c_func_smbus_byte_data | i2c_func_smbus_word_data) // determine the adapter capability
Goto exit;
If (! (Chip = kzarloc (sizeof (struct pca953x_chip), gfp_kernel ))){
Err =-enomem;
Goto exit;
}
/***** Build i2c-client ****/
Chip-> client = kzarloc (sizeof (struct i2c_client), gfp_kernel );
New_client = chip-> client;
I2c_set_clientdata (new_client, Chip );
New_client-> ADDR = address;
New_client-> adapter = adapter;
New_client-> driver = & pca953x_driver;
New_client-> flags = 0;
Strlcpy (new_client-> name, "pca953x", i2c_name_size );
If (ERR = i2c_attach_client (new_client) // register i2c_client
Goto exit_kfree;
If (ERR)
Goto exit_detach;
If (pca953x_major)
{
Result = register_chrdev_region (pca953x_dev, 1, "pca953x ");
}
Else {
Result = alloc_chrdev_region (& pca953x_dev, 0, 1, "pca953x ");
Pca953x_major = major (pca953x_dev );
}
If (result <0 ){
Printk (kern_notice "unable to get pca953x region, error % d/N", result );
Return result;
}
Pca953x_setup_cdev (chip, 0); // register a character device.
Return 0;
Exit_detach:
I2c_detach_client (new_client );
Exit_kfree:
Kfree (CHIP );
Exit:
Return err;
}
I2c_check_functionality is used to determine the ability to set the token, which is very important. You can also directly view the capabilities of setting up a token, as shown in figure
Static const struct i2c_algorithm smbus_algorithm = {
. Smbus_xfer = i801_access,
. Functionality = i801_func,
};
Static u32 i801_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 | i2c_func_smbus_write_i2c_block
| (Isich4? I2c_func_smbus_hwpec_calc: 0 );
}
● Character-driven implementation
Struct file_operations pca953x_fops = {
. Owner = this_module,
. IOCTL = pca953x_ioctl,
. Open = pca953x_open,
. Release = pca953x_release,
};
There is nothing to say about the character device driver itself. Here we mainly want to talk about how to call the I2C settings in the driver to help us complete data transmission.
Currently, the primary transport modes are smbus_xfer and master_xfer. In general, if the primary node supports master_xfer, it can also simulate support for SMBus transmission. However, if only smbus_xfer is implemented, some I2C transmission is not supported.
INT (* master_xfer) (struct i2c_adapter * ADAP, struct i2c_msg * msgs, int num );
INT (* smbus_xfer) (struct i2c_adapter * ADAP, 2010addr,
Unsigned short flags, char read_write,
U8 command, int size, Union i2c_smbus_data * data );
The parameter settings in master_xfer are consistent with the preceding user space programming. Now we only need to build relevant parameters in the driver and then call i2c_transfer to complete the transmission.
Int i2c_transfer (struct i2c_adapter * ADAP, struct i2c_msg * msgs, int num)
The parameter settings and call methods in smbus_xfer are as follows:
Static int pca953x_write_reg (struct pca953x_chip * chip, int Reg, uint16_t Val)
{
Int ret;
Ret = i2c_smbus_write_word_data (chip-> client, Reg <1, Val );
If (Ret <0 ){
Dev_err (& Chip-> client-> Dev, "failed writing register/N ");
Return-EIO;
}
Return 0;
}
The above function completes writing a 16-bit data to the Register of the chip address Reg. The implementation of i2c_smbus_write_word_data is as follows:
S32 i2c_smbus_write_word_data (struct i2c_client * client, u8 command, 2010value)
{
Union i2c_smbus_data data;
Data. Word = value;
Return i2c_smbus_xfer (client-> adapter, client-> ADDR, client-> flags,
I2c_smbus_write, command,
I2c_smbus_word_data, & data );
}
We can see that SMBus transfers a 16-bit data method. Other operations such as: character writing, character reading, Word Reading, block operations, can refer to the kernel i2c-core.c provided in the method.
● Cancel i2c_driver
Static void _ exit pca953x_exit (void)
{
I2c_del_driver (& pca953x_driver );
}
Module_exit (pca953x_exit );
● Detach_client action
Call the adapter registered in the kernel in sequence to disconnect the registered I2C device. This process is completed by calling the attach_adapter method in i2c_driver. The specific implementation form is as follows:
Static int pca953x_detach_client (struct i2c_client * client)
{
Int err;
Struct pca953x_chip * data;
If (ERR = i2c_detach_client (client) // disconnect i2c_client
Return err;
Data = i2c_get_clientdata (client );
Cdev_del (& (data-> cdev ));
Unregister_chrdev_region (mkdev (pca953x_major, 0), 1 );
Kfree (data-> client );
Kfree (data );
Return 0;
}
(2) Probe Method (New Style)
● Build i2c_driver
Like legacy, i2c_driver also needs to be built, but the content is different.
Static struct i2c_driver pca953x_driver = {
. Driver = {
. Name = "pca953x ",
},
. Probe = pca953x_probe, // called when the i2c_client and i2c_driver match
. Remove = pca953x_remove, // called upon Cancellation
. Id_table = pca953x_id, // matching rule
};
● Register i2c_driver
Static int _ init pca953x_init (void)
{
Return i2c_add_driver (& pca953x_driver );
}
Module_init (pca953x_init );
During i2c_driver registration, the driver is registered to the i2c_bus_type bus. The matching rules for this bus are:
Static const struct i2c_device_id * i2c_match_id (const struct i2c_device_id * ID,
Const struct i2c_client * client)
{
While (ID-> name [0]) {
If (strcmp (client-> name, ID-> name) = 0)
Return ID;
Id ++;
}
Return NULL;
}
We can see that the i2c_client name is used to match the id_table name. The id_table in this driver is
Static const struct i2c_device_id pca953x_id [] = {
{"Pca9534", 8 ,},
{"Pca9535", 16 ,},
{"Pca9536", 4 ,},
{"Pca9537", 4 ,},
{"Pca9538", 8 ,},
{"Pca9539", 16 ,},
{"Pca9554", 8 ,},
{"Pca9555", 16 ,},
{"Pca9557", 8 ,},
{"Max7310", 8 ,},
{}
};
Now we have such a question: In adapter mode, i2c_client is constructed by ourselves. Where does the current i2c_client come from? Let's take a look at the following explanation:
● Register i2c_board_info
For probe mode, i2c_board_info is usually registered in the platform code. The method is as follows:
Static struct i2c_board_info _ initdata test_i2c_devices [] = {
{
I2c_board_info ("pca9555", 0x27), // pca9555 is the chip name, 0x27 is the chip address
. Platform_data = & pca9555_data,
},{
I2c_board_info ("mt9v022", 0x48 ),
. Platform_data = & iclink [0],/* with extender */
},{
I2c_board_info ("mt9m001", 0x5d ),
. Platform_data = & iclink [0],/* with extender */
},
};
I2c_register_board_info (0, test_i2c_devices, array_size (test_i2c_devices); // register
I2c_client is built during the registration process. Note that i2c_register_board_info is not used by the module.
● Character drive Registration
In probe mode, the position where the character driver is added is in pca953x_probe.
Static int _ devinit pca953x_probe (struct i2c_client * client, const struct i2c_device_id * ID)
{
......
/***** Character device driver registration location ****/
......
Return 0;
}
● Cancel i2c_driver
Static void _ exit pca953x_exit (void)
{
I2c_del_driver (& pca953x_driver );
}
Module_exit (pca953x_exit );
● Deregister the character Device Driver
In probe mode, the position of the deregister character driver is in pca953x_remove.
Static int _ devinit pca953x_remove (struct i2c_client * client)
{
......
/***** Character device driver logout location ****/
......
Return 0;
}
● The data interaction method of the I2C device (that is, the method for calling the adapter to operate the device) is the same as that of the adapter.