Linux Kernel I2C subsystem Learning (III)

Source: Internet
Author: User
Write Device Driver: Quartet:
  1. Build i2c_driver
  2. Register i2c_driver
  3. Build i2c_client (first method: register the character device driver, second method: Fill in with the i2c_board_info of the board file, and then register)
  4. Cancel i2c_driver

The details are as follows:

● 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 encode (void) {return i2c_add_driver (& pca953x_driver);} module_init (pca953x_init); after i2c_add_driver (& pca953x_driver) is executed, these adapters are called sequentially to connect to our I2C devices. This process is completed by calling the attach_adapter method in i2c_driver. The specific implementation form is as follows: static int encode (struct i2c_adapter * adapter) {return i2c_probe (adapter, & addr_data, pca953x_detect);/* adapter: adapter addr_data: address information pca953x_detect: the addr_data address of the function */} called after the device is detected is specified by the following code. /* Addresses to scan */static unsigned short normal_i2c [] = {0x20, 0x24, 0x25, 0x26, 0x27, i2c_client_end}; 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 struct 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. Primary and secondary device number source 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 (response) {result = sums (pca953x_dev, 1, "pca953x");} else {result = alloc_chrdev_region (& pca953x_dev, "pca953x"); sums = 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 the 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, u16 value)        {                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.

Note: i2c_client information is usually filled with i2c_board_info In the BSP board file, for example: Define an i2c_client with the I2C device ID "ad7142_joystick", IP address 0x2c, and interrupt number irq_pf5   Static struct i2c_board_info _ initdata xxx_i2c_board_info [] = { { I2c_board_info ("ad7142_joystick", 0x2c ), . IRQ = irq_pf5,
},
......... }; Then register I2c_register_board_info (1, i2c_devs1, array_size (i2c_devs1 )); This completes i2c_client registration. 

● Cancel i2c_driver

static void __exit pca953x_exit(void)        {                i2c_del_driver(&pca953x_driver);        }        module_exit(pca953x_exit);

  

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 ;}

  

In fact, the I2C driver of the main chip is basically supported, haha, so the remaining workload is not very large, just complete the I2C driver operation from the chip OK, that is just to analyze how to write it for deep understanding.

In addition:

 

Several important structures: i2c_msg (set the device address), i2c_client (the address of the slave device, which is usually in the form of a platform device and tested using the probe function), and i2c_driver.

 

Several important methods: The i2c_add_driver device and the i2c_transfer device are used to interact with a group of messages between the I2C adapter and I2C device. The I2C Protocol differs from the sccb Protocol: slave address because I2C is a 7-bit address, the last bit is the read/write bit, while sccb is the eight-bit address. For example, ov9650 is the sccb protocol and its address is 0x60. If it is attached to the I2C bus, the address is 0x30. In this case, the sccb address is: 0x60: 0 1 1 0_0 0 0 0. 0: whether the value is 0 or the address bitI2C address: 0 1 1 0_0 0 0 0The last 0 in red is the read/write bit, so the address is changed to 7 digits + the read/write bit is 0 1 _ 0 0 0 + 0(Read/write bit) So the slave address is changed to 0x30 Linux kernel I2C driver. That's all!

 

 

 

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.