Linux Kernel I2C subsystem Learning (1)

Source: Internet
Author: User

This part is prepared for analysis and summarization in several parts

Because I2C communication must have at least two chips, the driver consists of two parts:
  1. I2C driver of the main chip
  2. I2C driver from the chip
Note: What if none of the options are supported ??? (Unfortunately, only two chips can be driven, but the process is similar)   (1). I2C driver of the main chip: (how to implement it is explained in detail later)First, check whether the Linux kernel supports the I2C driver in the master chip. If yes, configure it. Otherwise, write the I2C driver of the master chip.

Writing Method:

First. there must be an I2C bus driver (First, check whether the kernel I2C file supports this bus driver. Generally, there is support. If you don't have to write it yourself). Second. the I2C Device Driver (the address of the master chip, and so on) process is similar and will be analyzed later. Generally, the I2C controller Linux kernel of the master chip supports very well, such as 2410 I2C driver. (2). I2C driver for slave chip: The following mainly analyzes the I2C driver from the chip (there are also two ways, the first is to use the i2c-dev.c provided by the kernel to build, the other is to write) The first method is as follows:Use the i2c-dev.c provided by the system to implement a device file for an I2C adapter. Then, the I2C device is controlled by operating the I2C adapter at the application layer. I2c-dev.c is not designed for specific devices, but provides general interfaces such as read (), write () and IOCTL, the application layer can use these interfaces to access the storage space or registers of I2C devices attached to the adapter and control how the I2C devices work. However, the Read and Write methods have limited applicability. Therefore, the ioctl method is used to perform the following operations:

Generally, the read (), write () Methods of the i2c-dev.c are not used. The most common method is IOCTL. The IOCTL () method can implement all the above situations (two data formats, I2C algorithm and SMBus algorithm ).

Familiar with I2C AlgorithmsStruct i2c_rdwr_ioctl_data, struct i2c_msg. The command used is i2c_rdwr.

Struct i2c_rdwr_ioctl_data

{

Struct i2c_msg _ User * msgs;/* pointers to i2c_msgs */

_ U32 nmsgs;/* Number of i2c_msgs */
};
Struct i2c_msg {
_ 2010addr;/* slave address */
_ Flags;/* flag (read and write )*/
_ 2010len;/* Msg Length */
_ U8 * Buf;/* pointer to MSG data */
};

For SMBus algorithms, you need to be familiar with struct i2c_smbus_ioctl_data. The command used is i2c_smbus. The "Multi-start signal timing" issue does not need to be considered for SMBus algorithms.
Struct i2c_smbus_ioctl_data {
_ U8 read_write; // read and write
_ U8 command; // command
_ U32 size; // Data Length identifier
Union i2c_smbus_data _ User * data; // data
};

First, the kernel contains the support for the I2C controller (bus driver) driver in S3C2410. Provides the I2C algorithm (non-SMBus type, so the subsequent IOCTL command is i2c_rdwr)
Static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
. Master_xfer = s3c24xx_i2c_xfer,
. Functionality = s3c24xx_i2c_func,
};

 

On the other hand, it is necessary to determine the address of the slave chip and the read/write access time sequence for the at24c02 E2PROM operation.

I found an example on the Internet:

The specific analysis is as follows:

# Include <stdio. h> # include <Linux/types. h> # include <stdlib. h> # include <fcntl. h> # include <unistd. h> # include <sys/types. h> # include <sys/IOCTL. h> # include <errno. h> # define i2c_retries 0x0701 # define i2c_timeout 0x0702 # define i2c_rdwr 0x0707/******** define struct i2c_rdwr_ioctl_data and struct i2c_msg, it must be consistent with the kernel. Two important struct ******/struct i2c_msg {unsigned short ADDR; unsigned short flags; unsigned short Len; unsigned char * Buf ;}; struct i2c_rdwr_ioctl_data {struct i2c_msg * msgs; int nmsgs;/* The number of nmsgs determines the number of start signals. For "Single Start sequence", 1 */}; int main () {int FD, RET; struct i2c_rdwr_ioctl_data e2prom_data; FD = open ("/dev/i2c-0", o_rdwr );
/*

Why is it i2c-0 ??? It should be viewed in the kernel. Later, the i2c_get_adapter (int id) function is called at the underlying level of open. This function is very important, he can identify which I2C bus is occupied using 0 I2C controllers/dev/i2c-0 is generated after the i2c-dev.c is registered, representing an operational adapter. If you do not use the i2c-dev.c (here said the above why) method, there is no, do not need this section, i2c_driver struct has attach_adapter method: Inside the device_create (i2c_dev_class, & amp; ADAP-> Dev, mkdev (i2c_major, ADAP-> nr), null, "I2C-% d", ADAP-> nr); i2c_major = 89, that is, the i2c-dev.c generates a device file with the master device number 89 for each I2C adapter, the secondary device needs to define its own */If (FD <0) {perror ("Open error ");} e2prom_data.nmsgs = 2;/** in the operation sequence, a maximum of two start signals (in byte read operations) are used ), therefore, configure * e2prom_data.nmsgs to 2 */e2prom_data.msgs = (struct i2c_msg *) malloc (e2prom_da Ta. nmsgs * sizeof (struct i2c_msg); If (! E2prom_data.msgs) {perror ("malloc error"); exit (1);} IOCTL (FD, i2c_timeout, 1);/* timeout */IOCTL (FD, i2c_retries, 2);/* repeat times * // *** write data to E2PROM ** // **/e2prom_data.nmsgs = 1; (e2prom_data.msgs [0]). len = 2; // 1 E2PROM write Destination Address and 1 data (e2prom_data.msgs [0]). ADDR = 0x50; // E2PROM device address (e2prom_data.msgs [0]). flags = 0; // write (e2prom_data.msgs [0]). buf = (unsigned char *) malloc (2); (e2prom_data.msgs [0]). buf [0] = 0x10 ;/ /E2PROM write Destination Address (e2prom_data.msgs [0]). buf [1] = 0x58; // the data to write ret = IOCTL (FD, i2c_rdwr, (unsigned long) & e2prom_data); If (Ret <0) {perror ("IOCTL error1");} Sleep (1);/******* read data from E2PROM *******/e2prom_data.nmsgs = 2; (e2prom_data.msgs [0]). len = 1; // E2PROM target data address (e2prom_data.msgs [0]). ADDR = 0x50; // E2PROM device address (e2prom_data.msgs [0]). flags = 0; // write (e2prom_data.msgs [0]). buf [0] = 0x10; // e2p Rom data address (e2prom_data.msgs [1]). len = 1; // read data (e2prom_data.msgs [1]). ADDR = 0x50; // E2PROM device address (e2prom_data.msgs [1]). flags = i2c_m_rd; // read (e2prom_data.msgs [1]). buf = (unsigned char *) malloc (1); // address for storing the returned value. (E2prom_data.msgs [1]). buf [0] = 0; // initialize read buffer ret = IOCTL (FD, i2c_rdwr, (unsigned long) & e2prom_data); If (Ret <0) {perror ("IOCTL error2");} printf ("Buff [0] = % x/N", (e2prom_data.msgs [1]). buf [0]); close (FD); i2c_put_adapter (client-> adapter); release I2C bus return 0 ;}

The above describes a more common method of using i2c-dev.c to operate I2C equipment, this method can be said to be completed at the application layer of the specific I2C device driver work.

Next, we will prepare a detailed analysis on how to write the first part!

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.