Overview of Linux I2C Driver Architecture

  

The I2C bus has recently been involved because of work. Although I used I2c in the past, I saw that after a Linux kernel, a layer can be improved.

1. Linux I2C Driver Architecture

The I2C bus driver in Linux is divided into two parts, bus driver (BUS) and device driver (DEVICE). The responsibility of the bus driver is to add corresponding read and write methods for each I2C bus in the system. But the bus driver itself does not do any communication, it just exists there, waiting for the device driver to call its function.


A device driver is a driver that communicates with a specific device that is attached to the I2C bus. Through the functions provided by the I2C bus driver, the device driver can ignore the differences between different bus controllers and communicate with the hardware devices without regard to its implementation details.


1.1 Bus Driver

When the system is powered on, the I2C bus driver is loaded first. A bus driver is used to support reading and writing of a particular I2C bus. A bus driver usually requires two modules, a struct i2c_adapter and a struct i2c_algorithm to describe:

static struct i2c_adapter pb1550_board_adapter = {

name: "pb1550 adapter",

id: I2C_HW_AU1550_PSC,

algo: NULL,

algo_data: &pb1550_i2c_info,

inc_use: pb1550_inc_use,

dec_use: pb1550_dec_use,

client_register: pb1550_reg,

client_unregister: pb1550_unreg,

client_count: 0,

};


This sample A driver called "pb1550 adapter" is attached. But this module does not provide read and write functions, the specific read and write methods are provided by the second module, struct i2c_algorithm.


static struct i2c_algorithm au1550_algo = {

.name = "Au1550 algorithm",

.id = I2C_ALGO_AU1550,

.master_xfer = au1550_xfer,

.functionality = au1550_func,

};


i2c_adap->algo = &au1550_algo;


This example adds read-write &ld;;algorithm> to the above bus driver. Normally, each I2C bus driver defines its own read and write algorithm, but since some buses use the same algorithm, they can share the same set of read and write functions. The driver in this example defines its own read and write algorithm module, called "Au1550 algorithm".


After all is completed, by calling:

i2c_add_adapter(i2c_adap);


Registering these two modules to In the operating system
, the bus driver is installed. For the AMD au1550, this part has been provided by AMD.

1.2 Device Drivers

As mentioned above, the bus driver only provides a read/write mechanism for a bus, and does not communicate itself. Communication is done by the I2C device driver, and the device driver communicates with the specific device through the I2C bus. A device driver has two modules to describe, struct i2c_driver and struct i2c_client.


When the system is powered on and the I2C bus driver is loaded, the device driver can be loaded. First load the following structure:


static struct i2c_driver driver = {

.name = "i2c TV tuner driver",

.id = I2C_DRIVERID_TUNER,

.flags = I2C_DF_NOTIFY,

.attach_adapter = tuner_probe,

.detach_client = tuner_detach,

.command = tuner_command,

};


i2c_add_driver(&driver);


Once the i2c_driver is loaded, the attach_adapter function will be called. . In it, you can traverse each i2c bus driver in the system to detect the device you want to access:


static int tuner_probe(struct i2c_adapter *adap)

{

return i2c_probe(adap, &addr_data, tuner_attach);

}


Note that multiple devices may be found, so not only an I2C bus can Hanging multiple different types of devices, one device driver can also serve devices hanging on multiple different I2C buses at the same time.


Whenever a device driver detects a device it can support, it creates a struct i2c_client to identify the device:

new_client->addr = address;

new_client->adapter = adapter;

new_client->driver = &driver;


/* Tell the I2C layer a new Client has arrived */

err = i2c_attach_client(new_client);

if (err)

goto error;


visible An i2c_client represents a device that is located on the adapter bus and has an address of address and is driven by a driver. It binds the bus driver to the device driver and the device address. An i2c_client represents an I2C device.


When I get an I2C device, I can read and write this device directly:

/*

* The master routines are the ones normally Used to transmit data to devices

* on a bus (or read from them). Apart from two basic transfer functions to

* transmit one message at a time, a more complex version can be Used to

* transmit an arbitrary number of messages without interruption.

*/

extern int i2c_master_send(struct i2c_client *,const char* ,int);

extern int i2c_master_recv(struct i2c_client *,char* , int);


As in the usual sense of reading and writing functions, these two functions specify the device for the i2c_client pointer, Read and write int char. The return value is the number of bytes read and written. For our existing SLIC driver, as long as the data to be read and written on the bus is transferred to these two functions, the migration work is completed, we will get a Linux version of the I2C device driver.

Copyright © Windows knowledge All Rights Reserved