Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发

前面在Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构,下面进入我们的驱动开发过程

         首先看一张代码层次图,有助于我们的理解




       上面这些代码的展示是告诉我们:linux内核和芯片提供商为我们的的驱动程序提供了 i2c驱动的框架,以及框架底层与硬件相关的代码的实现

   剩下的就是针对挂载在i2c两线上的i2c设备了device,而编写的即具体设备驱动了,这里的设备就是硬件接口外挂载的设备,而非硬件接口本身(soc硬件接口本身的驱动可以理解为总线驱动)


一、编写驱动需要完成的工作

       编写具体的I2C驱动时,工程师需要处理的主要工作如下:

1)、提供I2C适配器的硬件驱动,探测,初始化I2C适配器(如申请I2C的I/O地址和中断号),驱动CPU控制的I2C适配器从硬件上产生。

2)、提供I2C控制的algorithm, 用具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋给i2c_adapter的algo指针。

3)、实现I2C设备驱动中的i2c_driver接口,用具体yyy的yyy_probe(),yyy_remove(),yyy_suspend(),yyy_resume()函数指针和i2c_device_id设备ID表赋给i2c_driver的probe,remove,suspend,resume和id_table指针。

4)、实现I2C设备所对应类型的具体驱动,i2c_driver只是实现设备与总线的挂接。

  上面的工作中前两个属于I2C总线驱动,后面两个属于I2C设备驱动。


二、开发实例

-------------------------------------------------------------------

开发板:Exynos4412-fs4412

Linux 内核版本:Linux 3.14

IIC 从机对象:陀螺仪MPU6050

--------------------------------------------------------------------

1、查看原理图

对应核心板pin


从机地址



可以获取的信息:

1、MPU6050 对应 IIC 通道5;

2、对应中断 EINT27  父节点 GPX3  3

3、因为ad0接地,所以从设备地址0x68

      base address 0x138B0000


2、创建设备树节点

      通过上面获取的信息,可以写出

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. i2c@138b0000 {  
  2.         #address-cells = <1>;  
  3.         #size-cells = <0>;  
  4.   
  5.         samsung,i2c-sda-delay = <100>;  
  6.         samsung,i2c-max-bus-freq = <20000>;  
  7.         pinctrl-0 = <&i2c5_bus>;  
  8.         pinctrl-names = "default";  
  9.         status = "okay";  
  10.      
  11.         pmu6050-3-asix@68 {  
  12.                compatible = "invense,mpu6050";  
  13.                reg = <0x68>;  
  14.               interrupt-parent = <&gpx3>;  
  15.               interrupts = <3 2>;  
  16.         };  
  17. };  

3、MPU6050相应寄存器

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #define SMPLRT_DIV 0x19 //采样率分频,典型值: 0x07(125Hz) */  
  2. #define CONFIG 0x1A // 低通滤波频率,典型值: 0x06(5Hz) */  
  3. #define GYRO_CONFIG 0x1B // 陀螺仪自检及测量范围,典型值: 0x18(不自检,2000deg/s) */  
  4. #define ACCEL_CONFIG 0x1C // 加速计自检、测量范围及高通滤波频率,典型值: 0x01(不自检, 2G, 5Hz) */  
  5. #define ACCEL_XOUT_H 0x3B // 存储最近的 X 轴、 Y 轴、 Z 轴加速度感应器的测量值 */  
  6. #define ACCEL_XOUT_L 0x3C  
  7. #define ACCEL_YOUT_H 0x3D  
  8. #define ACCEL_YOUT_L 0x3E  
  9. #define ACCEL_ZOUT_H 0x3F  
  10. #define ACCEL_ZOUT_L 0x40  
  11. #define TEMP_OUT_H 0x41 // 存储的最近温度传感器的测量值 */  
  12. #define TEMP_OUT_L 0x42  
  13. #define GYRO_XOUT_H 0x43 // 存储最近的 X 轴、 Y 轴、 Z 轴陀螺仪感应器的测量值 */  
  14. #define GYRO_XOUT_L 0x44  
  15. #define GYRO_YOUT_H 0x45  
  16. #define GYRO_YOUT_L 0x46  
  17. #define GYRO_ZOUT_H 0x47  
  18. #define GYRO_ZOUT_L 0x48  
  19. #define PWR_MGMT_1 0x6B // 电源管理,典型值: 0x00(正常启用) */  
  20. #define WHO_AM_I 0x75 //IIC 地址寄存器(默认数值 0x68,只读) */  

4、具体程序

mpu6050.h

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #ifndef MPU6050_HHHH  
  2. #define MPU6050_HHHH  
  3.   
  4. #define MPU6050_MAGIC 'K'  
  5.   
  6. union mpu6050_data  
  7. {  
  8.     struct {  
  9.         unsigned short x;  
  10.         unsigned short y;  
  11.         unsigned short z;  
  12.     }accel;  
  13.     struct {  
  14.         unsigned short x;  
  15.         unsigned short y;  
  16.         unsigned short z;  
  17.     }gyro;  
  18.     unsigned short temp;  
  19. };  
  20.   
  21. #define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)  
  22. #define GET_GYRO  _IOR(MPU6050_MAGIC, 1, union mpu6050_data)   
  23. #define GET_TEMP  _IOR(MPU6050_MAGIC, 2, union mpu6050_data)  
  24.   
  25. #endif  

i2c_driver

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/i2c.h>  
  4. #include <linux/cdev.h>  
  5. #include <linux/slab.h>  
  6. #include <linux/fs.h>  
  7. #include <linux/delay.h>  
  8.   
  9. #include <asm/uaccess.h>  
  10.   
  11. #include "mpu6050.h"  
  12.   
  13. MODULE_LICENSE("GPL");  
  14.   
  15. #define SMPLRT_DIV      0x19  
  16. #define CONFIG          0x1A  
  17. #define GYRO_CONFIG     0x1B  
  18. #define ACCEL_CONFIG    0x1C  
  19. #define ACCEL_XOUT_H    0x3B  
  20. #define ACCEL_XOUT_L    0x3C  
  21. #define ACCEL_YOUT_H    0x3D  
  22. #define ACCEL_YOUT_L    0x3E  
  23. #define ACCEL_ZOUT_H    0x3F  
  24. #define ACCEL_ZOUT_L    0x40  
  25. #define TEMP_OUT_H      0x41  
  26. #define TEMP_OUT_L      0x42  
  27. #define GYRO_XOUT_H     0x43  
  28. #define GYRO_XOUT_L     0x44  
  29. #define GYRO_YOUT_H     0x45  
  30. #define GYRO_YOUT_L     0x46  
  31. #define GYRO_ZOUT_H     0x47  
  32. #define GYRO_ZOUT_L     0x48  
  33. #define PWR_MGMT_1      0x6B  
  34.   
  35. #define MPU6050_MAJOR 500  
  36. #define MPU6050_MINOR 0  
  37.   
  38. struct mpu6050_device {  
  39.     struct cdev cdev;  
  40.     struct i2c_client *client;  
  41. };  
  42. struct mpu6050_device *mpu6050;   
  43.   
  44. static int mpu6050_read_byte(struct i2c_client *client, unsigned char reg)  
  45. {  
  46.     int ret;  
  47.   
  48.     char txbuf[1] = { reg };  
  49.     char rxbuf[1];  
  50.   
  51.     struct i2c_msg msg[2] = {  
  52.         {client->addr, 0, 1, txbuf},  
  53.         {client->addr, I2C_M_RD, 1, rxbuf}  
  54.     };  
  55.   
  56.     ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
  57.     if (ret < 0) {  
  58.         printk("ret = %d\n", ret);  
  59.         return ret;  
  60.     }  
  61.   
  62.     return rxbuf[0];  
  63. }  
  64.   
  65. static int mpu6050_write_byte(struct i2c_client *client, unsigned char reg, unsigned char val)  
  66. {  
  67.     char txbuf[2] = {reg, val};  
  68.   
  69.     struct i2c_msg msg[2] = {  
  70.         {client->addr, 0, 2, txbuf},  
  71.     };  
  72.   
  73.     i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
  74.   
  75.     return 0;  
  76. }  
  77.   
  78.   
  79. static int mpu6050_open(struct inode *inode, struct file *file)   
  80. {  
  81.     return 0;  
  82. }  
  83.   
  84. static int mpu6050_release(struct inode *inode, struct file *file)   
  85. {  
  86.     return 0;  
  87. }  
  88.   
  89. static long mpu6050_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  90. {  
  91.     union mpu6050_data data;  
  92.     struct i2c_client *client = mpu6050->client;  
  93.   
  94.     switch(cmd) {  
  95.     case GET_ACCEL:  
  96.         data.accel.x = mpu6050_read_byte(client, ACCEL_XOUT_L);  
  97.         data.accel.x |= mpu6050_read_byte(client, ACCEL_XOUT_H) << 8;  
  98.   
  99.         data.accel.y = mpu6050_read_byte(client, ACCEL_YOUT_L);  
  100.         data.accel.y |= mpu6050_read_byte(client, ACCEL_YOUT_H) << 8;  
  101.   
  102.         data.accel.z = mpu6050_read_byte(client, ACCEL_ZOUT_L);  
  103.         data.accel.z |= mpu6050_read_byte(client, ACCEL_ZOUT_H) << 8;  
  104.         break;  
  105.   
  106.     case GET_GYRO:  
  107.   
  108.         data.gyro.x = mpu6050_read_byte(client, GYRO_XOUT_L);  
  109.         data.gyro.x |= mpu6050_read_byte(client, GYRO_XOUT_H) << 8;  
  110.   
  111.         data.gyro.y = mpu6050_read_byte(client, GYRO_YOUT_L);  
  112.         data.gyro.y |= mpu6050_read_byte(client, GYRO_YOUT_H) << 8;  
  113.   
  114.         data.gyro.z = mpu6050_read_byte(client, GYRO_ZOUT_L);  
  115.         data.gyro.z |= mpu6050_read_byte(client, GYRO_ZOUT_H) << 8;  
  116.         break;  
  117.   
  118.     case GET_TEMP:    
  119.         data.temp = mpu6050_read_byte(client, TEMP_OUT_L);  
  120.         data.temp |= mpu6050_read_byte(client, TEMP_OUT_H) << 8;  
  121.         break;  
  122.   
  123.     default:  
  124.         printk("invalid argument\n");  
  125.         return -EINVAL;  
  126.     }  
  127.   
  128.     if (copy_to_user((void *)arg, &data, sizeof(data)))  
  129.         return -EFAULT;  
  130.   
  131.     return sizeof(data);  
  132. }  
  133.   
  134. struct file_operations mpu6050_fops = {  
  135.     .owner      = THIS_MODULE,  
  136.     .open       = mpu6050_open,  
  137.     .release    = mpu6050_release,  
  138.     .unlocked_ioctl = mpu6050_ioctl,  
  139. };  
  140.   
  141. static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  142. {  
  143.     int ret;  
  144.     dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
  145.     printk("match OK!\n");  
  146.   
  147.     mpu6050 = kzalloc(sizeof(*mpu6050), GFP_KERNEL);  
  148.     if (mpu6050 == NULL) {  
  149.         return -ENOMEM;  
  150.     }  
  151.   
  152.     mpu6050->client = client;  
  153.   
  154.     ret = register_chrdev_region(devno, 1, "mpu6050");  
  155.     if (ret < 0) {  
  156.         printk("failed to register char device region!\n");  
  157.         goto err1;  
  158.     }  
  159.   
  160.     cdev_init(&mpu6050->cdev, &mpu6050_fops);  
  161.     mpu6050->cdev.owner = THIS_MODULE;  
  162.     ret = cdev_add(&mpu6050->cdev, devno, 1);  
  163.     if (ret < 0) {  
  164.         printk("failed to add device\n");  
  165.         goto err2;  
  166.     }  
  167.       
  168.     mpu6050_write_byte(client, PWR_MGMT_1, 0x00);  
  169.     mpu6050_write_byte(client, SMPLRT_DIV, 0x07);  
  170.     mpu6050_write_byte(client, CONFIG, 0x06);  
  171.     mpu6050_write_byte(client, GYRO_CONFIG, 0xF8);  
  172.     mpu6050_write_byte(client, ACCEL_CONFIG, 0x19);  
  173.   
  174.     return 0;  
  175. err2:  
  176.     unregister_chrdev_region(devno, 1);  
  177. err1:  
  178.     kfree(mpu6050);  
  179.     return ret;  
  180. }  
  181.   
  182. static int mpu6050_remove(struct i2c_client *client)  
  183. {  
  184.     dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
  185.     cdev_del(&mpu6050->cdev);  
  186.     unregister_chrdev_region(devno, 1);  
  187.     kfree(mpu6050);  
  188.   
  189.     return 0;  
  190. }  
  191.   
  192. static const struct i2c_device_id mpu6050_id[] = {  
  193.     { "mpu6050", 0},  
  194.     {}  
  195. };   
  196.   
  197. static struct of_device_id mpu6050_dt_match[] = {  
  198.     {.compatible = "invense,mpu6050" },  
  199.     {/*northing to be done*/},  
  200. };  
  201.   
  202. struct i2c_driver mpu6050_driver = {  
  203.     .driver = {  
  204.         .name           = "mpu6050",  
  205.         .owner          = THIS_MODULE,  
  206.         .of_match_table = of_match_ptr(mpu6050_dt_match),  
  207.     },  
  208.     .probe      = mpu6050_probe,  
  209.     .remove     = mpu6050_remove,  
  210.     .id_table   = mpu6050_id,  
  211. };  
  212.   
  213. static init _init mpu6050_init(void)  
  214. {  
  215.     return i2c_add_driver(&mpu6050_driver);  
  216. }  
  217.   
  218. static void _exit mpu6050_exit(void)  
  219. {  
  220.     return i2c_del_driver(&mpu6050_driver);  
  221. }  
  222.   
  223. module_init(&mpu6050_init);  
  224. module_exit(&mpu6050_exit);  


test.c
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <fcntl.h>  
  5. #include <sys/ioctl.h>  
  6.   
  7. #include "mpu6050.h"  
  8.   
  9. int main(int argc, const char *argv[])  
  10. {  
  11.     int fd;  
  12.     union mpu6050_data data;   
  13.       
  14.     fd = open("/dev/mpu6050", O_RDWR);  
  15.     if (fd < 0) {  
  16.         perror("open");  
  17.         exit(1);  
  18.     }  
  19.   
  20.     while(1) {  
  21.         ioctl(fd, GET_ACCEL, &data);  
  22.         printf("acceleration data: x = %04x, y = %04x, z = %04x\n",   
  23.                 data.accel.x, data.accel.y, data.accel.z);  
  24.   
  25.         ioctl(fd, GET_GYRO, &data);  
  26.         printf("gyroscope data: x = %04x, y = %04x, z = %04x\n",   
  27.                 data.accel.x, data.accel.y, data.accel.z);  
  28.   
  29.         sleep(1);  
  30.     }  
  31.   
  32.     close(fd);  
  33.   
  34.     return 0;  
  35. }  

前面在Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构,下面进入我们的驱动开发过程

         首先看一张代码层次图,有助于我们的理解




       上面这些代码的展示是告诉我们:linux内核和芯片提供商为我们的的驱动程序提供了 i2c驱动的框架,以及框架底层与硬件相关的代码的实现

   剩下的就是针对挂载在i2c两线上的i2c设备了device,而编写的即具体设备驱动了,这里的设备就是硬件接口外挂载的设备,而非硬件接口本身(soc硬件接口本身的驱动可以理解为总线驱动)


一、编写驱动需要完成的工作

       编写具体的I2C驱动时,工程师需要处理的主要工作如下:

1)、提供I2C适配器的硬件驱动,探测,初始化I2C适配器(如申请I2C的I/O地址和中断号),驱动CPU控制的I2C适配器从硬件上产生。

2)、提供I2C控制的algorithm, 用具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋给i2c_adapter的algo指针。

3)、实现I2C设备驱动中的i2c_driver接口,用具体yyy的yyy_probe(),yyy_remove(),yyy_suspend(),yyy_resume()函数指针和i2c_device_id设备ID表赋给i2c_driver的probe,remove,suspend,resume和id_table指针。

4)、实现I2C设备所对应类型的具体驱动,i2c_driver只是实现设备与总线的挂接。

  上面的工作中前两个属于I2C总线驱动,后面两个属于I2C设备驱动。


二、开发实例

-------------------------------------------------------------------

开发板:Exynos4412-fs4412

Linux 内核版本:Linux 3.14

IIC 从机对象:陀螺仪MPU6050

--------------------------------------------------------------------

1、查看原理图

对应核心板pin


从机地址



可以获取的信息:

1、MPU6050 对应 IIC 通道5;

2、对应中断 EINT27  父节点 GPX3  3

3、因为ad0接地,所以从设备地址0x68

      base address 0x138B0000


2、创建设备树节点

      通过上面获取的信息,可以写出

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. i2c@138b0000 {  
  2.         #address-cells = <1>;  
  3.         #size-cells = <0>;  
  4.   
  5.         samsung,i2c-sda-delay = <100>;  
  6.         samsung,i2c-max-bus-freq = <20000>;  
  7.         pinctrl-0 = <&i2c5_bus>;  
  8.         pinctrl-names = "default";  
  9.         status = "okay";  
  10.      
  11.         pmu6050-3-asix@68 {  
  12.                compatible = "invense,mpu6050";  
  13.                reg = <0x68>;  
  14.               interrupt-parent = <&gpx3>;  
  15.               interrupts = <3 2>;  
  16.         };  
  17. };  

3、MPU6050相应寄存器

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #define SMPLRT_DIV 0x19 //采样率分频,典型值: 0x07(125Hz) */  
  2. #define CONFIG 0x1A // 低通滤波频率,典型值: 0x06(5Hz) */  
  3. #define GYRO_CONFIG 0x1B // 陀螺仪自检及测量范围,典型值: 0x18(不自检,2000deg/s) */  
  4. #define ACCEL_CONFIG 0x1C // 加速计自检、测量范围及高通滤波频率,典型值: 0x01(不自检, 2G, 5Hz) */  
  5. #define ACCEL_XOUT_H 0x3B // 存储最近的 X 轴、 Y 轴、 Z 轴加速度感应器的测量值 */  
  6. #define ACCEL_XOUT_L 0x3C  
  7. #define ACCEL_YOUT_H 0x3D  
  8. #define ACCEL_YOUT_L 0x3E  
  9. #define ACCEL_ZOUT_H 0x3F  
  10. #define ACCEL_ZOUT_L 0x40  
  11. #define TEMP_OUT_H 0x41 // 存储的最近温度传感器的测量值 */  
  12. #define TEMP_OUT_L 0x42  
  13. #define GYRO_XOUT_H 0x43 // 存储最近的 X 轴、 Y 轴、 Z 轴陀螺仪感应器的测量值 */  
  14. #define GYRO_XOUT_L 0x44  
  15. #define GYRO_YOUT_H 0x45  
  16. #define GYRO_YOUT_L 0x46  
  17. #define GYRO_ZOUT_H 0x47  
  18. #define GYRO_ZOUT_L 0x48  
  19. #define PWR_MGMT_1 0x6B // 电源管理,典型值: 0x00(正常启用) */  
  20. #define WHO_AM_I 0x75 //IIC 地址寄存器(默认数值 0x68,只读) */  

4、具体程序

mpu6050.h

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #ifndef MPU6050_HHHH  
  2. #define MPU6050_HHHH  
  3.   
  4. #define MPU6050_MAGIC 'K'  
  5.   
  6. union mpu6050_data  
  7. {  
  8.     struct {  
  9.         unsigned short x;  
  10.         unsigned short y;  
  11.         unsigned short z;  
  12.     }accel;  
  13.     struct {  
  14.         unsigned short x;  
  15.         unsigned short y;  
  16.         unsigned short z;  
  17.     }gyro;  
  18.     unsigned short temp;  
  19. };  
  20.   
  21. #define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)  
  22. #define GET_GYRO  _IOR(MPU6050_MAGIC, 1, union mpu6050_data)   
  23. #define GET_TEMP  _IOR(MPU6050_MAGIC, 2, union mpu6050_data)  
  24.   
  25. #endif  

i2c_driver

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/i2c.h>  
  4. #include <linux/cdev.h>  
  5. #include <linux/slab.h>  
  6. #include <linux/fs.h>  
  7. #include <linux/delay.h>  
  8.   
  9. #include <asm/uaccess.h>  
  10.   
  11. #include "mpu6050.h"  
  12.   
  13. MODULE_LICENSE("GPL");  
  14.   
  15. #define SMPLRT_DIV      0x19  
  16. #define CONFIG          0x1A  
  17. #define GYRO_CONFIG     0x1B  
  18. #define ACCEL_CONFIG    0x1C  
  19. #define ACCEL_XOUT_H    0x3B  
  20. #define ACCEL_XOUT_L    0x3C  
  21. #define ACCEL_YOUT_H    0x3D  
  22. #define ACCEL_YOUT_L    0x3E  
  23. #define ACCEL_ZOUT_H    0x3F  
  24. #define ACCEL_ZOUT_L    0x40  
  25. #define TEMP_OUT_H      0x41  
  26. #define TEMP_OUT_L      0x42  
  27. #define GYRO_XOUT_H     0x43  
  28. #define GYRO_XOUT_L     0x44  
  29. #define GYRO_YOUT_H     0x45  
  30. #define GYRO_YOUT_L     0x46  
  31. #define GYRO_ZOUT_H     0x47  
  32. #define GYRO_ZOUT_L     0x48  
  33. #define PWR_MGMT_1      0x6B  
  34.   
  35. #define MPU6050_MAJOR 500  
  36. #define MPU6050_MINOR 0  
  37.   
  38. struct mpu6050_device {  
  39.     struct cdev cdev;  
  40.     struct i2c_client *client;  
  41. };  
  42. struct mpu6050_device *mpu6050;   
  43.   
  44. static int mpu6050_read_byte(struct i2c_client *client, unsigned char reg)  
  45. {  
  46.     int ret;  
  47.   
  48.     char txbuf[1] = { reg };  
  49.     char rxbuf[1];  
  50.   
  51.     struct i2c_msg msg[2] = {  
  52.         {client->addr, 0, 1, txbuf},  
  53.         {client->addr, I2C_M_RD, 1, rxbuf}  
  54.     };  
  55.   
  56.     ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
  57.     if (ret < 0) {  
  58.         printk("ret = %d\n", ret);  
  59.         return ret;  
  60.     }  
  61.   
  62.     return rxbuf[0];  
  63. }  
  64.   
  65. static int mpu6050_write_byte(struct i2c_client *client, unsigned char reg, unsigned char val)  
  66. {  
  67.     char txbuf[2] = {reg, val};  
  68.   
  69.     struct i2c_msg msg[2] = {  
  70.         {client->addr, 0, 2, txbuf},  
  71.     };  
  72.   
  73.     i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
  74.   
  75.     return 0;  
  76. }  
  77.   
  78.   
  79. static int mpu6050_open(struct inode *inode, struct file *file)   
  80. {  
  81.     return 0;  
  82. }  
  83.   
  84. static int mpu6050_release(struct inode *inode, struct file *file)   
  85. {  
  86.     return 0;  
  87. }  
  88.   
  89. static long mpu6050_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  90. {  
  91.     union mpu6050_data data;  
  92.     struct i2c_client *client = mpu6050->client;  
  93.   
  94.     switch(cmd) {  
  95.     case GET_ACCEL:  
  96.         data.accel.x = mpu6050_read_byte(client, ACCEL_XOUT_L);  
  97.         data.accel.x |= mpu6050_read_byte(client, ACCEL_XOUT_H) << 8;  
  98.   
  99.         data.accel.y = mpu6050_read_byte(client, ACCEL_YOUT_L);  
  100.         data.accel.y |= mpu6050_read_byte(client, ACCEL_YOUT_H) << 8;  
  101.   
  102.         data.accel.z = mpu6050_read_byte(client, ACCEL_ZOUT_L);  
  103.         data.accel.z |= mpu6050_read_byte(client, ACCEL_ZOUT_H) << 8;  
  104.         break;  
  105.   
  106.     case GET_GYRO:  
  107.   
  108.         data.gyro.x = mpu6050_read_byte(client, GYRO_XOUT_L);  
  109.         data.gyro.x |= mpu6050_read_byte(client, GYRO_XOUT_H) << 8;  
  110.   
  111.         data.gyro.y = mpu6050_read_byte(client, GYRO_YOUT_L);  
  112.         data.gyro.y |= mpu6050_read_byte(client, GYRO_YOUT_H) << 8;  
  113.   
  114.         data.gyro.z = mpu6050_read_byte(client, GYRO_ZOUT_L);  
  115.         data.gyro.z |= mpu6050_read_byte(client, GYRO_ZOUT_H) << 8;  
  116.         break;  
  117.   
  118.     case GET_TEMP:    
  119.         data.temp = mpu6050_read_byte(client, TEMP_OUT_L);  
  120.         data.temp |= mpu6050_read_byte(client, TEMP_OUT_H) << 8;  
  121.         break;  
  122.   
  123.     default:  
  124.         printk("invalid argument\n");  
  125.         return -EINVAL;  
  126.     }  
  127.   
  128.     if (copy_to_user((void *)arg, &data, sizeof(data)))  
  129.         return -EFAULT;  
  130.   
  131.     return sizeof(data);  
  132. }  
  133.   
  134. struct file_operations mpu6050_fops = {  
  135.     .owner      = THIS_MODULE,  
  136.     .open       = mpu6050_open,  
  137.     .release    = mpu6050_release,  
  138.     .unlocked_ioctl = mpu6050_ioctl,  
  139. };  
  140.   
  141. static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  142. {  
  143.     int ret;  
  144.     dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
  145.     printk("match OK!\n");  
  146.   
  147.     mpu6050 = kzalloc(sizeof(*mpu6050), GFP_KERNEL);  
  148.     if (mpu6050 == NULL) {  
  149.         return -ENOMEM;  
  150.     }  
  151.   
  152.     mpu6050->client = client;  
  153.   
  154.     ret = register_chrdev_region(devno, 1, "mpu6050");  
  155.     if (ret < 0) {  
  156.         printk("failed to register char device region!\n");  
  157.         goto err1;  
  158.     }  
  159.   
  160.     cdev_init(&mpu6050->cdev, &mpu6050_fops);  
  161.     mpu6050->cdev.owner = THIS_MODULE;  
  162.     ret = cdev_add(&mpu6050->cdev, devno, 1);  
  163.     if (ret < 0) {  
  164.         printk("failed to add device\n");  
  165.         goto err2;  
  166.     }  
  167.       
  168.     mpu6050_write_byte(client, PWR_MGMT_1, 0x00);  
  169.     mpu6050_write_byte(client, SMPLRT_DIV, 0x07);  
  170.     mpu6050_write_byte(client, CONFIG, 0x06);  
  171.     mpu6050_write_byte(client, GYRO_CONFIG, 0xF8);  
  172.     mpu6050_write_byte(client, ACCEL_CONFIG, 0x19);  
  173.   
  174.     return 0;  
  175. err2:  
  176.     unregister_chrdev_region(devno, 1);  
  177. err1:  
  178.     kfree(mpu6050);  
  179.     return ret;  
  180. }  
  181.   
  182. static int mpu6050_remove(struct i2c_client *client)  
  183. {  
  184.     dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
  185.     cdev_del(&mpu6050->cdev);  
  186.     unregister_chrdev_region(devno, 1);  
  187.     kfree(mpu6050);  
  188.   
  189.     return 0;  
  190. }  
  191.   
  192. static const struct i2c_device_id mpu6050_id[] = {  
  193.     { "mpu6050", 0},  
  194.     {}  
  195. };   
  196.   
  197. static struct of_device_id mpu6050_dt_match[] = {  
  198.     {.compatible = "invense,mpu6050" },  
  199.     {/*northing to be done*/},  
  200. };  
  201.   
  202. struct i2c_driver mpu6050_driver = {  
  203.     .driver = {  
  204.         .name           = "mpu6050",  
  205.         .owner          = THIS_MODULE,  
  206.         .of_match_table = of_match_ptr(mpu6050_dt_match),  
  207.     },  
  208.     .probe      = mpu6050_probe,  
  209.     .remove     = mpu6050_remove,  
  210.     .id_table   = mpu6050_id,  
  211. };  
  212.   
  213. static init _init mpu6050_init(void)  
  214. {  
  215.     return i2c_add_driver(&mpu6050_driver);  
  216. }  
  217.   
  218. static void _exit mpu6050_exit(void)  
  219. {  
  220.     return i2c_del_driver(&mpu6050_driver);  
  221. }  
  222.   
  223. module_init(&mpu6050_init);  
  224. module_exit(&mpu6050_exit);  


test.c
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <fcntl.h>  
  5. #include <sys/ioctl.h>  
  6.   
  7. #include "mpu6050.h"  
  8.   
  9. int main(int argc, const char *argv[])  
  10. {  
  11.     int fd;  
  12.     union mpu6050_data data;   
  13.       
  14.     fd = open("/dev/mpu6050", O_RDWR);  
  15.     if (fd < 0) {  
  16.         perror("open");  
  17.         exit(1);  
  18.     }  
  19.   
  20.     while(1) {  
  21.         ioctl(fd, GET_ACCEL, &data);  
  22.         printf("acceleration data: x = %04x, y = %04x, z = %04x\n",   
  23.                 data.accel.x, data.accel.y, data.accel.z);  
  24.   
  25.         ioctl(fd, GET_GYRO, &data);  
  26.         printf("gyroscope data: x = %04x, y = %04x, z = %04x\n",   
  27.                 data.accel.x, data.accel.y, data.accel.z);  
  28.   
  29.         sleep(1);  
  30.     }  
  31.   
  32.     close(fd);  
  33.   
  34.     return 0;  
  35. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402240.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫利器六PyQuery的用法

你是否觉得 XPath 的用法多少有点晦涩难记呢&#xff1f; 你是否觉得 BeautifulSoup 的语法多少有些悭吝难懂呢&#xff1f; 你是否甚至还在苦苦研究正则表达式却因为少些了一个点而抓狂呢&#xff1f; 你是否已经有了一些前端基础了解选择器却与另外一些奇怪的选择器语法混淆了…

windows10下载

http://care.dlservice.microsoft.com/dl/download/F/5/7/F574727C-B145-4A7D-B85B-11C4E8DC894B/9841.0.140912-1613.FBL_RELEASE_CLIENTENTERPRISE_VOL_X64FRE_ZH-CN.ISO转载于:https://www.cnblogs.com/thankyouGod/p/6366971.html

Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析

关于Exynos4412 IIC 裸机开发请看 &#xff1a;Exynos4412 裸机开发 —— IIC总线 &#xff0c;下面回顾下 IIC 基础概念 一、IIC 基础概念 IIC(Inter&#xff0d;Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线&#xff0c;用于连接微控制器及其外围设备。I…

Python 爬虫进阶一之爬虫框架概述

综述 爬虫入门之后&#xff0c;我们有两条路可以走。 一个是继续深入学习&#xff0c;以及关于设计模式的一些知识&#xff0c;强化 Python 相关知识&#xff0c;自己动手造轮子&#xff0c;继续为自己的爬虫增加分布式&#xff0c;多线程等功能扩展。另一条路便是学习一些优秀…

1039. 到底买不买(20)

1039. 到底买不买&#xff08;20&#xff09; 小红想买些珠子做一串自己喜欢的珠串。卖珠子的摊主有很多串五颜六色的珠串&#xff0c;但是不肯把任何一串拆散了卖。于是小红要你帮忙判断一下&#xff0c;某串珠子里是否包含了全部自己想要的珠子&#xff1f;如果是&#xff0c…

Exynos4412 ADC 设备驱动开发

具体ADC硬件知识及裸机驱动请看&#xff1a; Exynos4412裸机开发 —— A/D转换器 1、原理图如下&#xff1a; 2、相关寄存器信息 ADC_BASE 0x126C0000ADCCON 0x0000 1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6ADCDLY 0x000…

mongodb morphia

原文&#xff1a;http://www.blogjava.net/watchzerg/archive/2012/09/20/388109.html快速开始&#xff1a;Entitypublic class Hotel {Id private ObjectId id;private String name;private int stars;Embeddedprivate Address address;}Embeddedpublic class Address {privat…

2017 《Java技术预备作业 》1501 乔 赫

1.阅读邹欣老师的博客,谈谈你期望的师生关系是什么样的&#xff1f; 师生关系为亦师亦友&#xff0c;但不缺少老师的严肃 2.你有什么技能&#xff08;学习&#xff0c;棋类&#xff0c;球类&#xff0c;乐器&#xff0c;艺术&#xff0c;游戏&#xff0c;......&#xff09;比大…

Python 爬虫进阶二之 PySpider 框架安装配置

PySpider官方文档 项目地址 官方文档 安装 phantomjs PhantomJS 是一个基于 WebKit 的服务器端 JavaScript API。它全面支持 web 而不需浏览器支持&#xff0c;其快速、原生支持各种 Web 标准&#xff1a;DOM 处理、CSS 选择器、JSON、Canvas 和 SVG。 PhantomJS 可以用于页…

Exynos4412 中断驱动开发(三)—— 设备树中中断节点的创建

提到中断就必须了解到GIC&#xff0c;下面先了解一下GIC 一、GIC概念 GIC&#xff08;Generic Interrupt Controller&#xff09;是ARM公司提供的一个通用的中断控制器。GIC通过AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;这样的片上总线连接到一个…

老码农:如何写出让自己满意的代码

今天有位朋友在微博上问我这样一个问题&#xff1a; “老码农的自留地 &#xff0c;最近出于学习目的写一个管理系统&#xff0c;越到后边&#xff0c;越觉得自己前边的代码写得烂。前辈&#xff0c;我想让代码写得更好一点&#xff0c;能不能谈谈你的经验&#xff0c;给我指点…

Python 爬虫进阶三之 Scrapy 框架安装配置

初级的爬虫我们利用 urllib 和 urllib2 库以及正则表达式就可以完成了&#xff0c;不过还有更加强大的工具&#xff0c;爬虫框架 Scrapy&#xff0c;这安装过程也是煞费苦心哪&#xff0c;在此整理如下。 官网 官方安装文档 安装python 安装 Python 安装过程我就不多说啦&a…

泛型类、泛型方法及泛型应用

泛型类、泛型方法及泛型应用 泛型是Java SE 1.5的新特性&#xff0c;泛型的本质是参数化类型&#xff0c;也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中&#xff0c;分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安…

Exynos4412 中断驱动开发(二)—— 中断处理流程分析

前面已经学习了中断的注册过程&#xff0c;下面由一张流程图来看一下当中断发生时的处理流程&#xff1a; 中断发生之后处理流程 a -- 具体的CPU architecture相关模块进行现场保护&#xff0c;然后调用machine driver执行对应的中断处理handler; b -- machine driver对应中断处…

用For循环加cat按顺序合并文件

工作目录下面有mydoc1.txt&#xff0c;mydoc2.txt...mydoc41.txt&#xff0c;本来想用sed排列依次取值排序&#xff0c;然后用cat来合并这些文件&#xff0c;发现达不到预期效果&#xff0c;合并令如下所示&#xff1a;ls -lF *.txt | sed -n /mydoc1/,/mydoc41/p | xargs -i …

Python 函数装饰器

装饰器(Decorators)是 Python 的一个重要部分。简单地说&#xff1a;他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短&#xff0c;也更Pythonic&#xff08;Python范儿&#xff09;。大多数初学者不知道在哪儿使用它们&#xff0c;所以我将要分享下&#xff0c;…

vim永久取消空格颜色

这是无意中发现的 vim 随便一个文件的时候空格变成某种颜色,感觉太显眼了 而:set nohsl只能一次修改 而且在执行:set nu 下是不可执行 我们只需在编辑中执行 :.,s/hsl/nohsl/gc转载于:https://www.cnblogs.com/spaceport/p/6379435.html

Exynos4412 中断驱动开发(一)—— 中断基础及中断的注册过程

一、中断基础概念 所谓中断&#xff0c;指CPU在执行程序的过程中&#xff0c;出现了某些突发事件即待处理&#xff0c;CPU必须暂停当前的程序。转去处理突发事件&#xff0c;处理完毕后CPU又返回原程序被中断的位置并继续执行。 1、中断分类 a -- 内部中断和外部中断 根据中断的…

调试与分析

一、获取内核转储 大多数Linux发行版默认关闭内核转储功能&#xff0c;可使用 ulimit -c 查看&#xff0c;-c 表示内核转储文件的大小限制&#xff0c;如果为0&#xff0c;表示未开启。 1、可设置为 ulimit -c unlimited 表示无限制&#xff0c;或设置为其它数值&#xff0c;单…

CSS选择器学习笔记

在 CSS 中&#xff0c;选择器是一种模式&#xff0c;用于选择需要添加样式的元素。 “CSS” 列指示该属性是在哪个 CSS 版本中定义的。&#xff08;CSS1、CSS2 还是 CSS3。&#xff09; 选择器例子例子描述CSS.class.intro选择 class“intro” 的所有元素。1#id#firstname选择…