I2C驱动程序

文章来源:http://blog.csdn.net/zqixiao_09/article/details/50917655

在此驱动的基础修改了一点东西和自己的注释


.dts:

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>;  
        };  
};  


mpu6050.h:

<span style="font-size:18px;"><span style="font-size:18px;">
#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;
	}qyro;
	unsigned short temp;
};

/*ioctl的一些参数定义*/
#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

</span></span>

i2c_driver.c:

<span style="font-size:18px;"><span style="font-size:18px;">
#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"

#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 MPU6050_MAJOR 500
#define MPU6050_MINOR 0

struct mpu6050_device
{
	struct cdev cdev;
	struct i2c_client *client;
};
struct mpu6050_device *mpu6050;

/*从从机client读数据到适配器*/
static int mpu6050_read_byte(struct i2c_client *client,unsigned char reg)
{
	int ret;

	char txbuf[1]={reg};/*reg是个变量啦*/
	char rxbuf[1];

	/*用i2c_msg结构来接收读写的消息*/
	struct i2c_msg msg[2]=
	{
		{client->addr,0,1,txbuf}, /*addr,flag,len,&data*/
		{client->addr,I2C_M_RD,1,rxbuf}
	};
	
	/*将从机client读来的消息发给适配器adapter*/
	ret=i2c_transfer(client->adapter,msg,ARRAY_SIZE(msg));
	if(ret<0)
	{
		printk("ret=%d/n",ret);
		return ret;
	}

	return rxbuf[0];
}

/*适配器将数据发给从机client*/
static int mpu6050_write_byte(struct i2c_client *client,unsigned char reg,unsigned char val)
{

	char txbuf[2]={reg,val};/*reg和val都是char型变量*/

	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 mpu_6050 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_device结构体指针并赋值*/
	mpu6050=kzalloc(sizeof(*mpu6050),GFP_KERNEL);
	if(mpu6050==NULL)
	{
		return -ENOMEM;
	}

	mpu6050->client=client;
	ret=register_chrdev_region(devno,1,"mpu6050");/*通过register_chrdev_region来获取设备号*/
	if(ret<0)
	{
		printk("fail to register char device region\n");
		goto err1;
	}

	/*通过cdev来描述字符设备,主要包含dev_t和file_operations*/
	cdev_init(&mpu6050->cdev,&mpu6050_fops);/*建立cdev与fops的连接*/
	mpu6050->cdev.owner=THIS_MODULE;
	ret=cdev_add(&mpu6050->cdev,devno,1);/*注册该驱动*/
	if(ret<0)
	{
		printk("fail 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);/*释放mpu6050_device申请的空间*/

	return 0;
}

/*要挂载到i2c_driver设备表中的设备ID项*/
static const struct i2c_device_id mpu6050_id[]=
{
	{"mpu6050",0},/*设备名和设备的位置*/
	{}
};

/*通过of_device_id和设备树节点中的.compatible进行匹配*/
static struct of_device_id mpu6050_dt_match[]=
{
	{.compatible="invense,mpu6050"},
	{/*northing to be done*/},
};

/*填充i2c_driver这个结构体*/
struct i2c_driver mpu6050_driver=
{
	.driver= /*device_driver--设备驱动结构体*/
	{
		.name="mpu6050",
		.owner=THIS_MODULE,
		.of_match_table=of_match_ptr(mpu6050_dt_math),
	},
	.probe=mpu6050_probe,
	.remove=mpu6050_remove,
	.id_table=mpu6050_id, /*设备ID表*/
};

static int __init mpu6050_init(void)
{
	return i2c_add_driver(&mpu6050_driver);/*将该驱动挂在到i2c总线上*/
}

static void __exit mpu6050_exit(void)
{
	i2c_del_driver(&mpu6050_driver);	/*从总线上卸载该驱动*/
}

module_init(&mpu6050_init);
module_exit(&mpu6050_exit);
MODULE_LICENSE("GPL");
MOUDLE_AUTHOR("ever");





</span></span>

test.c:

<span style="font-size:18px;"><span style="font-size:18px;">
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/ioctl.h>

#include"mpu6050.h"

int main(int argc,char **argv)
{
	int fd;
	/*union跟struct有点像,不过每次只能有一个数据类型*/
	union mpu6050_data data;

	fd=open("/dev/mpu6050",O_RDWR);
	if(fd<0)
	{
		printf("fail open\n");
		return 0;
	}

	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;
}


</span></span>



Makefile:

<span style="font-size:18px;"><span style="font-size:18px;">
ifneq ($(KERNELRELEASE),)
obj-m:=i2c_dirver.o
else
KDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:
	make -C $(KDIR) M=$(PWD) modules
	gcc -Wall -o test test.c
clean:
	make -C $(KDIR) M=$(PWD) clean
endif
</span></span>



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值