1. 程式人生 > >Linux I2C驅動--用戶態驅動簡單示例

Linux I2C驅動--用戶態驅動簡單示例

圖片 irq 代碼 eth pri 根據 debug disable sla

1. Linux內核支持I2C通用設備驅動(用戶態驅動:由應用層實現對硬件的控制可以稱之為用戶態驅動),實現文件位於drivers/i2c/i2c-dev.c,設備文件為/dev/i2c-0

技術分享圖片

2. I2C通用設備驅動以字符設備註冊進內核的

static const struct file_operations i2cdev_fops = {
    .owner        = THIS_MODULE,
    .llseek        = no_llseek,
    .read        = i2cdev_read,
    .write        = i2cdev_write,
    .unlocked_ioctl    
= i2cdev_ioctl, .open = i2cdev_open, .release = i2cdev_release, }; res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);

3. 對設備文件進行讀寫時,可以調用read、write或者ioctl等方法,他們都是通過調用函數i2c_transfer來實現的

int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
    
int ret; /* REVISIT the fault reporting model here is weak: * * - When we get an error after receiving N bytes from a slave, * there is no way to report "N". * * - When we get a NAK after transmitting N bytes to a slave, * there is no way to report "N" ... or to let the master * continue executing the rest of this combined message, if * that‘s the appropriate response. * * - When for example "num" is two and we successfully complete * the first message but get an error part way through the * second, it‘s unclear whether that should be reported as * one (discarding status on the second message) or errno * (discarding status on the first one).
*/ if (adap->algo->master_xfer) { #ifdef DEBUG for (ret = 0; ret < num; ret++) { dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD) ? R : W, msgs[ret].addr, msgs[ret].len, (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : ""); } #endif if (in_atomic() || irqs_disabled()) { ret = mutex_trylock(&adap->bus_lock); if (!ret) /* I2C activity is ongoing. */ return -EAGAIN; } else { mutex_lock_nested(&adap->bus_lock, adap->level); } ret = adap->algo->master_xfer(adap,msgs,num); mutex_unlock(&adap->bus_lock); return ret; } else { dev_dbg(&adap->dev, "I2C level transfers not supported\n"); return -EOPNOTSUPP; } }

4. i2c_transfer通過代碼可以看出,i2c_transfer 通過調用相應的 adapter 的 master_xfer 方法實現的,而 master_xfer 主要是根據 struct i2c_msg 類型的msgs來進行處理的。

struct i2c_msg {
    __u16 addr;    /* slave address            */
    __u16 flags;
#define I2C_M_TEN        0x0010    /* this is a ten bit chip address */
#define I2C_M_RD        0x0001    /* read data, from slave to master */
#define I2C_M_NOSTART        0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR    0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK        0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN        0x0400    /* length will be first received byte */
    __u16 len;        /* msg length                */
    __u8 *buf;        /* pointer to msg data            */
};

5. I2C用戶態驅動簡單示例

Linux I2C驅動--用戶態驅動簡單示例