#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/device.h> 
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>

//宏定义
#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 WHO_AM_I                                    0x75
#define SlaveAddress                                0xD0
#define Address                                     0x68                  //MPU6050地址
#define I2C_RETRIES                                 0x0701
#define I2C_TIMEOUT                                 0x0702
#define I2C_SLAVE                                   0x0703       //IIC从器件的地址设置
#define I2C_BUS_MODE                                0x0780


static struct mpu6050_dev{
    struct cdev c_dev;
    dev_t devno;
    struct class *class;
    struct device *device;
    struct i2c_client *client;
};


static int i2c_write_mpu6050(struct i2c_client *mpu6050_client, u8 address, u8 data)
{
    int error = 0;
    u8 write_data[2];
    struct i2c_msg send_msg; //要发送的数据结构体

    /*设置要发送的数据*/
    write_data[0] = address;
    write_data[1] = data;

    /*发送 iic要写入的地址 reg*/
    send_msg.addr = mpu6050_client->addr; //mpu6050在 iic 总线上的地址
    send_msg.flags = 0;                                       //标记为发送数据
    send_msg.buf = write_data;                        //写入的首地址
    send_msg.len = 2;                                         //reg长度

    /*执行发送*/
    error = i2c_transfer(mpu6050_client->adapter, &send_msg, 1);
    if (error != 1)
    {
            pr_err("\n i2c_transfer error \n");
            return -1;
    }
    return 0;
}
static int i2c_read_mpu6050(struct i2c_client *mpu6050_client, u8 address, void *data, u32 length)
{
    return 0;
}
static int mpu6050_init(struct i2c_client *mpu6050_client)
{
    int error = 0;
    /*配置mpu6050*/
    error += i2c_write_mpu6050(mpu6050_client, PWR_MGMT_1, 0X00);
    error += i2c_write_mpu6050(mpu6050_client, SMPLRT_DIV, 0X07);
    error += i2c_write_mpu6050(mpu6050_client, CONFIG, 0X06);
    error += i2c_write_mpu6050(mpu6050_client, ACCEL_CONFIG, 0X01);

    if (error < 0)
    {
            /*初始化错误*/
            pr_err("\n mpu6050_init error \n");
            return -1;
    }
    return 0;
}

/*字符设备操作函数集，open函数实现*/
static int mpu6050_open(struct inode *inode, struct file *filp)
{
    struct mpu6050_dev *mpu = NULL;
    mpu = container_of(inode->i_cdev, struct mpu6050_dev, c_dev);
    
    filp->private_data = mpu;
    
    return  mpu6050_init(mpu);

    
}
/*字符设备操作函数集，.read函数实现*/
static ssize_t mpu6050_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    return 0;
}
/*字符设备操作函数集，.release函数实现*/
static int mpu6050_release(struct inode *inode, struct file *filp)
{
    return 0;
}
/*字符设备操作函数集*/
static struct file_operations mpu6050_chr_dev_fops =
    {
            .owner = THIS_MODULE,
            .open = mpu6050_open,
            .read = mpu6050_read,
            .release = mpu6050_release,
};

static struct mpu6050_dev mpu6050dev;


/*i2c总线设备函数集*/
static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0; 
    ret = alloc_chrdev_region(&(mpu6050dev.devno),0,1,"mpu6050");
    if(ret < 0){
        pr_err("chrdev alloc region failed\n");
        return ret;
    }

    pr_info("devno is %u(major:%u,minor:%u)\n",mpu6050dev.devno,MAJOR(mpu6050dev.devno), MINOR(mpu6050dev.devno));

    cdev_init(&mpu6050dev.c_dev, &mpu6050_chr_dev_fops);
    mpu6050dev.c_dev.owner = THIS_MODULE;
    ret = cdev_add(&mpu6050dev.c_dev, mpu6050dev.devno, 1);
    if(ret < 0){
        pr_err("chrdev add failed\n");
        goto cdev_add_err;
    }

    ret = class_create(THIS_MODULE, "mpu_class");
    if(IS_ERR(ret))
    {
        pr_err("create class faild!/n");
        goto class_create_err;
    }
    mpu6050dev.class = ret;
    
    ret =  device_create(mpu6050dev.class,NULL,devno,NULL,"mpu6050");
    if(IS_ERR(ret))
    {
        pr_err("device_create failed\n");
        goto device_create_err;
    }
    mpu6050dev.device = ret;

    mpu6050dev.client = client;
    
    return 0;

device_create_err:
    class_destroy(mpu6050dev.class);
class_create_err:
    cdev_del(&mpu6050dev.c_dev);
cdev_add_err:
    unregister_chrdev_region(mpu6050dev.devno, 1);
    return ret;

}
static int mpu6050_remove(struct i2c_client *client)
{

    device_destroy(mpu6050dev.class, mpu6050dev.device);
    class_destroy(mpu6050dev.class);
    cdev_del(&mpu6050dev.c_dev);
    unregister_chrdev_region(mpu6050dev.devno, 1);

    return 0;
}

/*定义ID 匹配表*/
static const struct i2c_device_id gtp_device_id[] = {
    {"fire,i2c_mpu6050", 0},
    {}};

/*定义设备树匹配表*/
static const struct of_device_id mpu6050_of_match_table[] = {
    {.compatible = "fire,i2c_mpu6050"},
    {/* sentinel */}};


/*定义i2c总线设备结构体*/
struct i2c_driver mpu6050_driver = {
    .probe = mpu6050_probe,
    .remove = mpu6050_remove,
    .id_table = gtp_device_id,
    .driver = {
            .name = "fire,i2c_mpu6050",
            .owner = THIS_MODULE,
            .of_match_table = mpu6050_of_match_table,
    },
};

/*
 * 驱动初始化函数
 */
static int __init mpu6050_driver_init(void)
{
    int ret;
    pr_info("mpu6050_driver_init\n");
    ret = i2c_add_driver(&mpu6050_driver);
    return 0;
}

/*
 * 驱动注销函数
 */
static void __exit mpu6050_driver_exit(void)
{
    pr_info("mpu6050_driver_exit\n");
    i2c_del_driver(&mpu6050_driver);
}

module_init(mpu6050_driver_init);
module_exit(mpu6050_driver_exit);

MODULE_LICENSE("GPL");



