First, explain why I wrote this article , There are many blogs on the Internet that also introduce I2C Drive in linux Implementation of porting on , But I think that quite a few of them did not distinguish the driving model when they wrote , Is based on device tree, It's still based on tradition Platform Model , Some articles just transplant the code to the platform to debug and test , There is no clear internal logic call relationship , So I think it is necessary to explain and analyze the two driving models clearly , The reader of this article must have debugged on the single chip microcomputer IIC Bus as the premise , Can analyze from chip datasheet And its working principle and the basic operation of the bus , although I2C The hardware architecture is relatively simple , however I2C Architecture in Linux The implementation in is quite complicated , As a driver engineer , Write specific I2C Driving time , The main work is as follows :

1)、 Provide I2C The hardware driver of the adapter , Probe , initialization I2C Adapter ( If you apply I2C Of I/O Address and interrupt number ), drive CPU The control of the I2C The adapter generates all kinds of signals and processes them from the hardware I2C interrupt (I2C Bus driver );

2)、 Provide I2C The control of the algorithm, With a specific adapter xxx_xfer() Function fill i2c_algorithm Of master_xfer The pointer , And put i2c_algorithm The pointer is assigned to i2c_adapter Of algo The pointer (I2C Bus driver ), Used to produce I2C Access the signal required by the slave cycle ;

3)、 Realization I2C In device driver i2c_driver Interface , Use concrete yyy Of yyy_probe(),yyy_remove(),yyy_suspend(),yyy_resume() Function pointers and i2c_device_id equipment ID Table assignment i2c_driver Of probe,remove,suspend,resume and id_table The pointer (I2C Device drivers );

4)、 Realization I2C Specific driver of the corresponding type of device ,i2c_driver It just realizes the connection between the device and the bus (I2C Device drivers ).

Step1, We have to sort out platform_device and platform_driver The match between

contrast linux2.6.29 The implementation is shown in the figure 1,linux3.14.78 The implementation of this method is shown in the figure 2, You can find , Conventional Platform The driving model is just through matching platform_device Device name and driver name , And for 3.0 Later kernels , It can be done in four ways , First, it's based on the device tree style matching ( A device tree is a data structure that describes hardware ), The second is based on ACPI Style matching , The third is matching ID surface (platform_device Whether the device name appears in platform_driver Of ID In table ), The fourth way is to use the traditional matching device and driver name to achieve , Let's start with matching platform_device Device name and driver name IIC stay 2.6.29 Graft on , And then we analyze how to realize it by means of device tree IIC stay 3.14.78 Graft on , Now let's start :

 Copy code

 1 //linux2.6.29 In the system platform The bus defines a bus_type Example platform_bus_type,
 2 struct bus_type platform_bus_type = {
 3     .name = “platform”,
 4     .dev_attrs = platform_dev_attrs,
 5     .match = platform_match,
 6     .uevent = platform_uevent,
 7     .pm = PLATFORM_PM_OPS_PTR,
 8 };
 9 EXPORT_SYMBOL_GPL(platform_bus_type);
10  
11 // Here we should focus on its match() Member functions , It is this member who shows platform_device and platform_driver How to match .
12 static int platform_match(struct device *dev, struct device_driver *drv)
13 {
14     struct platform_device *pdev;
15 
16     pdev = container_of(dev, struct platform_device, dev);
17     return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
18 }
19 // matching platform_device and platform_driver The two are mainly name Whether the fields are the same .
20 // Yes platform_device The definition of is usually in BSP In the board file , In the board file , take platform_device Reduced to an array , Finally through platform_add_devices() Function unified registration .
21 //platform_add_devices() Function to add platform devices to the system , Of this function   Archetype :
22 int platform_add_devices(struct platform_device **devs, int num);
23 // The first parameter of this function is the pointer to the platform device array , The second parameter is the number of platform devices , It calls... Internally platform_device_register() Letter   Number is used to register a single platform device .

 Copy code

 Copy code

//linux3.14.78 kernel
 1 static int platform_match(struct device *dev, struct device_driver *drv)
 2 {
 3     struct platform_device *pdev = to_platform_device(dev);
 4     struct platform_driver *pdrv = to_platform_driver(drv);
 5 
 6     /* Attempt an OF style match first */
 7     if (of_driver_match_device(dev, drv))
 8         return 1;
 9 
10     /* Then try ACPI style match */
11     if (acpi_driver_match_device(dev, drv))
12         return 1;
13 
14     /* Then try to match against the id table */
15     if (pdrv->id_table)
16         return platform_match_id(pdrv->id_table, pdev) != NULL;
17 
18     /* fall-back to driver name match */
19     return (strcmp(pdev->name, drv->name) == 0);
20 }

 Copy code

 Step2, Add device object hardware information , Corresponding i2c_client,i2c_client The information is usually in BSP Board file through i2c_board_info fill , Statically at the start of the system i2c Device registration ( Device registration is divided into dynamic discovery registration and static registration ) The following code defines a I2C The equipment ID by “24c08”, The address is 0x50 Of i2c_client, Use i2c_register_board_info Will all register i2c_board_info Object to an object named __i2c_board_list On the list of , The concrete realization is mach_s3c2440.c Call in i2c_register_board_info, See code below for details ;

 Copy code

1 static struct i2c_board_info i2c_devices[] __initdata = {
 2 {I2C_BOARD_INFO("24c08", 0x50), },
 3 };
 4 static void __init My2440_machine_init(void)
 5 {
 6     s3c24xx_fb_set_platdata(&My2440_fb_info);
 7     s3c_i2c0_set_platdata(NULL);
 8     i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
 9     
10     s3c_device_spi0.dev.platform_data= &s3c2410_spi0_platdata;  
11     spi_register_board_info(s3c2410_spi0_board, ARRAY_SIZE(s3c2410_spi0_board));  
12     s3c_device_spi1.dev.platform_data= &s3c2410_spi1_platdata;  
13     spi_register_board_info(s3c2410_spi1_board, ARRAY_SIZE(s3c2410_spi1_board));  
14     s3c_device_nand.dev.platform_data = &My2440_nand_info;
15     s3c_device_sdi.dev.platform_data = &My2440_mmc_cfg;
16 
17     platform_add_devices(My2440_devices, ARRAY_SIZE(My2440_devices));
18 }
19 
20 MACHINE_START(MY2440, "MY2440")
21     /* Maintainer: Ben Dooks <[email protected]> */
22     .phys_io    = S3C2410_PA_UART,
23     .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
24     .boot_params    = S3C2410_SDRAM_PA + 0x100,
25 
26     .init_irq    = s3c24xx_init_irq,
27     .map_io        = My2440_map_io,
28     .init_machine    = My2440_machine_init,
29     .timer        = &s3c24xx_timer,
30 MACHINE_END

 Copy code

 Step3, The concept is clear ,i2c_adapter Corresponding to a physical adapter ,i2c_client Corresponding to real physical devices , Every i2c You need one i2c_client To describe ,i2c_client Attached to the i2c_adapter, Because one adapter can connect multiple I2C equipment , So a i2c_adapter Can be multiple i2c_client Attached to ; and i2c_driver Corresponding to a set of driving methods , The relationship between their data structures is shown in the figure below . When the system starts or the module loads ,i2c Adapter device driver i2cdev_driver Added to the system , The concrete realization is drivers/i2c/i2c-dev.c in , Now analyze its implementation , stay i2c-dev.c in , Defines a name i2c_dev_init() Initialization function for , from module_init(i2c_dev_init) It can be seen that , This function is executed when the system is started or the module is loaded , Mainly complete 3 Kind of operation

first. call register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops), by I2C The registered master device number of the adapter is I2C_MAJOR(89)、 The secondary equipment number is 0~255、 The set of file operations is i2cdev_fops Character devices , That is, for each I2C The adapter generates a master device number of 89 The device file for , Realized i2c_driver Member function and file operation interface ;

second. call class_create(THIS_MODULE, "i2c-dev") The registered name is “i2c-dev” The device class of , And then registered another i2cdev_notifier;

Third. call i2c_for_each_dev(NULL, i2cdev_attach_adapter) Traverse i2c_bus_type Devices on the bus , Perform... On the device found i2cdev_attach_adapter() function , It calls first get_free_i2c_dev() Assign and initialize a struct i2c_dev structure , send i2c_dev->adap Point to the operating adapter after , The i2c_dev It's going to be inserted into the edge i2c_dev_list in , Create another device, The binding adapter And in /dev/ Create a character device node under the directory ;

 Copy code

static int __init i2c_dev_init(void)
 {
     int res;
     printk(KERN_INFO "i2c /dev entries driver\n");
    res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
    if (res)
         goto out;
     i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
     if (IS_ERR(i2c_dev_class)) {
         res = PTR_ERR(i2c_dev_class);
         goto out_unreg_chrdev;
     }
     i2c_dev_class->dev_groups = i2c_groups;
     /* Keep track of adapters which will be added or removed later */
     res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
     if (res)
         goto out_unreg_class;
     /* Bind to already existing adapters right away */
     i2c_for_each_dev(NULL, i2cdev_attach_adapter); 
     return 0;
 out_unreg_class:
     class_destroy(i2c_dev_class);
 out_unreg_chrdev:
     unregister_chrdev(I2C_MAJOR, "i2c");
 out:
     printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
     return res;
 }

 Copy code

Step4, add to i2c Bus driver (I2C Adapter driven registration ), because I2C Bus controllers are usually in memory , So it's also connected to platform On the bus , To pass the platform_driver and platform_device To perform . Even though I2C The adapter provides the bus for others , It itself is connected to platform A customer on the bus . In the file drivers/i2c/busses/i2c-s3c2410.c in ,platform_driver Register by calling the initialization function i2c_adapter_s3c_init Function to complete , And I2C The adapter corresponds to platform_driver Of probe Function mainly completes the following two tasks :

1、 initialization I2C Hardware resources used by the adapter , If you apply I/O Address 、 Interrupt number 、 Clock, etc ;2、 adopt i2c_add_numbered_adapter() add to i2c_adapter Data structure of , Of course, this i2c_adapter Members of the data structure have been initialized by the corresponding function pointer of the corresponding adapter

i2c_add_numbered_adapter(&i2c->adap)-->i2c_register_adapter(adap)-->i2c_scan_static_board_info(adap)-->list_for_each_entry(devinfo, &__i2c_board_list, list)-->i2c_new_device(adapter,&devinfo->board_info)), With adapter Structures and found devinfo In structure i2c_board_info The structure is a parameter in i2c_bus_type Add... To the bus client equipment , Add i2c_client.

 Copy code

1 static int s3c24xx_i2c_probe(struct platform_device *pdev)
  2 {
  3     struct s3c24xx_i2c *i2c;
  4     struct s3c2410_platform_i2c *pdata = NULL;
  5     struct resource *res;
  6     int ret;
  7     if (!pdev->dev.of_node) {
  8         pdata = dev_get_platdata(&pdev->dev);
  9         if (!pdata) {
 10             dev_err(&pdev->dev, "no platform data\n");
 11             return -EINVAL;
 12         }
 13     }
 14     i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
 15     if (!i2c) {
 16         dev_err(&pdev->dev, "no memory for state\n");
 17         return -ENOMEM;
 18     }
 19     i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 20     if (!i2c->pdata) {
 21         dev_err(&pdev->dev, "no memory for platform data\n");
 22         return -ENOMEM;
 23     }
 24     i2c->quirks = s3c24xx_get_device_quirks(pdev);
 25     if (pdata)
 26         memcpy(i2c->pdata, pdata, sizeof(*pdata));
 27     else
 28         s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
 29     strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
 30     i2c->adap.owner   = THIS_MODULE;
 31     i2c->adap.algo    = &s3c24xx_i2c_algorithm;   // Set the communication method of the adapter  32  
        i2c->adap.retries = 2;
 33     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 34     i2c->tx_setup     = 50;
 35     init_waitqueue_head(&i2c->wait);
 36     /* find the clock and enable it */
 37     i2c->dev = &pdev->dev;
 38     i2c->clk = devm_clk_get(&pdev->dev, "i2c");
 39     if (IS_ERR(i2c->clk)) {
 40         dev_err(&pdev->dev, "cannot get clock\n");
 41         return -ENOENT;
 42     }
 43     dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
 44     /* map the registers */
 45     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 46     i2c->regs = devm_ioremap_resource(&pdev->dev, res);
 47     if (IS_ERR(i2c->regs))
 48         return PTR_ERR(i2c->regs);
 49     dev_dbg(&pdev->dev, "registers %p (%p)\n",
 50         i2c->regs, res);
 51     /* setup info block for the i2c core , take s3c24xx_i2c Object of type I2C As a means of communication, private data is stored in algo_data in ,
such master_xfer And so on can pass through the adapter's algo_data Get this object
*/
 52     i2c->adap.algo_data = i2c;
 53     i2c->adap.dev.parent = &pdev->dev;
 54     i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
 55     /* inititalise the i2c gpio lines */
 56     if (i2c->pdata->cfg_gpio) {
 57         i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
 58     } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
 59         return -EINVAL;
 60     }
 61     /* initialise the i2c controller*/
 62     clk_prepare_enable(i2c->clk);
 63     ret = s3c24xx_i2c_init(i2c); 
 64     clk_disable(i2c->clk);
 65     if (ret != 0) {
 66         dev_err(&pdev->dev, "I2C controller init failed\n");
 67         return ret;
 68     }
 69     /* find the IRQ for this unit (note, this relies on the init call to
 70      * ensure no current IRQs pending, obtain IRQ Resource and register the interrupt ,s3c24xx_i2c_irq Is an interrupt handling function for subsequent transmission
 71      */
 72     if (!(i2c->quirks & QUIRK_POLL)) {
 73         i2c->irq = ret = platform_get_irq(pdev, 0);
 74         if (ret <= 0) {
 75             dev_err(&pdev->dev, "cannot find IRQ\n");
 76             clk_unprepare(i2c->clk);
 77             return ret;
 78         }
 79     ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
 80                 dev_name(&pdev->dev), i2c);
 81         if (ret != 0) {
 82             dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
 83             clk_unprepare(i2c->clk);
 84             return ret;
 85         }
 86     }
 87     ret = s3c24xx_i2c_register_cpufreq(i2c);
 88     if (ret < 0) {
 89         dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
 90         clk_unprepare(i2c->clk);
 91         return ret;
 92     }
 93     /* Note, previous versions of the driver used i2c_add_adapter()
 94      * to add the bus at any number. We now pass the bus number via
 95      * the platform data, so if unset it will now default to always
 96      * being bus 0.
 97      */
 98     i2c->adap.nr = i2c->pdata->bus_num;
 99     i2c->adap.dev.of_node = pdev->dev.of_node;
100     platform_set_drvdata(pdev, i2c);
101     pm_runtime_enable(&pdev->dev);
102     ret = i2c_add_numbered_adapter(&i2c->adap);   // Add adapter statically
103     if (ret < 0) {
104         dev_err(&pdev->dev, "failed to add bus to i2c core\n");
105         pm_runtime_disable(&pdev->dev);
106         s3c24xx_i2c_deregister_cpufreq(i2c);
107         clk_unprepare(i2c->clk);
108         return ret;
109     }
110     pm_runtime_enable(&i2c->adap.dev);
111     dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
112     return 0;
113 }

 Copy code

 Step5, To write i2c Device drivers , This part of the work is completely completed by the driver engineer . The work done before :I2C The adapter is driven by platform_driver And arch/arm/mach-s3c2440 Medium platform( Or nodes in the device tree ) adopt platform Bus match() Function derivation Cause s3c24xx_i2c_probe Implementation , To complete the I2C Registration of adapter controller ; And mounted on I2C The equipment above , With a gyroscope MPU6050 As object , What it depends on i2c_driver And arch/arm/mach-s3c2440 Medium i2c_board_info Pointing to the device ( Or nodes in the device tree ) adopt I2C Bus match() Function matching leads to i2c_driver.i2c_probe perform .

Device tree information

 Copy code

 1 [email protected] {
 2     #address-cells = <1>;
 3     #size-cells = <0>;
 4     samsung,i2c-sda-delay = <100>;
 5     samsung,i2c-max-bus-freq = <20000>;
 6     pinctrl-0 = <&i2c5_bus>;
 7     pinctrl-names = "default";
 8     status = "okay";
 9 
10     [email protected] {
11         compatible = "fs4412,mpu6050";
12         reg = <0x68>;
13     };
14 };

 Copy code

 Copy code

//i2c_driver.c
  1 #include <linux/kernel.h>
  2 #include <linux/module.h>
  3 #include <linux/i2c.h>
  4 #include <linux/device.h>
  5 #include <linux/cdev.h>
  6 #include <linux/fs.h>
  7 #include <linux/slab.h>
  8 #include <asm/uaccess.h>
  9 #include "mpu6050.h"
 10 
 11 
 12 #define DEVICE_MAJOR 665
 13 #define DEVICE_MINOR 0
 14 #define DEV_NUM      1
 15 #define DEVICE_NAME "mpu6050"
 16 
 17 struct mpu6050_device{
 18     struct cdev i2c_cdev;
 19     struct i2c_client *client;
 20 };
 21 
 22 struct mpu6050_device* mpu6050_device;
 23 struct class* cls;
 24 
 25 dev_t devno;
 26 int ret;
 27 
 28 MODULE_LICENSE("GPL");
 29 
 30 static const struct of_device_id i2c_dt_table[]={
 31 
 32     {
 33         .compatible="i2c,mpu6050",
 34     },
 35     {
 36     },
 37     
 38 };
 39 static const struct i2c_device_id i2c_id_table[]={
 40     {
 41         "mpu6050",0
 42     },
 43     {
 44     },
 45 
 46 };
 47 
 48 static int mpu6050_read_byte(struct i2c_client* client,char reg)
 49 {
 50 
 51     char txbuf[1]={reg};
 52     char rxbuf[1];
 53     struct i2c_msg msg[2]={
 54         {
 55             client->addr,0,1,txbuf
 56         
 57         },
 58         {
 59             client->addr,1,1,rxbuf
 60         }
 61 
 62     };
 63     ret=i2c_transfer(client->adapter,msg,ARRAY_SIZE(msg));
 64     if(ret<0)
 65     {  
 66         return -EFAULT;
 67     }
 68     return rxbuf[0];
 69 
 70 }
 71 
 72 static int mpu6050_write_byte(struct i2c_client* client,char reg,char val)
 73 {
 74 
 75     char txbuf[2]={reg,val};
 76     struct i2c_msg msg[1]={
 77         {
 78             client->addr,0,2,txbuf
 79         
 80         },
 81     };
 82     ret=i2c_transfer(client->adapter,msg,ARRAY_SIZE(msg));
 83     if(ret<0)
 84     {  
 85         printk("i2c_transfer failed!!\n");
 86         return -EFAULT;
 87     }
 88     return 0;
 89 }
 90 
 91 static int i2c_open(struct inode *inode,struct file* file)
 92 {
 93     return 0;
 94 }
 95 static int i2c_release(struct inode *inode,struct file* file)
 96 {
 97     return 0;
 98 }
 99 static long i2c_ioctl(struct file* file,unsigned int cmd,unsigned long arg)
100 {
101     union mpu6050_data data;
102     struct i2c_client *client=mpu6050_device->client;
103     switch (cmd)
104     {
105     case GET_ACCEL:
106         data.accel.x=mpu6050_read_byte(client,ACCEL_XOUT_L);
107         data.accel.x|=mpu6050_read_byte(client,ACCEL_XOUT_H)<<8;
108         data.accel.y=mpu6050_read_byte(client,ACCEL_YOUT_L);
109         data.accel.y|=mpu6050_read_byte(client,ACCEL_YOUT_H)<<8;
110         data.accel.z=mpu6050_read_byte(client,ACCEL_ZOUT_L);
111         data.accel.z|=mpu6050_read_byte(client,ACCEL_ZOUT_H)<<8;
112         break;
113     case GET_GYRO:
114         data.gyro.x=mpu6050_read_byte(client,GYRO_XOUT_L);
115         data.gyro.x|=mpu6050_read_byte(client,GYRO_XOUT_H)<<8;
116         data.gyro.y=mpu6050_read_byte(client,GYRO_YOUT_L);
117         data.gyro.y|=mpu6050_read_byte(client,GYRO_YOUT_H)<<8;
118         data.gyro.z=mpu6050_read_byte(client,GYRO_ZOUT_L);
119         data.gyro.z|=mpu6050_read_byte(client,GYRO_ZOUT_H)<<8;
120         break;
121     case GET_TEMP:
122         data.temp=mpu6050_read_byte(client,TEMP_OUT_L);
123         data.temp|=mpu6050_read_byte(client,TEMP_OUT_H)<<8;
124         break;
125     default :
126         printk("invalid argument\n");
127         return -EINVAL;
128 
129     }
130     
131     if(copy_to_user((void*)arg,&data,sizeof(data)))
132     {
133         return -EFAULT;
134     }
135     return sizeof(data);
136 }
137 
138 const struct file_operations fops={
139     .owner=THIS_MODULE,
140     .open=i2c_open,
141     .release=i2c_release,
142     .unlocked_ioctl=i2c_ioctl,
143 };
144 
145 
146 int i2c_probe(struct i2c_client* client,const struct i2c_device_id* device_id)
147 {
148     printk("i2c_mpu6050  probe!!!\n");
149     devno=MKDEV(DEVICE_MAJOR,DEVICE_MINOR);
150     mpu6050_device=kzalloc(sizeof(mpu6050_device),GFP_KERNEL);
151     if(mpu6050_device==NULL)
152     {
153         return -ENOMEM;
154     }
155     mpu6050_device->client=client;
156 
157     ret=register_chrdev_region(devno,DEV_NUM,DEVICE_NAME);
158     if(ret<0)
159     {
160         printk("register_chrdev_region failed!!!\n");
161         return -1;
162     }
163 
164     cls=class_create(THIS_MODULE,"I2C");
165     if(IS_ERR(cls))
166     {
167         printk("class:I2C create failed!!!\n");
168     }
169     printk("class:I2C create succeed!!!\n");
170     device_create(cls,NULL,devno,NULL,"MPU6050");
171     cdev_init(&mpu6050_device->i2c_cdev,&fops);
172     mpu6050_device->i2c_cdev.owner=THIS_MODULE;
173     printk("i2c_cdev init succeed!!!\n");
174     cdev_add(&mpu6050_device->i2c_cdev,devno,DEV_NUM);
175     printk("i2c_cdev add succeed!!!\n");
176 
177     mpu6050_write_byte(client,SMPLRT_DIV,0X07);
178     mpu6050_write_byte(client,CONFIG,0X06);
179     mpu6050_write_byte(client,GYRO_CONFIG,0XF8);
180     mpu6050_write_byte(client,ACCEL_CONFIG,0X19);
181     mpu6050_write_byte(client,PWR_MGMT_1,0X00);
182     mpu6050_write_byte(client,WHO_AM_I,0x68);
183 
184 
185     return 0;
186 }
187 int i2c_remove(struct i2c_client*client)
188 {
189 
190     device_destroy(cls,devno);
191     class_destroy(cls);
192     printk("class_destroy succeed!!!\n");
193     cdev_del(&mpu6050_device->i2c_cdev);
194     unregister_chrdev_region(devno,DEV_NUM);
195     
196     kfree(mpu6050_device);
197     return 0;
198 }
199 static struct i2c_driver i2c_dr ={
200 
201     .driver={
202             .name="mpu6050",
203             .of_match_table=i2c_dt_table,
204     },
205     .id_table=i2c_id_table,
206     .probe=i2c_probe,
207     .remove=i2c_remove,
208 };
209 
210 module_i2c_driver(i2c_dr);

 Copy code

  test.c

 Copy code

 1 #include <stdio.h>
 2 #include <sys/ioctl.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6 #include <unistd.h>
 7 
 8 #include "mpu6050.h"
 9 int main(int argc, const char *argv[])
10 {
11     int fd;
12     float temperature;
13 //    unsigned long data;
14     union mpu6050_data data;
15     int ret;
16     fd=open("/dev/MPU6050",O_RDWR);
17     if(fd<0)
18     {
19         perror("fail to open MPU6050");
20         return -1;
21     }
22     printf("open /dev/MPU6050 succeed!\n");
23     while(1)
24     {
25 
26         printf("****************data from mpu6050*************************\n");
27         printf("\n");
28 
29         ioctl(fd,GET_ACCEL,&data);    
30         printf("accel:x=%-5d,y=%-5d,z=%-5d\n",data.accel.x,data.accel.y,data.accel.z);
31         printf("\n");
32 
33         ioctl(fd,GET_GYRO,&data);    
34         printf("gyro :x=%-5d,y=%-5d,z=%-5d\n",data.gyro.x,data.gyro.y,data.gyro.z);
35         printf("\n");
36 
37         ioctl(fd,GET_TEMP,&data);
38         temperature=((float)data.temp)/340+36.53;
39         printf("temperature=%f\n",temperature);
40         printf("\n");
41         
42         sleep(1);
43 
44     }

 Copy code

The data actually collected :

 

 

reference :1.《 thorough Linux Kernel architecture 》 2.《Linux Detailed description of device driven development 》