您的位置:首页 > 其它

i2c 驱动三:自己实现设备和驱动分离

2016-10-28 18:30 316 查看
有关linux的i2c相关文章有一下几篇,他们互相关联,应该一同看:

    - i2c 驱动一:简介

    - i2c 驱动二:devfs文件系统

    - i2c 驱动三:自己实现设备和驱动分离

    - i2c 驱动四:sysfs文件系统

   
- i2c 驱动五:gpio模拟i2c

对i2c的驱动和设备的匹配说完之后,感觉如何获得 adapter 等的一些小的注意事项还是不能尽然说尽,干脆来个自己实现 platform 架构的 i2c 驱动

.

├── dev

│   ├── Makefile

│   └── mpu6050_dev.c

└── dri

    ├── Makefile

    └── mpu6050_dri.c

mpu6050_dev.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>

MODULE_LICENSE("GPL");

static struct i2c_client *mpu6050_clientp;

static struct i2c_board_info mpu6050_i2c_devs = {
.type = "mpu6050",
.addr = 0x68,
/*I2C_BOARD_INFO("mpu6050", 0x50), //这个宏是上边两个变量赋值的替换*/
};

static int mpu6050_dev_init(void)
{
struct i2c_adapter *i2c_adap;    //分配一个适配器的指针

printk("mpu6050_dev_init.\n");

i2c_adap = i2c_get_adapter(0);   //0 是 i2c 总线编号

mpu6050_clientp = i2c_new_device(i2c_adap, &mpu6050_i2c_devs); //只能添加一个
if (!mpu6050_clientp)
printk("register i2c error!\n");

i2c_put_adapter(i2c_adap);       //释放 adapter

return 0;
}

static void mpu6050_dev_exit(void)
{
printk("mpu6050_dev_exit.\n");
i2c_unregister_device(mpu6050_clientp);
}

module_init(mpu6050_dev_init);
module_exit(mpu6050_dev_exit);

Makefile

ifeq ($(KERNELRELEASE),)

#KERNELDIR ?= /lib/modules/$(shell uname -r)/build
KERNELDIR ?= ~/wor_lip/linux-3.4.112
PWD := $(shell pwd)

modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules* Module*

.PHONY: modules modules_install clean

else
obj-m := mpu6050_dev.o
endif

mpu6050_dri.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.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

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[] = {
{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[] = {
{client->addr, 0, 2, txbuf},

};

i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));

return 0;
}

static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
unsigned short accel_x = 0, accel_y = 0, accel_z = 0;
unsigned short gyro_x = 0, gyro_y = 0, gyro_z = 0;
unsigned short temp = 0;

printk("match OK!\n");
/*printk("irqno = %d\n", client->irq);*/
printk("addr = %d\n", client->addr);

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, 0x18);
mpu6050_write_byte(client, ACCEL_CONFIG, 0x01);

while(1) {
accel_x = mpu6050_read_byte(client, ACCEL_XOUT_L);
accel_x |= mpu6050_read_byte(client, ACCEL_XOUT_H) << 8;

accel_y =  mpu6050_read_byte(client, ACCEL_YOUT_L);
accel_y |= mpu6050_read_byte(client, ACCEL_YOUT_H) << 8;

accel_z = mpu6050_read_byte(client, ACCEL_ZOUT_L);
accel_z |= mpu6050_read_byte(client, ACCEL_ZOUT_H) << 8;

printk("acceleration data: x = %04x, y = %04x, z = %04x\n", accel_x, accel_y, accel_z);

gyro_x = mpu6050_read_byte(client, GYRO_XOUT_L);
gyro_x |= mpu6050_read_byte(client, GYRO_XOUT_H) << 8;

gyro_y = mpu6050_read_byte(client, GYRO_YOUT_L);
gyro_y |= mpu6050_read_byte(client, GYRO_YOUT_H) << 8;

gyro_z = mpu6050_read_byte(client, GYRO_ZOUT_L);
gyro_z |= mpu6050_read_byte(client, GYRO_ZOUT_H) << 8;

printk("gyroscope data: x = %04x, y = %04x, z = %04x\n", gyro_x, gyro_y, gyro_z);

temp = mpu6050_read_byte(client, TEMP_OUT_L);
temp |= mpu6050_read_byte(client, TEMP_OUT_H) << 8;

printk("temperature data: %x\n", temp);

mdelay(500);
}

return 0;
}

static int mpu6050_remove(struct i2c_client *client)
{
printk("driver removed.\n");

return 0;
}

static const struct i2c_device_id mpu6050_id[] = {
{ "mpu6050", 0 },
};

/*MODULE_DEVICE_TABLE(i2c, mpu6050_id);*/

static struct i2c_driver mpu6050_driver = {
.driver = {
.name           = "xx",    //供模块匹配用
.owner          = THIS_MODULE,
},
.probe      = mpu6050_probe,
.remove     = mpu6050_remove,
.id_table   = mpu6050_id,     /* 用于I2C driver的probe函数调用 */     //供平台文件匹配用
};

/*i2c_add_driver();*/

module_i2c_driver(mpu6050_driver);//简单方式,内核中是个宏,完成了模块的初始化和卸载

Makefile

ifeq ($(KERNELRELEASE),)

#KERNELDIR ?= /lib/modules/$(shell uname -r)/build
KERNELDIR ?= ~/wor_lip/linux-3.4.112
PWD := $(shell pwd)

modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules* Module*

.PHONY: modules modules_install clean

else
obj-m := mpu6050_dri.o
endif


各自生成,放到板子的根目录下 insmod ,就会直接打印mpu的数据,打印结果如上一片中结果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: