linux设备驱动I2C驱动
Posted stay hungry stay foolish
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux设备驱动I2C驱动相关的知识,希望对你有一定的参考价值。
i2c驱动程序的核心是创建i2c_driver结构体
/* This is the driver that will be inserted */ static struct i2c_driver at24cxx_driver = { .driver = { .name = "at24cxx", }, .id = I2C_DRIVERID_AT24Cxx, .attach_adapter = at24cxx_attach_adapter, .detach_client = at24cxx_detach_client, };
再at24cxx_attach_adapter里面
static int at24cxx_attach_adapter(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, at24cxx_detect); }
当probe到设备后, at24cxx_detect会被调用
这里有两个需要完成的
(1) 配置addr_data
(2)at24cxx_detect
对于addr_data
/* * Generic i2c probe * concerning the addresses: i2c wants 7 bit (without the r/w bit), so ‘>>1‘ */ static unsigned short normal_i2c[] = { 0x50, /* 7位地址 */ I2C_CLIENT_END, }; static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, };
而在 at24cxx_detect中主要有
(1) 设置一个i2c_client 结构体变量
(2) 设置它
(3) 注册
首先创建全局i2c_client变量
static struct i2c_client *at24cxx_client;
static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind) { printk(KERN_INFO "at24cxx_detect "); int err = 0; /* 分配 */ at24cxx_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); /* 设置 */ at24cxx_client->addr = address; at24cxx_client->adapter = adapter; at24cxx_client->driver = &at24cxx_driver; at24cxx_client->flags = 0; /* Fill in the remaining client fields */ strlcpy(at24cxx_client->name, "at24cxx", I2C_NAME_SIZE); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(at24cxx_client))) goto exit_kfree; exit_kfree: kfree(at24cxx_client); return err; }
i2c设置好了, 数据传输使用i2c_transfer
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
因此, 数据传送是需要构造设置msg
与用户程序交互的读:
static int at24cxx_read (struct file *file, char __user *usrbuf, size_t len, loff_t *offset) { /* * buf[0] addr * buf[1] data */ int ret; unsigned char address; unsigned char data; struct i2c_msg msg[2]; if(len != 2) return -EFAULT; if(copy_from_user(&address, usrbuf, 1)) res = -EFAULT; /* i2c 传输 */ /* 先发送地址 */ msg[0].addr = at24cxx_client->addr; // dest msg[0].buf = &address; // src msg[0].flags = 0; // write msg[0].len = 1; // len /* 再读 */ msg[1].addr = at24cxx_client->addr; // dest msg[2].buf = &data; // src msg[1].flags = I2C_M_RD; // read msg[1].len = 1; // len ret = i2c_transfer(at24cxx_client->adapter, msg, 2); if(ret == 2) { if(copy_to_user(&usrbuf, &data, 1)) res = -EFAULT; return 1; } else return -EIO; return 0; }
写:
static int at24cxx_write (struct file *file, const char __user *usrbuf, size_t len, loff_t *offset) { /* * buf[0] addr * buf[1] data */ int ret; unsigned char buf[2]; struct i2c_msg msg[1]; if(len != 2) return -EFAULT; if(copy_from_user(buf, usrbuf, 2)) res = -EFAULT; /* i2c 传输 */ msg[0].addr = at24cxx_client->addr; // dest msg[0].buf = buf; // src msg[0].flags = 0; // write msg[0].len = 2; // len ret = i2c_transfer(at24cxx_client->adapter, msg, 1); if(ret == 1) return 2; else return -EIO; }
以上是关于linux设备驱动I2C驱动的主要内容,如果未能解决你的问题,请参考以下文章