前面在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、创建设备树节点
      通过上面获取的信息,可以写出
- 
i2c@138b0000 {  
- 
        #address-cells = <1>;  
- 
        #size-cells = <0>;  
- 
  
- 
        samsung,i2c-sda-delay = <100>;  
- 
        samsung,i2c-max-bus-freq = <20000>;  
- 
        pinctrl-0 = <&i2c5_bus>;  
- 
        pinctrl-names = "default";  
- 
        status = "okay";  
- 
     
- 
        pmu6050-3-asix@68 {  
- 
               compatible = "invense,mpu6050";  
- 
               reg = <0x68>;  
- 
              interrupt-parent = <&gpx3>;  
- 
              interrupts = <3 2>;  
- 
        };  
- 
};  
 
3、MPU6050相应寄存器
- 
#define SMPLRT_DIV 0x19 //采样率分频,典型值: 0x07(125Hz) */  
- 
#define CONFIG 0x1A // 低通滤波频率,典型值: 0x06(5Hz) */  
- 
#define GYRO_CONFIG 0x1B // 陀螺仪自检及测量范围,典型值: 0x18(不自检,2000deg/s) */  
- 
#define ACCEL_CONFIG 0x1C // 加速计自检、测量范围及高通滤波频率,典型值: 0x01(不自检, 2G, 5Hz) */  
- 
#define ACCEL_XOUT_H 0x3B // 存储最近的 X 轴、 Y 轴、 Z 轴加速度感应器的测量值 */  
- 
#define ACCEL_XOUT_L 0x3C  
- 
#define ACCEL_YOUT_H 0x3D  
- 
#define ACCEL_YOUT_L 0x3E  
- 
#define ACCEL_ZOUT_H 0x3F  
- 
#define ACCEL_ZOUT_L 0x40  
- 
#define TEMP_OUT_H 0x41 // 存储的最近温度传感器的测量值 */  
- 
#define TEMP_OUT_L 0x42  
- 
#define GYRO_XOUT_H 0x43 // 存储最近的 X 轴、 Y 轴、 Z 轴陀螺仪感应器的测量值 */  
- 
#define GYRO_XOUT_L 0x44  
- 
#define GYRO_YOUT_H 0x45  
- 
#define GYRO_YOUT_L 0x46  
- 
#define GYRO_ZOUT_H 0x47  
- 
#define GYRO_ZOUT_L 0x48  
- 
#define PWR_MGMT_1 0x6B // 电源管理,典型值: 0x00(正常启用) */  
- 
#define WHO_AM_I 0x75 //IIC 地址寄存器(默认数值 0x68,只读) */  
 
4、具体程序
mpu6050.h
- 
#ifndef MPU6050_HHHH  
- 
#define MPU6050_HHHH  
- 
  
- 
#define MPU6050_MAGIC ‘K‘  
- 
  
- 
union mpu6050_data  
- 
{  
- 
    struct {  
- 
        unsigned short x;  
- 
        unsigned short y;  
- 
        unsigned short z;  
- 
    }accel;  
- 
    struct {  
- 
        unsigned short x;  
- 
        unsigned short y;  
- 
        unsigned short z;  
- 
    }gyro;  
- 
    unsigned short temp;  
- 
};  
- 
  
- 
#define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)  
- 
#define GET_GYRO  _IOR(MPU6050_MAGIC, 1, union mpu6050_data)   
- 
#define GET_TEMP  _IOR(MPU6050_MAGIC, 2, union mpu6050_data)  
- 
  
- 
#endif  
 
i2c_driver
- 
#include <linux/kernel.h>  
- 
#include <linux/module.h>  
- 
#include <linux/i2c.h>  
- 
#include <linux/cdev.h>  
- 
#include <linux/slab.h>  
- 
#include <linux/fs.h>  
- 
#include <linux/delay.h>  
- 
  
- 
#include <asm/uaccess.h>  
- 
  
- 
#include "mpu6050.h"  
- 
  
- 
MODULE_LICENSE("GPL");  
- 
  
- 
#define SMPLRT_DIV      0x19  
- 
#define CONFIG          0x1A  
- 
#define GYRO_CONFIG     0x1B  
- 
#define ACCEL_CONFIG    0x1C  
- 
#define ACCEL_XOUT_H    0x3B  
- 
#define ACCEL_XOUT_L    0x3C  
- 
#define ACCEL_YOUT_H    0x3D  
- 
#define ACCEL_YOUT_L    0x3E  
- 
#define ACCEL_ZOUT_H    0x3F  
- 
#define ACCEL_ZOUT_L    0x40  
- 
#define TEMP_OUT_H      0x41  
- 
#define TEMP_OUT_L      0x42  
- 
#define GYRO_XOUT_H     0x43  
- 
#define GYRO_XOUT_L     0x44  
- 
#define GYRO_YOUT_H     0x45  
- 
#define GYRO_YOUT_L     0x46  
- 
#define GYRO_ZOUT_H     0x47  
- 
#define GYRO_ZOUT_L     0x48  
- 
#define PWR_MGMT_1      0x6B  
- 
  
- 
#define MPU6050_MAJOR 500  
- 
#define MPU6050_MINOR 0  
- 
  
- 
struct mpu6050_device {  
- 
    struct cdev cdev;  
- 
    struct i2c_client *client;  
- 
};  
- 
struct mpu6050_device *mpu6050;   
- 
  
- 
static int mpu6050_read_byte(struct i2c_client *client, unsigned char reg)  
- 
{  
- 
    int ret;  
- 
  
- 
    char txbuf[1] = { reg };  
- 
    char rxbuf[1];  
- 
  
- 
    struct i2c_msg msg[2] = {  
- 
        {client->addr, 0, 1, txbuf},  
- 
        {client->addr, I2C_M_RD, 1, rxbuf}  
- 
    };  
- 
  
- 
    ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
- 
    if (ret < 0) {  
- 
        printk("ret = %d\n", ret);  
- 
        return ret;  
- 
    }  
- 
  
- 
    return rxbuf[0];  
- 
}  
- 
  
- 
static int mpu6050_write_byte(struct i2c_client *client, unsigned char reg, unsigned char val)  
- 
{  
- 
    char txbuf[2] = {reg, val};  
- 
  
- 
    struct i2c_msg msg[2] = {  
- 
        {client->addr, 0, 2, txbuf},  
- 
    };  
- 
  
- 
    i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
- 
  
- 
    return 0;  
- 
}  
- 
  
- 
  
- 
static int mpu6050_open(struct inode *inode, struct file *file)   
- 
{  
- 
    return 0;  
- 
}  
- 
  
- 
static int mpu6050_release(struct inode *inode, struct file *file)   
- 
{  
- 
    return 0;  
- 
}  
- 
  
- 
static long mpu6050_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
- 
{  
- 
    union mpu6050_data data;  
- 
    struct i2c_client *client = mpu6050->client;  
- 
  
- 
    switch(cmd) {  
- 
    case GET_ACCEL:  
- 
        data.accel.x = mpu6050_read_byte(client, ACCEL_XOUT_L);  
- 
        data.accel.x |= mpu6050_read_byte(client, ACCEL_XOUT_H) << 8;  
- 
  
- 
        data.accel.y = mpu6050_read_byte(client, ACCEL_YOUT_L);  
- 
        data.accel.y |= mpu6050_read_byte(client, ACCEL_YOUT_H) << 8;  
- 
  
- 
        data.accel.z = mpu6050_read_byte(client, ACCEL_ZOUT_L);  
- 
        data.accel.z |= mpu6050_read_byte(client, ACCEL_ZOUT_H) << 8;  
- 
        break;  
- 
  
- 
    case GET_GYRO:  
- 
  
- 
        data.gyro.x = mpu6050_read_byte(client, GYRO_XOUT_L);  
- 
        data.gyro.x |= mpu6050_read_byte(client, GYRO_XOUT_H) << 8;  
- 
  
- 
        data.gyro.y = mpu6050_read_byte(client, GYRO_YOUT_L);  
- 
        data.gyro.y |= mpu6050_read_byte(client, GYRO_YOUT_H) << 8;  
- 
  
- 
        data.gyro.z = mpu6050_read_byte(client, GYRO_ZOUT_L);  
- 
        data.gyro.z |= mpu6050_read_byte(client, GYRO_ZOUT_H) << 8;  
- 
        break;  
- 
  
- 
    case GET_TEMP:    
- 
        data.temp = mpu6050_read_byte(client, TEMP_OUT_L);  
- 
        data.temp |= mpu6050_read_byte(client, TEMP_OUT_H) << 8;  
- 
        break;  
- 
  
- 
    default:  
- 
        printk("invalid argument\n");  
- 
        return -EINVAL;  
- 
    }  
- 
  
- 
    if (copy_to_user((void *)arg, &data, sizeof(data)))  
- 
        return -EFAULT;  
- 
  
- 
    return sizeof(data);  
- 
}  
- 
  
- 
struct file_operations mpu6050_fops = {  
- 
    .owner      = THIS_MODULE,  
- 
    .open       = mpu6050_open,  
- 
    .release    = mpu6050_release,  
- 
    .unlocked_ioctl = mpu6050_ioctl,  
- 
};  
- 
  
- 
static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)  
- 
{  
- 
    int ret;  
- 
    dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
- 
    printk("match OK!\n");  
- 
  
- 
    mpu6050 = kzalloc(sizeof(*mpu6050), GFP_KERNEL);  
- 
    if (mpu6050 == NULL) {  
- 
        return -ENOMEM;  
- 
    }  
- 
  
- 
    mpu6050->client = client;  
- 
  
- 
    ret = register_chrdev_region(devno, 1, "mpu6050");  
- 
    if (ret < 0) {  
- 
        printk("failed to register char device region!\n");  
- 
        goto err1;  
- 
    }  
- 
  
- 
    cdev_init(&mpu6050->cdev, &mpu6050_fops);  
- 
    mpu6050->cdev.owner = THIS_MODULE;  
- 
    ret = cdev_add(&mpu6050->cdev, devno, 1);  
- 
    if (ret < 0) {  
- 
        printk("failed to add device\n");  
- 
        goto err2;  
- 
    }  
- 
      
- 
    mpu6050_write_byte(client, PWR_MGMT_1, 0x00);  
- 
    mpu6050_write_byte(client, SMPLRT_DIV, 0x07);  
- 
    mpu6050_write_byte(client, CONFIG, 0x06);  
- 
    mpu6050_write_byte(client, GYRO_CONFIG, 0xF8);  
- 
    mpu6050_write_byte(client, ACCEL_CONFIG, 0x19);  
- 
  
- 
    return 0;  
- 
err2:  
- 
    unregister_chrdev_region(devno, 1);  
- 
err1:  
- 
    kfree(mpu6050);  
- 
    return ret;  
- 
}  
- 
  
- 
static int mpu6050_remove(struct i2c_client *client)  
- 
{  
- 
    dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
- 
    cdev_del(&mpu6050->cdev);  
- 
    unregister_chrdev_region(devno, 1);  
- 
    kfree(mpu6050);  
- 
  
- 
    return 0;  
- 
}  
- 
  
- 
static const struct i2c_device_id mpu6050_id[] = {  
- 
    { "mpu6050", 0},  
- 
    {}  
- 
};   
- 
  
- 
static struct of_device_id mpu6050_dt_match[] = {  
- 
    {.compatible = "invense,mpu6050" },  
- 
    {},  
- 
};  
- 
  
- 
struct i2c_driver mpu6050_driver = {  
- 
    .driver = {  
- 
        .name           = "mpu6050",  
- 
        .owner          = THIS_MODULE,  
- 
        .of_match_table = of_match_ptr(mpu6050_dt_match),  
- 
    },  
- 
    .probe      = mpu6050_probe,  
- 
    .remove     = mpu6050_remove,  
- 
    .id_table   = mpu6050_id,  
- 
};  
- 
  
- 
static init _init mpu6050_init(void)  
- 
{  
- 
    return i2c_add_driver(&mpu6050_driver);  
- 
}  
- 
  
- 
static void _exit mpu6050_exit(void)  
- 
{  
- 
    return i2c_del_driver(&mpu6050_driver);  
- 
}  
- 
  
- 
module_init(&mpu6050_init);  
- 
module_exit(&mpu6050_exit);  
 
test.c
- 
#include <stdio.h>  
- 
#include <stdlib.h>  
- 
#include <unistd.h>  
- 
#include <fcntl.h>  
- 
#include <sys/ioctl.h>  
- 
  
- 
#include "mpu6050.h"  
- 
  
- 
int main(int argc, const char *argv[])  
- 
{  
- 
    int fd;  
- 
    union mpu6050_data data;   
- 
      
- 
    fd = open("/dev/mpu6050", O_RDWR);  
- 
    if (fd < 0) {  
- 
        perror("open");  
- 
        exit(1);  
- 
    }  
- 
  
- 
    while(1) {  
- 
        ioctl(fd, GET_ACCEL, &data);  
- 
        printf("acceleration data: x = %04x, y = %04x, z = %04x\n",   
- 
                data.accel.x, data.accel.y, data.accel.z);  
- 
  
- 
        ioctl(fd, GET_GYRO, &data);  
- 
        printf("gyroscope data: x = %04x, y = %04x, z = %04x\n",   
- 
                data.accel.x, data.accel.y, data.accel.z);  
- 
  
- 
        sleep(1);  
- 
    }  
- 
  
- 
    close(fd);  
- 
  
- 
    return 0;  
- 
}  
 
前面在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、创建设备树节点
      通过上面获取的信息,可以写出
- 
i2c@138b0000 {  
- 
        #address-cells = <1>;  
- 
        #size-cells = <0>;  
- 
  
- 
        samsung,i2c-sda-delay = <100>;  
- 
        samsung,i2c-max-bus-freq = <20000>;  
- 
        pinctrl-0 = <&i2c5_bus>;  
- 
        pinctrl-names = "default";  
- 
        status = "okay";  
- 
     
- 
        pmu6050-3-asix@68 {  
- 
               compatible = "invense,mpu6050";  
- 
               reg = <0x68>;  
- 
              interrupt-parent = <&gpx3>;  
- 
              interrupts = <3 2>;  
- 
        };  
- 
};  
 
3、MPU6050相应寄存器
- 
#define SMPLRT_DIV 0x19 //采样率分频,典型值: 0x07(125Hz) */  
- 
#define CONFIG 0x1A // 低通滤波频率,典型值: 0x06(5Hz) */  
- 
#define GYRO_CONFIG 0x1B // 陀螺仪自检及测量范围,典型值: 0x18(不自检,2000deg/s) */  
- 
#define ACCEL_CONFIG 0x1C // 加速计自检、测量范围及高通滤波频率,典型值: 0x01(不自检, 2G, 5Hz) */  
- 
#define ACCEL_XOUT_H 0x3B // 存储最近的 X 轴、 Y 轴、 Z 轴加速度感应器的测量值 */  
- 
#define ACCEL_XOUT_L 0x3C  
- 
#define ACCEL_YOUT_H 0x3D  
- 
#define ACCEL_YOUT_L 0x3E  
- 
#define ACCEL_ZOUT_H 0x3F  
- 
#define ACCEL_ZOUT_L 0x40  
- 
#define TEMP_OUT_H 0x41 // 存储的最近温度传感器的测量值 */  
- 
#define TEMP_OUT_L 0x42  
- 
#define GYRO_XOUT_H 0x43 // 存储最近的 X 轴、 Y 轴、 Z 轴陀螺仪感应器的测量值 */  
- 
#define GYRO_XOUT_L 0x44  
- 
#define GYRO_YOUT_H 0x45  
- 
#define GYRO_YOUT_L 0x46  
- 
#define GYRO_ZOUT_H 0x47  
- 
#define GYRO_ZOUT_L 0x48  
- 
#define PWR_MGMT_1 0x6B // 电源管理,典型值: 0x00(正常启用) */  
- 
#define WHO_AM_I 0x75 //IIC 地址寄存器(默认数值 0x68,只读) */  
 
4、具体程序
mpu6050.h
- 
#ifndef MPU6050_HHHH  
- 
#define MPU6050_HHHH  
- 
  
- 
#define MPU6050_MAGIC ‘K‘  
- 
  
- 
union mpu6050_data  
- 
{  
- 
    struct {  
- 
        unsigned short x;  
- 
        unsigned short y;  
- 
        unsigned short z;  
- 
    }accel;  
- 
    struct {  
- 
        unsigned short x;  
- 
        unsigned short y;  
- 
        unsigned short z;  
- 
    }gyro;  
- 
    unsigned short temp;  
- 
};  
- 
  
- 
#define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)  
- 
#define GET_GYRO  _IOR(MPU6050_MAGIC, 1, union mpu6050_data)   
- 
#define GET_TEMP  _IOR(MPU6050_MAGIC, 2, union mpu6050_data)  
- 
  
- 
#endif  
 
i2c_driver
- 
#include <linux/kernel.h>  
- 
#include <linux/module.h>  
- 
#include <linux/i2c.h>  
- 
#include <linux/cdev.h>  
- 
#include <linux/slab.h>  
- 
#include <linux/fs.h>  
- 
#include <linux/delay.h>  
- 
  
- 
#include <asm/uaccess.h>  
- 
  
- 
#include "mpu6050.h"  
- 
  
- 
MODULE_LICENSE("GPL");  
- 
  
- 
#define SMPLRT_DIV      0x19  
- 
#define CONFIG          0x1A  
- 
#define GYRO_CONFIG     0x1B  
- 
#define ACCEL_CONFIG    0x1C  
- 
#define ACCEL_XOUT_H    0x3B  
- 
#define ACCEL_XOUT_L    0x3C  
- 
#define ACCEL_YOUT_H    0x3D  
- 
#define ACCEL_YOUT_L    0x3E  
- 
#define ACCEL_ZOUT_H    0x3F  
- 
#define ACCEL_ZOUT_L    0x40  
- 
#define TEMP_OUT_H      0x41  
- 
#define TEMP_OUT_L      0x42  
- 
#define GYRO_XOUT_H     0x43  
- 
#define GYRO_XOUT_L     0x44  
- 
#define GYRO_YOUT_H     0x45  
- 
#define GYRO_YOUT_L     0x46  
- 
#define GYRO_ZOUT_H     0x47  
- 
#define GYRO_ZOUT_L     0x48  
- 
#define PWR_MGMT_1      0x6B  
- 
  
- 
#define MPU6050_MAJOR 500  
- 
#define MPU6050_MINOR 0  
- 
  
- 
struct mpu6050_device {  
- 
    struct cdev cdev;  
- 
    struct i2c_client *client;  
- 
};  
- 
struct mpu6050_device *mpu6050;   
- 
  
- 
static int mpu6050_read_byte(struct i2c_client *client, unsigned char reg)  
- 
{  
- 
    int ret;  
- 
  
- 
    char txbuf[1] = { reg };  
- 
    char rxbuf[1];  
- 
  
- 
    struct i2c_msg msg[2] = {  
- 
        {client->addr, 0, 1, txbuf},  
- 
        {client->addr, I2C_M_RD, 1, rxbuf}  
- 
    };  
- 
  
- 
    ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
- 
    if (ret < 0) {  
- 
        printk("ret = %d\n", ret);  
- 
        return ret;  
- 
    }  
- 
  
- 
    return rxbuf[0];  
- 
}  
- 
  
- 
static int mpu6050_write_byte(struct i2c_client *client, unsigned char reg, unsigned char val)  
- 
{  
- 
    char txbuf[2] = {reg, val};  
- 
  
- 
    struct i2c_msg msg[2] = {  
- 
        {client->addr, 0, 2, txbuf},  
- 
    };  
- 
  
- 
    i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
- 
  
- 
    return 0;  
- 
}  
- 
  
- 
  
- 
static int mpu6050_open(struct inode *inode, struct file *file)   
- 
{  
- 
    return 0;  
- 
}  
- 
  
- 
static int mpu6050_release(struct inode *inode, struct file *file)   
- 
{  
- 
    return 0;  
- 
}  
- 
  
- 
static long mpu6050_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
- 
{  
- 
    union mpu6050_data data;  
- 
    struct i2c_client *client = mpu6050->client;  
- 
  
- 
    switch(cmd) {  
- 
    case GET_ACCEL:  
- 
        data.accel.x = mpu6050_read_byte(client, ACCEL_XOUT_L);  
- 
        data.accel.x |= mpu6050_read_byte(client, ACCEL_XOUT_H) << 8;  
- 
  
- 
        data.accel.y = mpu6050_read_byte(client, ACCEL_YOUT_L);  
- 
        data.accel.y |= mpu6050_read_byte(client, ACCEL_YOUT_H) << 8;  
- 
  
- 
        data.accel.z = mpu6050_read_byte(client, ACCEL_ZOUT_L);  
- 
        data.accel.z |= mpu6050_read_byte(client, ACCEL_ZOUT_H) << 8;  
- 
        break;  
- 
  
- 
    case GET_GYRO:  
- 
  
- 
        data.gyro.x = mpu6050_read_byte(client, GYRO_XOUT_L);  
- 
        data.gyro.x |= mpu6050_read_byte(client, GYRO_XOUT_H) << 8;  
- 
  
- 
        data.gyro.y = mpu6050_read_byte(client, GYRO_YOUT_L);  
- 
        data.gyro.y |= mpu6050_read_byte(client, GYRO_YOUT_H) << 8;  
- 
  
- 
        data.gyro.z = mpu6050_read_byte(client, GYRO_ZOUT_L);  
- 
        data.gyro.z |= mpu6050_read_byte(client, GYRO_ZOUT_H) << 8;  
- 
        break;  
- 
  
- 
    case GET_TEMP:    
- 
        data.temp = mpu6050_read_byte(client, TEMP_OUT_L);  
- 
        data.temp |= mpu6050_read_byte(client, TEMP_OUT_H) << 8;  
- 
        break;  
- 
  
- 
    default:  
- 
        printk("invalid argument\n");  
- 
        return -EINVAL;  
- 
    }  
- 
  
- 
    if (copy_to_user((void *)arg, &data, sizeof(data)))  
- 
        return -EFAULT;  
- 
  
- 
    return sizeof(data);  
- 
}  
- 
  
- 
struct file_operations mpu6050_fops = {  
- 
    .owner      = THIS_MODULE,  
- 
    .open       = mpu6050_open,  
- 
    .release    = mpu6050_release,  
- 
    .unlocked_ioctl = mpu6050_ioctl,  
- 
};  
- 
  
- 
static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)  
- 
{  
- 
    int ret;  
- 
    dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
- 
    printk("match OK!\n");  
- 
  
- 
    mpu6050 = kzalloc(sizeof(*mpu6050), GFP_KERNEL);  
- 
    if (mpu6050 == NULL) {  
- 
        return -ENOMEM;  
- 
    }  
- 
  
- 
    mpu6050->client = client;  
- 
  
- 
    ret = register_chrdev_region(devno, 1, "mpu6050");  
- 
    if (ret < 0) {  
- 
        printk("failed to register char device region!\n");  
- 
        goto err1;  
- 
    }  
- 
  
- 
    cdev_init(&mpu6050->cdev, &mpu6050_fops);  
- 
    mpu6050->cdev.owner = THIS_MODULE;  
- 
    ret = cdev_add(&mpu6050->cdev, devno, 1);  
- 
    if (ret < 0) {  
- 
        printk("failed to add device\n");  
- 
        goto err2;  
- 
    }  
- 
      
- 
    mpu6050_write_byte(client, PWR_MGMT_1, 0x00);  
- 
    mpu6050_write_byte(client, SMPLRT_DIV, 0x07);  
- 
    mpu6050_write_byte(client, CONFIG, 0x06);  
- 
    mpu6050_write_byte(client, GYRO_CONFIG, 0xF8);  
- 
    mpu6050_write_byte(client, ACCEL_CONFIG, 0x19);  
- 
  
- 
    return 0;  
- 
err2:  
- 
    unregister_chrdev_region(devno, 1);  
- 
err1:  
- 
    kfree(mpu6050);  
- 
    return ret;  
- 
}  
- 
  
- 
static int mpu6050_remove(struct i2c_client *client)  
- 
{  
- 
    dev_t devno = MKDEV(MPU6050_MAJOR, MPU6050_MINOR);  
- 
    cdev_del(&mpu6050->cdev);  
- 
    unregister_chrdev_region(devno, 1);  
- 
    kfree(mpu6050);  
- 
  
- 
    return 0;  
- 
}  
- 
  
- 
static const struct i2c_device_id mpu6050_id[] = {  
- 
    { "mpu6050", 0},  
- 
    {}  
- 
};   
- 
  
- 
static struct of_device_id mpu6050_dt_match[] = {  
- 
    {.compatible = "invense,mpu6050" },  
- 
    {},  
- 
};  
- 
  
- 
struct i2c_driver mpu6050_driver = {  
- 
    .driver = {  
- 
        .name           = "mpu6050",  
- 
        .owner          = THIS_MODULE,  
- 
        .of_match_table = of_match_ptr(mpu6050_dt_match),  
- 
    },  
- 
    .probe      = mpu6050_probe,  
- 
    .remove     = mpu6050_remove,  
- 
    .id_table   = mpu6050_id,  
- 
};  
- 
  
- 
static init _init mpu6050_init(void)  
- 
{  
- 
    return i2c_add_driver(&mpu6050_driver);  
- 
}  
- 
  
- 
static void _exit mpu6050_exit(void)  
- 
{  
- 
    return i2c_del_driver(&mpu6050_driver);  
- 
}  
- 
  
- 
module_init(&mpu6050_init);  
- 
module_exit(&mpu6050_exit);  
 
test.c
- 
#include <stdio.h>  
- 
#include <stdlib.h>  
- 
#include <unistd.h>  
- 
#include <fcntl.h>  
- 
#include <sys/ioctl.h>  
- 
  
- 
#include "mpu6050.h"  
- 
  
- 
int main(int argc, const char *argv[])  
- 
{  
- 
    int fd;  
- 
    union mpu6050_data data;   
- 
      
- 
    fd = open("/dev/mpu6050", O_RDWR);  
- 
    if (fd < 0) {  
- 
        perror("open");  
- 
        exit(1);  
- 
    }  
- 
  
- 
    while(1) {  
- 
        ioctl(fd, GET_ACCEL, &data);  
- 
        printf("acceleration data: x = %04x, y = %04x, z = %04x\n",   
- 
                data.accel.x, data.accel.y, data.accel.z);  
- 
  
- 
        ioctl(fd, GET_GYRO, &data);  
- 
        printf("gyroscope data: x = %04x, y = %04x, z = %04x\n",   
- 
                data.accel.x, data.accel.y, data.accel.z);  
- 
  
- 
        sleep(1);  
- 
    }  
- 
  
- 
    close(fd);  
- 
  
- 
    return 0;  
- 
}  
 Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发
原文:http://blog.csdn.net/qq_21593899/article/details/51711638