Blog master Press: In fact, I have long wanted to write this I2C, during which there are a variety of things to delay. Write this for reference by the comrades during the May Day holiday. It will take some time to study the kernel in the future. Although I have some knowledge about the kernel before, I still don't have a system. The hardware structure of I2C is not complex. An adapter adds several devices. The architecture of the driver in Linux is quite complex and simple. In this article, I still use the actual example to introduce the hardware and software. I hope to help beginners and give some advice. Don't talk about it much. Enable it all !~
Some resources used in this article:
1. Source Insight software
2. mini2440 schematic. Http://wenku.baidu.com/view/0521ab8da0116c175f0e48fe.html
3. S3C2440 Datasheet
4. AT24C08 Datasheet
5. bq27200 Datasheet
6. at24.c, bq27x00_battery.c and i2c-s3c2410.c in kernel 2.6.31
7. mini2440 board file mach-mini2440.c
8. References: Linux device driver development (version 2nd) by Song Baohua
Structure of this article:
Part 1: AT24C08 driver
1. electrical connection of AT24C08 in mini2440
2. Linux I2C driver framework analysis
3. I2C bus driver code analysis
4. AT24C08 driver code analysis
Part 2: bq27200 driver
1. Typical application circuit of bq27200
2. Analyze the ba27x00 code and compare it with AT24C08 for better understanding.
--------------------- I am a split line ----------------------
Part 1
1. Electrical connection and board file of AT24C08 in mini2440
For example.
The I2C interface of 24c08 is directly connected to iiccl/iicsda of 2440. An I2C controller is integrated in 2440 and can be controlled through registers. First, mix these four registers with each other and use these four registers frequently for further analysis.
In the mini2440 board file, you can find the content about AT24C08, as follows:
/* <Br/> * I2C devices <br/> */<br/> static struct at24_platform_data AT24C08 ={< br/>. byte_len = sz_8k/8, <br/>. page_size = 16, <br/> }; </P> <p> static struct i2c_board_info mini2440_i2c_devs [] _ initdata ={< br/>{< br/> i2c_board_info ("24c08", 0x50 ), <br/>. platform_data = & AT24C08, <br/>}, <br/>}; </P> <p> static void _ init mini2440_init (void) <br/> {<br/> ...... <br/> i2c_register_board_info (0, mini2440_i2c_devs, <br/> array_size (mini2440_i2c_devs); <br/> ...... <br/>}
We can see that an I2C device is registered in the init function of mini2440, which is described using the i2c_board_info structure. This struct is defined in the I2C. h file. As follows:
Struct i2c_board_info {<br/> chartype [i2c_name_size]; <br/> unsigned into flags; <br/> unsigned into ADDR; <br/> void * platform_data; <br/> struct dev_archdata * archdata; <br/> intirq; <br/> };
The platform_data point to an at24_platform_data struct.
The above is only part of AT24C08. You can also see the section about 2440 internal I2C controller in the Board file, as follows:
Static struct platform_device * mini2440_devices [] _ initdata ={< br/> ...... <br/> & initi_device_i2c0, <br/> ...... <br/>}; </P> <p> static void _ init mini2440_init (void) <br/>{< br/> ...... <br/> platform_add_devices (mini2440_devices, array_size (mini2440_devices); <br/> ...... <br/>}
Specifically, s2c_device_i2c0 is defined in arch/ARM/plat-s3c/Dev-i2c0.c (a lot of C files starting with Dev-can be seen in the same directory, which are various devices integrated within 2440 ), take a closer look at the following code and compare it with datasheet 2440. You can clearly understand it:
* The starting IP address of the controller I/O is maid = 0x54000000, the size is 4 K, and the interrupt number is 43 = irq_iic s3c2410_irq (27)
* The Controller name is "s3c2410-i2c"
Static struct resource initi_i2c_resource [] ={< br/> [0] ={< br/>. start = maid, <br/>. end = maid + sz_4k-1, <br/>. flags = ioresource_mem, <br/>}, <br/> [1] ={< br/>. start = irq_iic, <br/>. end = irq_iic, <br/>. flags = ioresource_irq, <br/>}, <br/>}; </P> <p> struct platform_device initi_device_i2c0 = {<br/>. name = "s3c2410-i2c", <br/> # ifdef config_initi_dev_i2c1 <br/>. id = 0, <br/> # else <br/>. id =-1, <br/> # endif <br/>. num_resources = array_size (cloud_i2c_resource), <br/>. resource = initi_i2c_resource, <br/>}; <br/>
2. Linux I2C driver framework analysis
This part is the key part of this article. According to the above electrical connection, we can see that we have to make two drivers to operate 24c08.
The first aspect: 2440 I2C controller driver, with this part of the driver, we can operate the Controller to generate I2C timing signals to send data and receive data.
Second, the 24c08 driver can use the Controller to operate the chip correctly to read and store data.
In Linux, the first implementation is the I2C bus driver, and the second implementation is the I2C device driver. In general, if the CPU is integrated into the I2C controller and the Linux kernel supports this CPU, you don't have to worry about the bus driver. The kernel is ready. However, if there is no I2C controller in the CPU, but an external connection, we need to implement the bus driver ourselves. For device drivers, common drivers are also included in the kernel. If we use a chip that is not in the kernel, we have to write it on our own.
Shows the I2C architecture in Linux (the picture is from the network ). The split line is divided into three layers: user space (that is, the application), kernel (that is, the driver part), and hardware (that is, the actual physical device, here is the I2C controller and AT24C08 in 2440 ). Is this clear enough? We are now looking at the middle layer.
What information can we see?
1). You can see several important components, they are: Driver, client, i2c-dev, i2c-core, algorithm, adapter. These parts have the corresponding data structure in the kernel, which is defined in the I2C. h file. Try not to paste the interrupted code to make up the number, so it will not be pasted. Briefly summarize the meaning of each struct.
Driver --> struct i2c_driver
This struct corresponds to the driving method. Important member functions include probe, remove, suspend, and resume.
It also includes an important data structure: struct i2c_device_id * id_table; if the driver can support several devices, it must contain the IDs of these devices.
Client --> struct i2c_client
The application is selectively blind. It can only see Abstract device files, and other parts are invisible. In the figure, only the client is associated with the application, so we can draw a bold conclusion: this client corresponds to a real physical device. In this article, it is AT24C08. Therefore, it is clear that the content in this struct should describe the device. Contains the chip address, device name, interrupt number used by the device, the Controller attached to the device, and the driver attached to the device.
Algorithm --> struct i2c_algorithm
Algorithm indicates an algorithm. The struct defines a set of communication methods used by the Controller. The key function is master_xfer (). In our actual work, we need to implement this function.
INT (* master_xfer) (struct i2c_adapter * ADAP, struct i2c_msg * msgs, int num );
Adapter --> struct i2c_adapter
This struct corresponds to a controller. It contains the Controller name, algorithm data, and controller devices.
2). We can see that the i2c-core plays a key role. This is actually the case. We will analyze it from here. The source code is in drivers/I2C/i2c-core.c. Several important functions can be seen in this file.
* Add/delete I2C controller functions
Int i2c_add_adapter (struct i2c_adapter * adapter) <br/> int i2c_del_adapter (struct i2c_adapter * ADAP)
* Added/deleted device-driven functions.Int i2c_register_driver (struct module * owner, struct i2c_driver * driver) <br/> void i2c_del_driver (struct i2c_driver * driver) <br/>
* Added/deleted I2C device functions
Struct i2c_client * <br/> i2c_new_device (struct i2c_adapter * ADAP, struct i2c_board_info const * info); <br/> void i2c_unregister_device (struct i2c_client * client)
Note: Before 2.6.30, i2c_attach_client () and i2c_detach_client () functions were used. Then attach is transferred to i2c_new_device by merge, while detach is directly replaced by unresister. In fact, both functions call device_register () and device_unregister () internally (). The source code is as follows:
* I2C transmission, sending, and receiving FunctionsInt i2c_transfer (struct i2c_adapter * ADAP, struct i2c_msg * msgs, int num); </P> <p> int i2c_master_send (struct i2c_client * client, const char * Buf, int count); </P> <p> int i2c_master_recv (struct i2c_client * client, char * Buf, int count );
Both send and receive call the transfer function, while transfer does not directly interact with hardware, but calls the master_xfer () function in algorithm. Therefore, we want to transmit data, you must implement this master_xfer () function by yourself, which is one of the key points of bus-driven development. The following describes the process of calling the read () system:
(To be continued)