246 lines
6.9 KiB
C
246 lines
6.9 KiB
C
|
#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");
|
|||
|
|
|||
|
|
|||
|
|