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驱动的主要内容,如果未能解决你的问题,请参考以下文章

:Linux I2C核心总线与设备驱动

Linux驱动之I2C驱动架构

LINUX驱动之IIC驱动

:Linux I2C核心总线与设备驱动

linux驱动之i2c子系统mpu6050设备驱动

Linux驱动之I2C设备驱动